Создаем библиотеку на php и публикуем на packagist

image-loader.svg

Прежде чем приступать к написанию кода, нам нужно решить, что именно такого полезного мы можем создать, какие функции будет выполнять библиотека. Довольно популярным является написание библиотек, упрощающих работу с тем или иным API. Зачастую API представляют из себя большой список различных методов, работающих не только через GET method http-протокола. И это доставляет сложность при работе с ним у программистов: нужно постоянно учитывать все нюансы обращения к методу, его ответа, а еще может присутствовать аутентификация при работе и тд.

Гораздо проще иметь готовый класс или группу классов, через которые можно легко объектно-ориентированно работать, не сильно заботясь обо всех этих нюансах, к тому же современные IDE умеют подсказывать и подсвечивать, когда у вас есть такой класс, а стороннего API они никак не знают и не подскажут. Поэтому написание библиотеки-прослойки между API и использующим его приложением так популярно.

Наша основная цель научиться создавать и публиковать lib для composer, а не реализация крутого и огромного решения, поэтому я выбрал API, которое уже имеет официальную php client library, но все же его вполне можно дополнить, и тем самым упростить использование. Я говорю о Почте от Google: Gmail API. Если перейти на официальную страницу настройки и использования этого API https://developers.google.com/gmail/api/quickstart/php, то мы увидим, что она предполагает все же некоторую подготовительную работу прежде, чем можно будет приступить к непосредственной работе с почтой.

Посмотрим на листинг в пункте «Step 2: Set up the sample», там мы видим подключение composer зависимостей, затем функцию getClient (), которая создает подключение к сервису почты, и только после нее идет пример кода работы с почтовыми лейблами. Как минимум эту функцию мы можем вынести за скобки нашего основного веб-приложения в библиотеку, которую сделать доступной для установки на любой проект, где понадобится работа с Gmail. Конечно, в реальном мире разработки создавать библиотеку только ради упрощения одной функции идея не самая лучшая, но мы учимся, к тому же вполне вероятно, что во время работы мы войдем во вкус и придумаем, что еще можно упростить, ускорить и вынести в библиотеку кроме этой функции настройки и подключения.

Создание библиотеки

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

mkdir gmail && cd gmail
composer init

Composer предлагает нам ввести данные о создаваемом пакете:

Welcome to the Composer config generator  

This command will guide you through creating your composer.json config.

Package name (/) [zhukmax/gmail]: 
Description []: Package for easy using Gmail Api
Author [ZhukMax , n to skip]: 
Minimum Stability []: dev
Package Type (e.g. library, project, metapackage, composer-plugin) []: library
License []: Apache-2.0

Define your dependencies.

Would you like to define your dependencies (require) interactively [yes]? no
Would you like to define your dev dependencies (require-dev) interactively [yes]? no

{
    "name": "zhukmax/gmail",
    "description": "Package for easy using Gmail Api",
    "type": "library",
    "license": "Apache-2.0",
    "authors": [
        {
            "name": "ZhukMax",
            "email": "zhukmax@ya.ru"
        }
    ],
    "minimum-stability": "dev",
    "require": {}
}

Do you confirm generation [yes]?
Include the Composer autoloader with: require 'vendor/autoload.php';

