Реализация шаблона репозитория с помощью LaravelPhp

Кемеровские программисты php общаются здесь
Ответить
Anonymous
 Реализация шаблона репозитория с помощью Laravel

Сообщение Anonymous »

Недавно я начал изучать Laravel 4 и его возможности. Я хочу реализовать шаблон репозитория, чтобы переместить туда логику модели. И на этом этапе я столкнулся с рядом неудобств или непониманием того, как это организовать. Общий вопрос у меня звучит примерно так: Можно ли реализовать и применить этот шаблон в Laravel без головной боли и стоит ли это?

Вопрос был разделен на несколько частей, что вызвало у меня замешательство.

1) Laravel предоставляет удобный способ привязки модели в качестве параметра контроллера, например. я делаю это так:

Код: Выделить всё

// routes.php
Route::bind('article', function($slug)
{
return Article::where('slug', $slug)->first();
});

Route::get('articles/{article}', 'ArticlesController@getArticle');

// controllers/ArticlesController.php
class ArticlesController extends BaseController {

public function getArticle(Article $article)
{
return View::make('article.show', compact('article'));
}
}
Если я хочу использовать паттерн «Репозиторий», то я не могу использовать этот подход, так как в этом случае контроллер явно будет знать о существовании моделей Артикул? Правильно ли будет переписать этот пример с использованием шаблона репозитория таким образом:

Код: Выделить всё

// routes.php
Route::get('articles/{slug}', 'ArticlesController@getArticle');

// controllers/ArticlesController.php
class ArticlesController extends BaseController {

private $article;

public function __construct(ArticleRepository $article) {
$this->article = $article;
}

public function getArticle($slug)
{
$article = $this->article->findBySlug($slug);

return View::make('article.show', compact('article'));
}
}
2) Предположим, мой код выше с использованием репозитория верен. Теперь я хочу увеличивать счетчик просмотров статьи каждый раз, когда она будет показана, однако я хочу выполнить эту обработку в событии. То есть код такой:

Код: Выделить всё

// routes.php
Route::get('articles/{slug}', 'ArticlesController@getArticle');

// controllers/ArticlesController.php
class ArticlesController extends BaseController {

private $article;

public function __construct(ArticleRepository $article) {
$this->article = $article;
}

public function getArticle($slug)
{
$article = $this->article->findBySlug($slug);
Events::fire('article.shown');

return View::make('articles.single', compact('article'));
}
}

// some event subscriber
class ArticleSubscriber {

public function onShown()
{
// why implementation is missed described bellow
}

public function subscribe($events)
{
$events->listen('article.shown', 'ArticleSubscriber@onShown');
}

}
На этом этапе я снова задумался о том, как реализовать обработку событий. Я не могу передать модель $article напрямую в событие, потому что это опять же нарушает принципы ООП и мой подписчик узнает о существовании модели статьи. Итак, я не могу этого сделать:

Код: Выделить всё

// controllers/ArticlesController.php
...
\Events::fire('article.shown', $article);
...

// some event subscriber
...
public function onShown(Article $article)
{
$article->increment('views');
}
...
С другой стороны, я не вижу смысла вводить в репозиторий подписчика ArticleRepository (или внедрять его в конструктор подписчика), потому что сначала мне нужно найти статью, а потом обновить счетчик, в итоге я получу дополнительный запрос (потому что раньше в конструкторе я делал то же самое) к базе данных:

Код: Выделить всё

// controllers/ArticlesController.php
...
Events::fire('article.shown', $slug);
...

// some event subscriber
...
private $article;

public function __construct(ArticleRepository $articleRepository)
{
$this->article = $articleRepository;
}

public function onShown($slug)
{
$article = $this->articleRepository->findBySlug($slug);
$article->increment('views');
}
...
Более того, после обработки События (т.е. увеличения количества просмотров) необходимо, чтобы контроллер знал об обновленной модели, потому что в представлении я хочу для отображения обновленного счетчика просмотров. Получается, что как-то мне все равно нужно вернуть новую модель из Event, но мне бы не хотелось, чтобы Event стал общим методом обработки того или иного действия (для этого есть репозиторий) и вернуть некоторое значение. Кроме того, вы можете заметить, что мой последний метод onShow() снова противоречит правилам шаблона Repository, но я не понимаю, как поместить эту логику в репозиторий:

Код: Выделить всё

public function onShown($slug)
{
$article = $this->articleRepository->findBySlug($slug);
// INCORRECT! because the Event shouldn't know that the model is able to implement Eloquent
// $article->increment('views');
}
Можно ли как-то передать найденную модель обратно в репозиторий и увеличить ее счетчик (противоречит ли это такому подходу к шаблону Repository?)? Примерно так:

Код: Выделить всё

public function onShown($slug)
{
$article = $this->articleRepository->findBySlug($slug);
$this->articleRepository->updateViews($article);
}

// ArticleRepository.php
...
public function updateViews(Article $article) {
$article->increment('views');
}
...
В результате попробую сформулировать всё более компактно:
  • Мне придется отказаться от передачи моделей непосредственно в контроллер и от других удобств, предоставляемых DI, если я буду использовать шаблон репозитория?
  • Можно ли использовать репозиторий для хранения состояния модели и передавать его между сущностями (например, от фильтра к контроллеру от контроллера к Event и обратно), избегая нецензурных повторных обращений к db и такой подход будет правильным (постоянство модели)?
Такие дела, это мои вопросы. Хотелось бы услышать ответы, мысли, комментарии. Может быть, я неправильно подхожу к нанесению выкройки? Теперь это вызывает больше головной боли, чем решает проблему сопоставления данных.

Также я прочитал несколько статей о реализации репозитория:
но это не решает моего недоразумения

Подробнее здесь: https://stackoverflow.com/questions/267 ... th-laravel
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Php»