diff --git a/.travis.yml b/.travis.yml index 15b43bf1..78975f4b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,6 @@ language: php sudo: false php: - - 5.4 - 5.5 - 5.6 - hhvm diff --git a/composer.json b/composer.json index cd544d53..3c3a5ce5 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "license": "BSD-3-Clause", "homepage": "https://modules.zendframework.com", "require": { - "php": "~5.4", + "php": "~5.5", "bshaffer/oauth2-server-php": "dev-develop", "zendframework/zendframework": "~2.3.0", "rwoverdijk/assetmanager": "1.3.*", diff --git a/module/Application/config/module.config.php b/module/Application/config/module.config.php index 94d2e3d4..e0d4805c 100644 --- a/module/Application/config/module.config.php +++ b/module/Application/config/module.config.php @@ -7,6 +7,8 @@ * @license http://framework.zend.com/license/new-bsd New BSD License */ +use Application\Service; + return array( 'router' => array( 'routes' => array( @@ -87,6 +89,7 @@ 'service_manager' => array( 'factories' => array( 'translator' => 'Zend\I18n\Translator\TranslatorServiceFactory', + Service\RepositoryRetriever::class => Service\RepositoryRetrieverFactory::class, ), ), 'translator' => array( diff --git a/module/Application/src/Application/Service/RepositoryRetriever.php b/module/Application/src/Application/Service/RepositoryRetriever.php new file mode 100644 index 00000000..7b716240 --- /dev/null +++ b/module/Application/src/Application/Service/RepositoryRetriever.php @@ -0,0 +1,85 @@ +githubClient = $githubClient; + } + + /** + * Return MetaData from User Repository + * @param string $user + * @param string $module + * @return mixed + */ + public function getUserRepositoryMetadata($user, $module) + { + return json_decode($this->githubClient->api('repos')->show($user, $module)); + } + + /** + * Get all Repositories from GitHub User + * @param string $user + * @param array $params + * @return RepositoryCollection + */ + public function getUserRepositories($user, array $params = array()) + { + return $this->githubClient->api('user')->repos($user, $params); + } + + /** + * Get File Content from User Repository + * @param string $user + * @param string $module + * @param string $filePath + * @return string|null + */ + public function getRepositoryFileContent($user, $module, $filePath) + { + $contentResponse = $this->getRepositoryFileMetadata($user, $module, $filePath); + + if (!isset($contentResponse->content)) { + return null; + } + + return base64_decode($contentResponse->content); + } + + /** + * Return File MetaData from User Repository + * @param string $user + * @param string $module + * @param string $filePath + * @return mixed + */ + public function getRepositoryFileMetadata($user, $module, $filePath) + { + return json_decode($this->githubClient->api('repos')->content($user, $module, $filePath)); + } + + /** + * Return all Repositories from current authenticated GitHub User + * @param array $params + * @return RepositoryCollection + */ + public function getAuthenticatedUserRepositories(array $params = array()) + { + return $this->githubClient->api('current_user')->repos($params); + } +} diff --git a/module/Application/src/Application/Service/RepositoryRetrieverFactory.php b/module/Application/src/Application/Service/RepositoryRetrieverFactory.php new file mode 100644 index 00000000..796037c1 --- /dev/null +++ b/module/Application/src/Application/Service/RepositoryRetrieverFactory.php @@ -0,0 +1,23 @@ +get(Client::class); + + return new RepositoryRetriever($githubClient); + } +} diff --git a/module/Application/test/ApplicationTest/Integration/Service/RepositoryRetrieverTest.php b/module/Application/test/ApplicationTest/Integration/Service/RepositoryRetrieverTest.php new file mode 100644 index 00000000..373ec84d --- /dev/null +++ b/module/Application/test/ApplicationTest/Integration/Service/RepositoryRetrieverTest.php @@ -0,0 +1,20 @@ +assertInstanceOf( + Service\RepositoryRetriever::class, + $serviceManager->get(Service\RepositoryRetriever::class) + ); + } +} diff --git a/module/Application/test/ApplicationTest/Service/RepositoryRetrieverTest.php b/module/Application/test/ApplicationTest/Service/RepositoryRetrieverTest.php new file mode 100644 index 00000000..d0b3aacc --- /dev/null +++ b/module/Application/test/ApplicationTest/Service/RepositoryRetrieverTest.php @@ -0,0 +1,193 @@ + 'foo'], + ['name' => 'bar'], + ['name' => 'baz'], + ]; + + $client = $this->getClientMock( + new Api\User(), + $payload + ); + + $service = new RepositoryRetriever($client); + + $repositories = $service->getUserRepositories('foo'); + + $this->assertInstanceOf(Collection\RepositoryCollection::class, $repositories); + + $count = 0; + foreach ($repositories as $repository) { + $this->assertEquals(current($payload), (array)$repository); + next($payload); + ++$count; + } + + $this->assertEquals(count($payload), $count); + } + + public function testCanRetrieveUserRepositoryMetadata() + { + $payload = [ + 'name' => 'foo', + 'url' => 'http://foo.com', + ]; + + $client = $this->getClientMock( + new Api\Repos(), + $payload + ); + + $service = new RepositoryRetriever($client); + + $metadata = $service->getUserRepositoryMetadata('foo', 'bar'); + + $this->assertInstanceOf('stdClass', $metadata); + $this->assertEquals($payload, (array)$metadata); + } + + public function testCanRetrieveRepositoryFileContent() + { + $payload = [ + 'content' => base64_encode('foo'), + ]; + + $client = $this->getClientMock( + new Api\Repos(), + $payload + ); + + $service = new RepositoryRetriever($client); + + $response = $service->getRepositoryFileContent('foo', 'bar', 'foo.baz'); + + $this->assertEquals('foo', $response); + } + + public function testResponseContentMissingOnGetRepositoryFileContent() + { + $payload = []; + + $client = $this->getClientMock( + new Api\Repos(), + $payload + ); + + $service = new RepositoryRetriever($client); + + $response = $service->getRepositoryFileContent('foo', 'bar', 'baz'); + + $this->assertNull($response); + } + + public function testCanRetrieveRepositoryFileMetadata() + { + $payload = [ + 'name' => 'foo', + 'url' => 'http://foo.com', + ]; + + $client = $this->getClientMock( + new Api\Repos(), + $payload + ); + + $service = new RepositoryRetriever($client); + + $metadata = $service->getRepositoryFileMetadata('foo', 'bar', 'baz'); + + $this->assertInstanceOf('stdClass', $metadata); + $this->assertEquals($payload, (array) $metadata); + } + + public function testCanRetrieveAuthenticatedUserRepositories() + { + $payload = [ + ['name' => 'foo'], + ['name' => 'bar'], + ['name' => 'baz'], + ]; + + $client = $this->getClientMock( + new Api\CurrentUser(), + $payload + ); + + $service = new RepositoryRetriever($client); + + $repositories = $service->getAuthenticatedUserRepositories(); + + $this->assertInstanceOf(Collection\RepositoryCollection::class, $repositories); + + $count = 0; + foreach ($repositories as $repository) { + $this->assertEquals(current($payload), (array) $repository); + next($payload); + ++$count; + } + + $this->assertEquals(count($payload), $count); + } + + /** + * @param Api\AbstractApi $apiInstance + * @param array $payload + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function getClientMock(Api\AbstractApi $apiInstance, array $payload = []) + { + $response = $this->getMock('Zend\Http\Response'); + + $response + ->expects($this->any()) + ->method('getBody') + ->willReturn(json_encode($payload)) + ; + + $headers = $this->getMock('Zend\Http\Headers'); + + $response + ->expects($this->any()) + ->method('getHeaders') + ->willReturn($headers) + ; + + $httpClient = $this->getMock('EdpGithub\Http\Client'); + + $httpClient + ->expects($this->any()) + ->method('get') + ->willReturn($response) + ; + + $client = $this->getMock('EdpGithub\Client'); + + $client + ->expects($this->any()) + ->method('getHttpClient') + ->willReturn($httpClient) + ; + + $apiInstance->setClient($client); + + $client + ->expects($this->any()) + ->method('api') + ->willReturn($apiInstance) + ; + + return $client; + } +} diff --git a/module/ZfModule/src/ZfModule/Controller/IndexController.php b/module/ZfModule/src/ZfModule/Controller/IndexController.php index 23bbceb6..fed11a14 100644 --- a/module/ZfModule/src/ZfModule/Controller/IndexController.php +++ b/module/ZfModule/src/ZfModule/Controller/IndexController.php @@ -2,6 +2,7 @@ namespace ZfModule\Controller; +use Application\Service\RepositoryRetriever; use EdpGithub\Client; use EdpGithub\Collection\RepositoryCollection; use Zend\Cache; @@ -33,22 +34,30 @@ class IndexController extends AbstractActionController */ private $githubClient; + /** + * @var RepositoryRetriever + */ + private $repositoryRetriever; + /** * @param Cache\Storage\StorageInterface $moduleCache * @param Mapper\Module $moduleMapper * @param Service\Module $moduleService * @param Client $githubClient + * @param RepositoryRetriever $repositoryRetriever */ public function __construct( Cache\Storage\StorageInterface $moduleCache, Mapper\Module $moduleMapper, Service\Module $moduleService, - Client $githubClient + Client $githubClient, + RepositoryRetriever $repositoryRetriever ) { $this->moduleCache = $moduleCache; $this->moduleMapper = $moduleMapper; $this->moduleService = $moduleService; $this->githubClient = $githubClient; + $this->repositoryRetriever = $repositoryRetriever; } public function viewAction() @@ -62,45 +71,32 @@ public function viewAction() return; } - $cacheKey = 'module-view-' . $vendor . '-' . $module; + $repositoryCacheKey = 'module-view-' . $vendor . '-' . $module; + $repository = $this->repositoryRetriever->getUserRepositoryMetadata($vendor, $module); - $repository = json_decode($this->githubClient->api('repos')->show($vendor, $module)); $httpClient = $this->githubClient->getHttpClient(); $response= $httpClient->getResponse(); - if ($response->getStatusCode() == Http\Response::STATUS_CODE_304 && $this->moduleCache->hasItem($cacheKey)) { - return $this->moduleCache->getItem($cacheKey); + if ($response->getStatusCode() == Http\Response::STATUS_CODE_304 && $this->moduleCache->hasItem($repositoryCacheKey)) { + return $this->moduleCache->getItem($repositoryCacheKey); } - $readme = $this->githubClient->api('repos')->readme($vendor, $module); - $readme = json_decode($readme); + $readme = $this->repositoryRetriever->getRepositoryFileContent($vendor, $module, 'README.md'); + $license = $this->repositoryRetriever->getRepositoryFileContent($vendor, $module, 'LICENSE'); + $license = !$license ? 'No license file found for this Module' : $license; - try { - $license = $this->githubClient->api('repos')->content($vendor, $module, 'LICENSE'); - $license = json_decode($license); - $license = base64_decode($license->content); - } catch (\Exception $e) { - $license = 'No license file found for this Module'; - } - - try { - $composerJson = $this->githubClient->api('repos')->content($vendor, $module, 'composer.json'); - $composerConf = json_decode($composerJson); - $composerConf = base64_decode($composerConf->content); - $composerConf = json_decode($composerConf, true); - } catch (\Exception $e) { - $composerConf = 'No composer.json file found for this Module'; - } + $composerConf = $this->repositoryRetriever->getRepositoryFileContent($vendor, $module, 'composer.json'); + $composerConf = !$composerConf ? 'No composer.json file found for this Module' : json_decode($composerConf, true); $viewModel = new ViewModel(array( 'vendor' => $vendor, 'module' => $module, 'repository' => $repository, - 'readme' => base64_decode($readme->content), + 'readme' => $readme, 'composerConf' => $composerConf, 'license' => $license, )); - $this->moduleCache->setItem($cacheKey, $viewModel); + $this->moduleCache->setItem($repositoryCacheKey, $viewModel); return $viewModel; } @@ -118,8 +114,7 @@ public function indexAction() 'direction' => 'desc', ); - /* @var RepositoryCollection $repos */ - $repos = $this->githubClient->api('current_user')->repos($params); + $repos = $this->repositoryRetriever->getAuthenticatedUserRepositories($params); $identity = $this->zfcUserAuthentication()->getIdentity(); $cacheKey = 'modules-user-' . $identity->getId(); @@ -144,8 +139,7 @@ public function organizationAction() 'direction' => 'desc', ); - /* @var RepositoryCollection $repos */ - $repos = $this->githubClient->api('user')->repos($owner, $params); + $repos = $this->repositoryRetriever->getUserRepositories($owner, $params); $identity = $this->zfcUserAuthentication()->getIdentity(); $cacheKey = 'modules-organization-' . $identity->getId() . '-' . $owner; @@ -162,7 +156,7 @@ public function organizationAction() * @param string $cacheKey * @return array */ - public function fetchModules(RepositoryCollection $repos, $cacheKey) + private function fetchModules(RepositoryCollection $repos, $cacheKey) { $cacheKey .= '-github'; @@ -210,8 +204,7 @@ public function addAction() $repo = $request->getPost()->get('repo'); $owner = $request->getPost()->get('owner'); - $repository = $this->githubClient->api('repos')->show($owner, $repo); - $repository = json_decode($repository); + $repository = $this->repositoryRetriever->getUserRepositoryMetadata($owner, $repo); if (!($repository instanceof \stdClass)) { throw new Exception\RuntimeException( @@ -272,8 +265,7 @@ public function removeAction() $repo = $request->getPost()->get('repo'); $owner = $request->getPost()->get('owner'); - $repository = $this->githubClient->api('repos')->show($owner, $repo); - $repository = json_decode($repository); + $repository = $this->repositoryRetriever->getUserRepositoryMetadata($owner, $repo); if (!$repository instanceof \stdClass) { throw new Exception\RuntimeException( diff --git a/module/ZfModule/src/ZfModule/Controller/IndexControllerFactory.php b/module/ZfModule/src/ZfModule/Controller/IndexControllerFactory.php index 16b09041..588978eb 100644 --- a/module/ZfModule/src/ZfModule/Controller/IndexControllerFactory.php +++ b/module/ZfModule/src/ZfModule/Controller/IndexControllerFactory.php @@ -2,6 +2,7 @@ namespace ZfModule\Controller; +use Application\Service\RepositoryRetriever; use EdpGithub\Client; use Zend\Cache; use Zend\Mvc\Controller\ControllerManager; @@ -31,13 +32,17 @@ public function createService(ServiceLocatorInterface $controllerManager) $moduleService = $serviceManager->get('zfmodule_service_module'); /* @var Client $githubClient */ - $githubClient = $serviceManager->get('EdpGithub\Client'); + $githubClient = $serviceManager->get(Client::class); + + /* @var RepositoryRetriever $repositoryRetriever */ + $repositoryRetriever = $serviceManager->get(RepositoryRetriever::class); return new IndexController( $moduleCache, $moduleMapper, $moduleService, - $githubClient + $githubClient, + $repositoryRetriever ); } }