Статьи

Популярные пользователи по языкам и регионам с Silex и Github

Github API V3 — это очень мощный набор конечных точек API, которые вы можете использовать для получения полезной информации о ваших репозиториях, действиях и событиях. Мало того, это позволяет вам получить доступ к публичной информации о других. Тот факт, что он имеет библиотеки на многих языках и платформах , также является большим плюсом; это позволяет быстро приступить к написанию кода.

Данные, которые вы можете получить через GitHub API V3, — это в основном то, что вы можете видеть в веб-интерфейсе GitHub, за исключением того, что вы можете использовать данные в своем приложении, чтобы сделать интересные выводы. Это то, что мы собираемся сделать в этой статье.

Юнес Рафи (Younes Rafie ) написал статью под названием « Как использовать API Github с PHP» , в которой он представляет многое из того, о чем мы здесь говорим, хотя и по-другому. Если вы еще не читали эту статью, не бойтесь! Мы вас покрыли.

Github logo

Концепция

Как отмечает Брэндон Сэвидж в своей статье, полное руководство по содействию открытому исходному коду :

Существуют миллионы разработчиков PHP, но только (большая) группа авторов, авторов и разработчиков программного обеспечения с открытым исходным кодом. Packagist сообщает о менее чем 50 000 пакетов в экосистеме PHP. Это огромное количество пакетов с открытым исходным кодом, но это мало по сравнению с разработчиками PHP в мире.

Теперь, что если бы существовал веб-сервис, в котором мы могли бы указать местоположение и язык (например, PHP) и получить отсортированный список участников в open-source? Это определенно сделало бы Брэндона очень счастливым.

В нашем веб-сервисе у нас будет одна конечная точка (то есть действие, URL), которая показывает десять самых популярных creators . Самые популярные creators — люди в локации, которые имеют наибольшее количество звездных наблюдателей. Для этого мы извлечем репозитории каждого человека и добавим количество раз, когда каждый из них был помечен звездой.

Проект GitHub Awards делает нечто подобное, хотя и в гораздо более сложной манере. Он использует такие инструменты, как GitHub Archive , которые выходят за рамки этой статьи. Юнес Рафи в этом посте тоже несколько осветил этот подход. Тем не менее, мы просто рассортируем пользователей по количеству подписчиков, так как это также является хорошим показателем популярности. Чтобы просмотреть полный исходный код этого приложения, посмотрите репозиторий Github .

Готовимся

Настройка машины разработки

Самый простой способ начать работу — использовать Laravel Homestead или нашу собственную Homestead Improved . Независимо от того, какой из них вы используете, если вы откроете свой файл конфигурации homestead.yaml , вы увидите конфигурацию по умолчанию, то есть сайт с названием homestead.app который загружает ваши php файлы из ~/Code .

 sites: - map: homestead.app to: /home/vagrant/Code/Laravel/public 

Получение Silex и настройка Homestead.yaml

Будучи микро-фреймворком, Silex не имеет много правил или соглашений. Тем не менее, это помогает прочитать эту статью, чтобы усвоить некоторые основы. Если вы не хотите переключаться между статьями, мы будем ссылаться на соответствующие разделы документации Silex в этом руководстве.

Как вы, возможно, знаете, Silex помещает свой файл index.php в web каталог в соответствии с соглашениями Symfony. Таким образом, ваш webroot будет на самом деле ~/Code/silex/web , а не ~/Code/Laravel/public . Давайте перейдем в раздел sites homestead.yaml и исправим это:

 sites: - map: homestead.app to: /home/vagrant/Code/silex/web 

Затем введите vagrant up для загрузки виртуальной машины и, как только это будет сделано, вставьте SSH в виртуальную vagrant ssh с помощью vagrant ssh . Внутри мы делаем следующее для запуска нового рабочего экземпляра Silex:

 cd Code composer create-project silex/silex 

После завершения этой процедуры (это может занять некоторое время) создайте подпапку в папке silex именем web и в ней файл index.php с содержимым:

 <?php require_once __DIR__.'/../vendor/autoload.php'; $app = new Silex\Application(); $app->get('/', function(){ return "Hello world"; }); $app->run(); 