Обратим внимание на название пакета (Package name), оно должно быть уникальным для того, чтобы можно было разместиться в packagist. Так же мы видим, что composer в квадратных скобках [ ] предлагает ответ на свой же вопрос, и если нас он устраивает, то просто нажимаем на клавишу Enter, иначе после двоеточия пишем свой вариант. Для лицензии проекта я выбрал Apache второй версии, открытую лицензию, отлично подходящую для opensource публикуемых программных решений, так же есть крайне популярные MIT и GNU GPL (https://ru.wikipedia.org/wiki/GNU_General_Public_License). В поле Description одним предложением описываем свою библиотеку, а в Author можно перечислить авторов, мой Composer уже знает меня, и поэтому подставил по умолчанию. На вопросы о зависимостях (dependencies) я пока что ответил отрицательно, мы поставим нужные зависимости позже, а также добавим кое-что вручную прям в файл composer.json, в котором и хранятся все настройки проекта.

В конце после вопроса «Do you confirm generation [yes]?» мы нажали Enter, и в корне проекта появился файл composer.json. Откроем его и пропишем зависимость от php, я выбрал версию не ниже 7.1, так как седьмая версия выпущена уже более пяти лет. Но если вы предполагаете, что вашей библиотекой будут пользоваться на проектах с php 5, тогда можно проставить »>=5.6.0». Далее запускаем команду установки зависимости от официальной Gmail API библиотеки:

composer require google/apiclient:^2.0

Это займет некоторое время, добавляем autoload, который позволит Composer’у находить все файлы с кодом у нас в проекте, и в конечном итоге наш composer.json будет выглядеть вот так:

{
    "name": "zhukmax/gmail",
    "description": "Package for easy using Gmail Api",
    "type": "library",
    "license": "Apache-2.0",
    "authors": [
        {
            "name": "ZhukMax",
            "email": "zhukmax@ya.ru"
        }
    ],
    "minimum-stability": "dev",
    "require": {
        "php": ">=7.1.0",
        "google/apiclient": "^2.0",
        "ext-json": "*"
    },
    "autoload": {
        "psr-4": {
            "Zhukmax\\Gmail\\": "src/"
        }
    }
}

Заходим на github под своим аккаунтом (если нужно зарегестрируйтесь) и создаем новый репозиторий с названием gmail, так же стоит указать описание, лицензию и другие настройки.

Новый репозиторий на githubНовый репозиторий на github

Подключаем к уже созданому локально проекту новый репозиторий:

git init
git remote add origin https://github.com/ZhukMax/gmail.git
git config checkout.defaultRemote origin
git pull origin main

Открываем папку с нашим проектов в любимом редакторе коде, я лично предпочитаю PhpStrorm, но вполне подойдет даже Notepad++. Создаем директорию src, в которой и будет располагаться основной код. Как видно из листинга выше, мы прописали именно эту папку для всех классов в namespace Zhukmax\Gmail.

Создаем директорию srcСоздаем директорию src

На шаге два из официальной инструкции к работе с Gmail API (https://developers.google.com/gmail/api/quickstart/php#step_2_set_up_the_sample) нам требуется создать файл, в котором размещаем некоторые конфигурационные данные, функцию авторизации и сам код работы с API. Как раз конфигурацию и авторизацию мы и перенесем в наш пакет, чтобы при использовании можно было не заморачиваться с этим кодом и сразу заниматься тем, что необходимо на проекте. Поэтому создаем класс авторизации в src и добавляем в него функцию авторизации:

touch src/Auth.php

Класс авторизацииКласс авторизации

Пока что наш код не будет работать, так как функции авторизации нужны настройки: название приложения, путь к директории для хранения токена, путь к файлу credentials.json, который можно получить в консоли разработчика Google. А еще этот код можно улучшить и упростить работу с ним для конечного разработчика. Для начала создадим публичный конструктор и метод, который будет отдавать готовый к работе сервис, либо выбрасывать исключение (Exception), если произошла какая-то ошибка, а уже созданный сделаем приватным:

credentialsPath = $params['credentials'];

    if (!$params['token']) {
      throw new Exception("Path to token is required");
    }
    $this->tokenPath = $params['token'];
    $this->name = $params['name'] ?? 'Gmail API PHP';
    $this->scope = $params['scope'] ?? Google_Service_Gmail::GMAIL_READONLY;
}

public function getService()
{
    $client = self::getClient();
    return new Google_Service_Gmail($client);
}

Добавляем путь к токенуДобавляем путь к токену

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

createAuthUrl();
    printf("Open the following link in your browser:\n%s\n", $authUrl);
    print 'Enter verification code: ';
    $authCode = trim(fgets(STDIN));

    // Exchange authorization code for an access token.
    $accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
    $client->setAccessToken($accessToken);

    // Check to see if there was an error.
    if (array_key_exists('error', $accessToken)) {
      throw new Exception(join(', ', $accessToken));
    }
}

private function saveToken(Google_Client $client)
{
    if (!file_exists(dirname($this->tokenPath))) {
      mkdir(dirname($this->tokenPath), 0700, true);
    }
    file_put_contents($this->tokenPath, json_encode($client->getAccessToken()));
}

Конечно, еще хорошо бы покрыть весь наш код юнит-тестами, но это уже другая история.

Публикация библиотеки

Когда код библиотеки готов сделаем коммит и отправим все правки в репозиторий на github (или другой выбранный вами ранее):

git push origin main

Теперь скопируем ссылку на репозиторий:

image-loader.svg

На сайте packagist.org после авторизации переходим в раздел Submit, вставляем GitHub URL — ссылку на репозиторий и нажимаем Check и затем Submit

image-loader.svg

Готово, наша библиотка отправлена в публичное пространство и доступна для установок и использования.

Результат

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

Репозиторий с кодом из статьи лежит по ссылке.

© Habrahabr.ru