Я хочу сделать первое приложение API в Laravel. Я не знаю, как лучше всего это сделать, я объясню, что я пытаюсь сделать, но, пожалуйста, не стесняйтесь давать ответы, как сделать это по-другому.
Я не хочу, чтобы весь мой интерфейс был написан в javascript и проанализировал вывод JSON API с помощью angular.js или что-то подобное. Я хочу, чтобы приложение Laravel создавало HTML-представления. Я пытаюсь пойти по пути, имея два контроллера для API и один для Интернета. Для показа действия пользователя мои routes.php выглядят так:
# the web controller Route::controller('user', 'WebUserController'); # the api controller Route::group(array('prefix' => 'api'), function() { Route::resource('user', 'UserController'); });
Таким образом, /user
возьмет меня в WebUserController
и /api/user
приведет меня в UserController
. Теперь я хочу поместить всю свою логику в API UserController
и вызвать его действия из WebUserController
. Вот код для обоих из них:
class UserController extends BaseController { public function show($id) { $user = User::find($id); return Response::json(array('success'=>true,'user'=>$user->toArray())); } } class WebUserController extends UserController { public function getView($id) { # call the show method of the API's User Controller $response = $this->show($id); return View::make('user.view')->with('data', $response->getData()); } }
В WebUserController
я могу получить json-контент ответа с помощью getData()
, но я не могу получить заголовки и код состояния (они являются защищенными свойствами Illuminate\Http\JsonResponse
).
Я думаю, что мой подход может быть не лучшим, поэтому я открыт для предложений, как сделать это приложение.
EDIT : на вопрос, как получить заголовки и статус ответа, ответил Дрю Льюис , но я все же думаю, что может быть лучший способ разработки этого
Вы должны использовать шаблон оформления репозитория / шлюза: см. Ответы здесь .
Например, при работе с моделью пользователя сначала создайте репозиторий пользователей. Единственная ответственность пользовательского репозитория заключается в связи с базой данных (выполнение CRUD-операций). Этот репозиторий пользователей расширяет общий базовый репозиторий и реализует интерфейс, содержащий все необходимые вам методы:
class EloquentUserRepository extends BaseRepository implements UserRepository { public function __construct(User $user) { $this->user = $user; } public function all() { return $this->user->all(); } public function get($id){} public function create(array $data){} public function update(array $data){} public function delete($id){} // Any other methods you need go here (getRecent, deleteWhere, etc) }
Затем создайте поставщика услуг, который связывает ваш интерфейс репозитория пользователя с вашим красноречивым репозиторием пользователей. Всякий раз, когда вам требуется репозиторий пользователя (разрешая его через контейнер IoC или вводя зависимость в конструкторе), Laravel автоматически предоставляет вам экземпляр созданного вами репозитория пользователя Eloquent. Это так, что если вы измените ORM на нечто иное, чем красноречивое, вы можете просто изменить этого поставщика услуг и никаких других изменений в вашей кодовой базе не требуется:
use Illuminate\Support\ServiceProvider; class RepositoryServiceProvider extends ServiceProvider { public function register() { $this->app->bind( 'lib\Repositories\UserRepository', // Assuming you used these 'lib\Repositories\EloquentUserRepository' // namespaces ); } }
Затем создайте пользовательский шлюз, целью которого является общение с любым количеством репозиториев и выполнение любой бизнес-логики вашего приложения:
use lib\Repositories\UserRepository; class UserGateway { protected $userRepository; public function __construct(UserRepository $userRepository) { $this->userRepository = $userRepository; } public function createUser(array $input) { // perform any sort of validation first return $this->userRepository->create($input); } }
Наконец, создайте свой пользовательский веб-контроллер. Этот контроллер разговаривает с вашим User Gateway:
class UserController extends BaseController { public function __construct(UserGatway $userGateway) { $this->userGateway = $userGateway; } public function create() { $user = $this->userGateway->createUser(Input::all()); } }
Структурируя дизайн своего приложения таким образом, вы получаете несколько преимуществ: вы получаете очень четкое разделение проблем, так как ваше приложение будет придерживаться принципа единой ответственности (отделяя вашу бизнес-логику от логики базы данных). Это позволяет вам выполнять тестирование модулей и интеграции намного проще, делает ваши контроллеры максимально возможными, а также позволяет вам легко заменять Eloquent для любой другой базы данных, если вы захотите в будущем.
Например, при переходе с Eloquent на Mongo единственное, что вам нужно изменить, это привязка поставщика услуг, а также создание MongoUserRepository, который реализует интерфейс UserRepository. Это связано с тем, что репозиторий – это единственное, что говорит с вашей базой данных – оно ничего не знает. Поэтому новый MongoUserRepository может выглядеть примерно так:
class MongoUserRepository extends BaseRepository implements UserRepository { public function __construct(MongoUser $user) { $this->user = $user; } public function all() { // Retrieve all users from the mongo db } ... }
И теперь поставщик услуг привяжет интерфейс UserRepository к новому MongoUserRepository:
$this->app->bind( 'lib\Repositories\UserRepository', 'lib\Repositories\MongoUserRepository' );
На всех ваших шлюзах вы ссылаетесь на UserRepository, поэтому, сделав это изменение, вы, по сути, говорите Laravel, чтобы использовать новый MongoUserRepository вместо старого Eloquent. Никаких других изменений не требуется.
Для этого проекта вы должны использовать репозиторий.
Пример –
//UserRepository Class class UserRepository { public function getById($id) { return User::find($id); } } // WebUser Controller class WebUserController extends BaseController { protected $user; public function __construct(UserRepository $user) { $this->user = $user; } public function show($id) { return View::make('user.view')->with('data', $this->user->getById($id)); } } // APIUser Controller class UserController extends BaseController { protected $user; public function __construct(UserRepository $user) { $this->user = $user; } public function show($id) { $data =>$this->user->getById($id); return Response::json(array('success'=>true,'user'= $data->toArray())); } }
Checkout Контроллеры RESTful Laravel:
http://laravel.com/docs/controllers#restful-controllers
Их документы выполняют довольно хорошую работу.
Но еще лучше – этот урок:
http://code.tutsplus.com/tutorials/laravel-4-a-start-at-a-restful-api-updated–net-29785
Это видео Джеффри Пути, он один из лучших разработчиков Laravel. В этом уроке он подключает приложение BackboneJS к службе RESTful, которую он устанавливает в Laravel. Тогда это не улучшится. Я могу написать вам много шаблонов, но просто изучите его, посмотрев хорошее видео и выпейте кофе. 😉
У меня есть ответ на проблему, с которой вы сталкиваетесь с ответом. Вы можете получить заголовки, код состояния и данные из ответа.
// your data $response->getData(); // the status code of the Response $response->getStatusCode(); // array of headers $response->headers->all(); // array of headers with preserved case $response->headers->allPreserveCase();
$ response-> – это Symfony \ Component \ HttpFoundation \ ResponseHeaderBag, который наследуется от Symfony \ Component \ HttpFoundation \ HeaderBag
Я бы также рекомендовал использовать репозиторий. Попытка вызвать один контроллер из другого будет падать в шаблон под названием HMVC (Hierarchical model-view-controller). Это означает, что все ваше приложение опирается на более низкие модули. В этом случае ваш API будет служить репозиторием для ваших данных (что в первую очередь не самое худшее в мире).
Однако, когда вы затем изменяете структуру того, как данные возвращаются в вашем API, все остальное, опираясь на это, должно будет знать, как реагировать. Скажите, что вы хотели иметь проверки авторизации, чтобы увидеть, сможет ли зарегистрированный пользователь увидеть детали возвращаемого пользователя и произошла ошибка.
В API вы возвращаете объект Response с 403 запрещенным кодом и некоторыми метаданными. Ваш контроллер HTML должен будет знать, как справиться с этим.
Сравните это с хранилищем, которое может вызвать исключение.
public function findById ($id) { $user = User::findOrFail($id); if (Auth::user->hasAccessTo($user)) { return $user; } else { throw new UnauthorizedAccessException('you do not have sufficient access to this resource'); } }
И ваш контроллер API будет выглядеть следующим образом:
public function show($id) { try { return $this->user->findById($id); } catch (UnauthorizedAccessException $e) { $message = $e->getMessage(); return Response::json('403', ['meta' => ['message' => $message]])); } }
Ваш HTML-контроллер будет выглядеть следующим образом:
public function show($id) { try { $user = $this->user->findById($id); } catch (UnauthorizedAccessException $e) { Session::flash('error', $e->getMessage()); // Redirect wherever you would like return Response::redirect('/'); } }
Это дает вам код многократного использования и позволяет вам самостоятельно менять свои реализации контроллера, не опасаясь изменить поведение другого. Я написал больше о том, как реализовать шаблон репозитория в этом сообщении : вы можете игнорировать интерфейс и, если хотите, пропустить право на реализацию.