Если вы сейчас откроете homestead.app:8000 в своем браузере, вы должны увидеть «Hello World» (при условии, что homestead.app находится в вашем файле hosts в соответствии с инструкциями ).

Поздравляем! Теперь вы готовы к работе!

Начало работы с GitHub API V3

Мы собираемся использовать библиотеку PHP GitHub KNPLabs для извлечения данных из GitHub через GitHub API V3 . Давайте добавим его в наш файл composer.json , выполнив команду: composer require knplabs/github-api ~1.4 .

Давайте включим режим отладки, установив для $app['debug'] значение true , и parhamdoustdar к GitHub API V3 с просьбой предоставить нам информацию о пользователе с именем parhamdoustdar . Обновите index.php .

 <?php require_once __DIR__.'/../vendor/autoload.php'; use Github\Client; use Silex\Application; $app = new Application(); $app['debug'] = true; $app->get('/', function (Application $app) { $client = new Client(); $parham = $client->user()->show('parhamdoustdar'); return $app->json($parham); }); $app->run(); 

Если вы зайдете на http://homestead.app:8000 , вы должны увидеть parhamdoustdar в json:

 { "login":"parhamdoustdar", "id":352539, "avatar_url":"https:\/\/avatars.githubusercontent.com\/u\/352539?v=3", "gravatar_id":"","url":"https:\/\/api.github.com\/users\/parhamdoustdar", "html_url":"https:\/\/github.com\/parhamdoustdar", "followers_url":"https:\/\/api.github.com\/users\/parhamdoustdar\/followers", "following_url":"https:\/\/api.github.com\/users\/parhamdoustdar\/following{\/other_user}", "gists_url":"https:\/\/api.github.com\/users\/parhamdoustdar\/gists{\/gist_id}", "starred_url":"https:\/\/api.github.com\/users\/parhamdoustdar\/starred{\/owner}{\/repo}", "subscriptions_url":"https:\/\/api.github.com\/users\/parhamdoustdar\/subscriptions", "organizations_url":"https:\/\/api.github.com\/users\/parhamdoustdar\/orgs", "repos_url":"https:\/\/api.github.com\/users\/parhamdoustdar\/repos", "events_url":"https:\/\/api.github.com\/users\/parhamdoustdar\/events{\/privacy}", "received_events_url":"https:\/\/api.github.com\/users\/parhamdoustdar\/received_events", "type":"User", "site_admin":false, "name":, "company":"TENA", "blog":"http:\/\/www.parhamdoustdar.com", "location":"Tehran", "email":"[email protected]", "hireable":true, "bio":null, "public_repos":9, "public_gists":2, "followers":3, "following":0, "created_at":"2010-08-03T07:56:17Z", "updated_at":"2015-03-01T20:01:26Z"} 

Если вы не поняли, что именно делает наш контроллер, не волнуйтесь! Мы пройдем через это вместе.

В строке 8 мы включаем режим отладки, как упоминалось ранее.

Внутри анонимной функции, которая будет вызываться при каждом доступе к корневому маршруту ( / ), мы создаем экземпляр Github\Client . Обратите внимание, что мы добавили аргумент типа Silex\Application . Как отмечено в разделе использования руководства Silex:

Silex автоматически закрывает текущее приложение благодаря закрытию типа.

В следующей строке мы вызываем метод user() на client объекте, чтобы получить объект типа Github\Api\User , который используется для получения информации о пользователях. Затем мы просто вызываем show() для этого объекта, передавая имя пользователя, о котором мы хотим получить информацию.

В последней строке используется вспомогательный метод json() объекта Silex\Application для визуализации нашего примера ответа json.

Каталог приложений

Возможно, вы заметили, что в нашем проекте нет места для размещения нашего исходного кода. Наличие одного файла index.php хорошо, когда вы пишете небольшой фрагмент кода, чтобы проверить, что все работает гладко, но сейчас пришло время нам создать папку для размещения исходного кода нашего приложения.

Для этого создайте папку в вашем каталоге silex , рядом с вашей web папкой, и назовите ее App . После этого давайте отредактируем composer.json и добавим информацию об автозагрузке:

 { ... "autoload": { "psr-0": { "Silex": "src/" }, "psr-4": { "App\\": "App/" } }, } 

