Если вы когда-либо разрабатывали API, у вас могли возникнуть проблемы с изменениями схемы базы данных. Если у вас не было хорошей реализации, вам пришлось переделывать всю модель при изменении имен некоторых столбцов. В этой статье я покажу, как вы можете использовать Fractal в качестве слоя между вашими моделями и выводом JSON. Этот пост покажет вам, как этот пакет облегчит разработку API.
Фрактал как пакет
Fractal — это проект, написанный на PHP и являющийся частью Лиги выдающихся пакетов . Все эти пакеты соответствуют нескольким требованиям, таким как использование PHP-FIG и покрытие Unit Test. Фрактал в основном разработан Филом Стердженом и до сих пор регулярно совершенствуется. Он также может быть использован с Composer .
Настройка среды
В демонстрационных целях я сейчас настрою фреймворк, используя Silex и Illuminate / Database (компонент ORM в Laravel). Неважно, если у вас нет опыта с одним из них. То, что я сделаю, очень просто, и я объясню их настолько, насколько смогу. Если что-то неясно, не стесняйтесь оставлять комментарии.
Я сейчас настрою рамки. Обратите внимание, что если вы не хотите следовать инструкциям, вы можете загрузить весь код в конце статьи . Теперь начните с создания новой папки внутри корневой папки. Мы начнем с создания нашего файла composer.json
со всеми необходимыми нам зависимостями. В нашем случае: Silex and Illuminate \ Database. Создайте файл composer.json
следующим образом:
{ "require": { "silex/silex": "~1.2", "illuminate/database": "*" }, }
Установите пакеты с помощью composer install
.
База данных
Я возьму пример онлайновой музыкальной базы данных. База данных предоставит информацию для нескольких песен: название песни, имя исполнителя, сайт исполнителя, название альбома, дата выпуска и музыкальный лейбл. В начале все это будет в одной таблице. Если вы хотите попробовать сами, загрузите файл 1.sql
из репозитория этой статьи и запустите его в своей базе данных.
Код
Чтобы использовать Silex с Illuminate \ Database, нам понадобится код. Внутри app folder
создайте новый файл index.php
. Здесь мы запустим Silex, подключимся к базе данных и определим маршруты:
<?php require("../vendor/autoload.php"); $app = new Silex\Application(); $app['database'] = require("database.php"); $app->mount('/tracks', include 'controllers/tracks.php'); $app->run();
В первой строке нам нужен файл автозагрузки для композитора. Затем мы создаем новое приложение Silex и загружаем в Illuminate/Database
. Затем мы создаем контроллер для /tracks
чтобы все URL, начинающиеся с controllers/tracks.php
были обработаны controllers/tracks.php
. Файл database.php
выглядит следующим образом, не забудьте изменить настройки соединения:
<?php use Illuminate\Database\Capsule\Manager as Capsule; $capsule = new Capsule; $capsule->addConnection([ 'driver' => 'mysql', 'host' => 'localhost', 'database' => 'musicstore', 'username' => 'root', 'password' => '', 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => '', ]); use Illuminate\Events\Dispatcher; use Illuminate\Container\Container; $capsule->setEventDispatcher(new Dispatcher(new Container)); $capsule->setAsGlobal(); $capsule->bootEloquent(); return $capsule;
Первая версия API
Первоначально база данных содержит только одну таблицу (импорт 1.sql
). Эта таблица содержит информацию о самом треке (название, музыкальный лейбл), альбоме (название и дата выпуска) и исполнителе (название и веб-сайт). Наш API предоставит две вещи: при переходе к /tracks
он выведет список json с идентификаторами дорожек, их заголовком и исполнителем. При переходе к /tracks/$id
track /tracks/$id
он выводит всю информацию о дорожке в виде объекта json.
Отслеживание
Начнем со списка треков. Поместите этот код в /controllers/tracks.php
:
<?php $tracks = $app['controllers_factory']; $tracks->get('/', function() use ($app) { $tracklist = Track::getTrackList(); $output = array("data" => $tracklist); return json_encode($output); }); return $tracks;
и этот код для модели, /models/Track.php
:
public static function getTrackList() { return Track::select('id','name','artist_name')->get(); }
При этом используется запросщик Illuminate \ Database, чтобы получить список идентификаторов, имен и статей, а затем вывести их. Вывод будет иметь такой формат:
{ data: [ { id: 1, name: "Song 1", artist_name: "Artist 1" }, { id: 2, name: "Song 2", artist_name: "Artist 2" } ] }
Это работает, как и ожидалось, но если схема таблицы изменится, изменится и вывод JSON. Теперь мы будем использовать фрактальный трансформатор для форсирования определенной структуры производства. Этот Transformer является классом, расширяющим Fractal\TransformerAbstract
. Создайте новую папку для преобразователей в папке вашего приложения с именем transformers
. Первым преобразователем является TracklistTransformer.php
который мы будем использовать исключительно для /tracks
, и он выглядит так:
<?php namespace Musicstore; class TracklistTransformer extends \League\Fractal\TransformerAbstract { public function transform(Track $track) { return [ 'id' => (int) $track->id, 'title' => $track->title, 'artist' => $track->artist_name ]; } }
Каждому преобразователю требуется метод transform()
, аргументом которого является объект, который вы хотите преобразовать, в нашем случае это экземпляр класса Track
. В операторе return структура определяется как ассоциативный массив.
Теперь мы применим преобразование и создадим выходной массив с использованием сериализатора . Мы собираемся использовать DataArraySerializer
потому что это поместит наши данные под data-key
в объекте JSON. Это позволяет вам иметь в своем ответе другую информацию, такую как коды состояния или сообщения об ошибках. Чтобы использовать этот сериализатор, нам понадобится экземпляр класса manager. Для этого я буду использовать DI-контейнер, чтобы нам не приходилось каждый раз переписывать шаблонный код. Новый файл /controllers/tracks.php
выглядит следующим образом:
<?php $tracks = $app['controllers_factory']; $tracks->get('/', function() use ($app) { $tracks = Track::getTrackList(); $tracklist = new \League\Fractal\Resource\Collection($tracks, new TracklistTransformer); $output = $app['serializer']->createData($tracklist)->toArray(); return json_encode($output); }); return $tracks;
Мы используем $tracklist = new \League\Fractal\Resource\Collection($tracks, new TracklistTransformer);
применить преобразование. В этом маршруте мы используем коллекцию треков: наша переменная $tracks
является объектом класса Illuminate \ Database \ Eloquent \ Collection . Этот класс совместим с Fractal и его преобразователями. Для другого маршрута мы будем использовать трансформатор для одного элемента таблицы. Но об этом чуть позже.
Для использования $app['serializer']
поместите этот код в index.php
, прямо под оператором app['database']
:
$app['serializer'] = $app->share(function() { $manager = new \League\Fractal\Manager(); $manager->setSerializer(new League\Fractal\Serializer\DataArraySerializer()); return $manager; });
Теперь у вас есть рабочий треклист.
Отслеживать информацию
Теперь я быстро продемонстрирую, как отображать информацию о конкретных дорожках, а затем вносить изменения в схему данных с помощью Fractal. Откройте controllers/tracks.php
и добавьте следующий код над оператором возврата:
<?php $tracks->get('/{id}', function($id) use ($app) { return Track::find($id); });
Track::find($id)
возвращает объект класса Track с идентификатором, соответствующим URL. Опять же, это работает, но это не очень хороший способ, поэтому мы будем внедрять Fractal. Создайте новый трансформатор transformers/TrackTransformer.php
:
<?php namespace Musicstore; class TrackTransformer extends \League\Fractal\TransformerAbstract { public function transform(Track $track) { return [ 'id' => (int) $track->id, 'title' => $track->title, 'artist_name' => $track->artist_name, 'artist_website' => $track->artist_website, 'album_name' => $track->album_name, 'album_release' => $track->album_release, 'album_label' => $track->album_label ]; } }
В вашем контроллере отредактируйте маршрут к этому:
$tracks->get('/{id}', function($id) use ($app) { $track = Track::find($id); $track = new \League\Fractal\Resource\Item($track, new TrackTransformer); $output = $app['serializer']->createData($track)->toArray(); return json_encode($output); });
Как вы можете видеть, он довольно похож на предыдущий маршрут, за исключением того, что в данном случае мы имеем дело не с Collection
а с одним Item
. Если вы используете 1.sql
вы можете перейти к localhost/app/tracks/1
1.sql
localhost/app/tracks/1
и посмотреть некоторые примеры данных.
Обновленная версия API
Наш музыкальный магазин хочет расширяться и предоставлять больше информации об артистах и альбомах. В новой схеме базы данных есть отдельные таблицы для художников и альбомов. Вы можете скачать 2.sql
чтобы использовать новую схему. Таблицы выглядят так:
СЛЕДЫ:
- Я бы
- заглавие
- artist_id
- album_id
ХУДОЖНИКИ:
- Я бы
- имя
- интернет сайт
АЛЬБОМЫ:
- Я бы
- имя
- выпуск
- метка
В таблице дорожек столбцы исполнителя и альбома представляют собой целые числа, которые соответствуют строкам в соответствующих таблицах. Мы будем использовать трансформеры, чтобы сохранить нашу структуру вывода одинаковой. Чтобы упростить задачу, мы будем использовать некоторые функции Illuminate\Database
. Зайдите в models/Track.php
и добавьте еще два метода:
public function artist() { return $this->belongsTo('\Musicstore\Artist'); } public function album() { return $this->belongsTo('\Musicstore\Album'); }
Если у нас есть объект Track
мы можем получить доступ к его Album
и Artist
, используя $track->album
и $track->artist
. Сначала нам нужно создать эти модели, поэтому создайте два файла models/Artist.php
и models/Album.php
:
// models/Artist.php <?php namespace Musicstore; class Artist extends \Illuminate\Database\Eloquent\Model { public function tracks() { return $this->hasMany('\Musicstore\Track'); } } // models/Album.php <?php namespace Musicstore; class Album extends \Illuminate\Database\Eloquent\Model { public function tracks() { return $this->hasMany('\Musicstore\Track'); } }
Последнее, что нам нужно сделать, это отредактировать наши трансформеры:
// transformers/TrackTransformer.php return [ 'id' => (int) $track->id, 'title' => $track->title, 'artist_name' => $track->artist->name, 'artist_website' => $track->artist->website, 'album_name' => $track->album->name, 'album_release' => $track->album->release, 'album_label' => $track->album->label ]; // transformers/TracklistTransformer.php return [ 'id' => (int) $track->id, 'title' => $track->title, 'artist' => $track->artist->name ];
Если вы все протестируете, вы увидите, что это работает.
Вывод
Как я продемонстрировал, вы можете, добавив Fractal перед выводом, легко вносить изменения в базу данных, не замечая конечного пользователя. Вы можете скачать полный пример кода здесь в моем хранилище . Если что-то неясно, пожалуйста, не стесняйтесь оставлять комментарии.