Затем запустите composer dump-autoload чтобы восстановить файлы автозагрузки. Теперь мы готовы перейти к реальной вещи!

Пользователи GitHub в локации

Первое, что нам нужно для нашего топлиста, — это получить список имен пользователей в определенном месте, которые имеют репозитории на указанном языке. Для этого мы можем использовать API поиска пользователей .

Если вы посмотрите на эту страницу, вы увидите, что мы можем указать несколько параметров при поиске пользователей. Однако нас интересует location и language , которые можно указать в параметре q . Если вы ранее использовали окно поиска GitHub, вы заметите, что параметр q — это то, что вы вводите в это текстовое поле.

Давайте продолжим и создадим сервис, который ищет пользователей, которые живут в нужном нам месте и имеют репозитории на нужном нам языке программирования. Мы назовем его UserSearcher и поместим в App/Services .

 <?php namespace App\Services; use Github\Client; class UserSearcher { /** * @var Client */ protected $client; public function __construct(Client $client) { $this->client = $client; } public function retrieveByLocationAndLanguage($location, $language) { $searchString = "location:${location} language:${language}"; $results = $this->fetchSearchResults($searchString, 10); return $this->extractUsernames($results); } protected function fetchSearchResults($searchString, $count) { $results = $this->client ->search() ->setPerPage($count) ->users($searchString, 'followers') ; return $results['items']; } protected function extractUsernames(array $results) { $usernames = []; foreach ($results as $result) { $usernames[] = $result['login']; } return $usernames; } } 

Как видите, метод UserSearcher::retrieveByLocationAndLanguage() сначала создает строку поиска. Если вы отправите Tehran и PHP в качестве первого и второго аргументов этой функции соответственно, строка будет следующим location:Tehran language:PHP .

Затем он получает список из десяти лучших результатов поиска, используя Github\Client . Как вы, вероятно, догадались, сначала он получает объект API поиска ( Github\Api\Search ) от клиента, а затем устанавливает perPage в 10, что означает, что он будет запрашивать только десять результатов поиска. После этого он отправляет строку поиска в GitHub и возвращает результаты. Обратите внимание, что результаты поиска сортируются по количеству подписчиков и по индексу элементов возвращаемого массива.

Метод extractUserNames() просто делает то, что вы ожидаете: он просматривает результаты и добавляет login каждого пользователя в массив, а затем возвращает его.

Что мы имеем на данный момент? Десять имен пользователей. Десять имен пользователей, которые мы можем запросить для их репозиториев, а затем сложить количество наблюдателей звезд для всех репозиториев под именем этого пользователя.

Готов?

Stargazers из хранилищ

Ниже приведен код для нашего класса App\Services\StarGazerCalculator :

 <?php namespace App\Services; use Github\Client; class StarGazerCalculator { /** * @var Client */ protected $client; public function __construct(Client $client) { $this->client = $client; } public function calculateStarGazersByUsername($username) { $repositories = $this->client->user()->repositories($username); $repositories = $this->filterForkedRepositories($repositories); return $this->addStarGazersFromRepositories($repositories); } protected function filterForkedRepositories(array $repositories) { return array_filter($repositories, function($repository) { return $repository['fork'] === false; }); } protected function addStarGazersFromRepositories(array $repositories) { return array_reduce($repositories, function($starGazersSoFar, $repository) { return $starGazersSoFar + $repository['stargazers_count']; }); } } 

Получение лучших авторов

Теперь пришло время начать писать наш последний класс, TopCreatorsRetriever . Этот класс объединяет функциональность, которую мы хотим — он получает десять самых популярных имен пользователей с UserSearcher класса UserSearcher , а затем перебирает этих пользователей, используя StarGazerCalculator чтобы получить количество StarGazerCalculator для каждого пользователя.

 <?php namespace App\Services; class TopCreatorsRetriever { /** * @var UserSearcher */ protected $searcher; /** * @var StarGazerCalculator */ protected $calculator; public function __construct(UserSearcher $searcher, StarGazerCalculator $calculator) { $this->searcher = $searcher; $this->calculator = $calculator; } public function retrieve($location, $language) { $usernames = $this->searcher->retrieveByLocationAndLanguage($location, $language); $map = $this->createUserStarGazerMap($usernames); return $this->sortMapByStarGazers($map); } protected function createuserStarGazerMap(array $usernames) { $results = []; foreach ($usernames as $username) { $results[$username] = $this->calculator->calculateStarGazersByUsername($username); } return $results; } protected function sortMapByStarGazers(array $map) { arsort($map, SORT_NUMERIC); return $map; } } 

Поставщик услуг

Как вы, возможно, знаете, чтобы добавить наши классы в контейнер внедрения зависимостей, поставляемый с Silex, нам нужно создать поставщика услуг, а затем зарегистрировать его в приложении . Это означает, что нам нужно создать поставщика услуг, чтобы использовать наш недавно написанный класс TopCreatorsRetriever . Нам не нужно регистрировать другие два класса, потому что эти два класса предназначены для внутреннего использования нашим высокоуровневым классом TopCreatorsRetriever .

Создайте новую папку в App/ и назовите ее Providers . Затем создайте файл с именем TopCreatorsRetrieverServiceProvider.php котором будет размещен код для нашего класса.

 <?php namespace App\Providers; use Silex\ServiceProviderInterface; use Silex\Application; use Github\Client; use App\Services\UserSearcher; use App\Services\StarGazerCalculator; use App\Services\TopCreatorsRetriever; class TopCreatorsRetrieverServiceProvider implements ServiceProviderInterface { public function register(Application $app) { $app['topCreatorsRetriever'] = $app->share(function() { $client = new Client(); $searcher = new UserSearcher($client); $calculator = new StarGazerCalculator($client); return new TopCreatorsRetriever($searcher, $calculator); }); } public function boot(Application $app) { } } 

Примечание . Не удаляйте пустую функцию boot() . Он должен существовать, даже если он пуст, чтобы наш класс соответствовал интерфейсу ServiceProviderInterface .

Использование TopCreatorsRetriever в нашем контроллере

Наконец пришло время увидеть всю нашу работу в действии. Мы определим маршрут в index.php называемый creators , который получает location и language качестве аргументов, а затем возвращает массив JSON с именами пользователей в качестве ключей и количеством звездных наблюдателей в качестве значений. Не забывайте, что, как отмечалось ранее, нам также необходимо зарегистрировать поставщика услуг, который мы создали ранее.

 <?php require_once __DIR__.'/../vendor/autoload.php'; use Silex\Application; use App\Providers\TopCreatorsRetrieverServiceProvider; $app = new Application(); $app['debug'] = true; $app->register(new TopCreatorsRetrieverServiceProvider()); $app->get('/creators/{location}/{language}', function (Application $app, $location, $language) { $data = $app['topCreatorsRetriever']->retrieve($location, $language); return $app->json($data); }); $app->run(); 

Очень просто. Единственное, что изменилось, — это регистрация нашего поставщика услуг и нашего маршрута, который содержит только две строки:

  1. Первая строка получает данные из класса TopCreatorsRetriever , и
  2. Вторая строка превращает эти данные в JSON.

Теперь, если вы отправите запрос по http://homestead.app:8000/creators/Tehran/PHP , вы увидите всех создателей пакетов с наибольшим количеством наблюдателей, которые живут в Тегеране:

 { "sallar":198, "sepehr":86, "reshadman":49, "moein7tl":49, "alijmlzd":13, "atkrad":4, "AmirHossein":3, "Yousha":0, "voltan":0, "zoli":0 } 

Поздравляем! Теперь вы знаете, кто самые популярные создатели пакетов в любой области!

Вывод

Теперь у нас есть приложение, которое собирает значимые данные из GitHub с помощью очень простого механизма: мы выбираем лучших пользователей в области, у которых есть репозиторий на нужном нам языке, и добавляем наблюдатели звезд для всех своих репозиториев.

Надеюсь, этот урок научил вас чему-то новому и полезному. Пожалуйста, оставьте свой отзыв в комментариях ниже, и не забудьте, что вы можете проверить полный исходный код здесь !