过滤 laravel 中的数据并处理视图
Filtering data in laravel and handling the views
我有一个 netflix 风格的电视节目项目,我正在构建一个 Shows
页面,我想按格式过滤该页面。每个节目都包含剧集,剧集可以是电视、DVD 和 BD 格式。
目前我正在使用单独的路由和控制器进行过滤,这些路由和控制器扩展了基础 ShowsController
。
Route::get('shows/view/{type}', ['as' => 'shows.viewtype', 'uses' => 'ShowsController@viewType',]);
Route::get('shows/bluray',['as' => 'shows.bluray','uses' => 'ShowsBlurayController@index']);
Route::get('shows/dvd',['as' => 'shows.dvd','uses' => 'ShowsDVDController@index']);
Route::get('shows/tv',['as' => 'shows.tv','uses' => 'ShowsTVController@index']);
格式控制器之一的示例
class ShowsBlurayController extends ShowsController
{
public function index()
{
// Set user state for browsing bluray
Session::push('user.showtype', 'bluray');
$shows = $this->show->getBlurayPaginated(16);
return $this->getIndexView(compact('shows'));
}
}
我使用 getIndexView()
方法(在 ShowsController
中)来确定 2 个可用视图之一:poster
和 list
。
public function getIndexView($shows)
{
$viewType = get_session_or_cookie('show_viewtype', 'list');
if ($viewType == 'posters') {
return View::make('shows.index', $shows)
->nest('showsView', 'shows.partials.posters', $shows);
} else {
return View::make('shows.index', $shows)
->nest('showsView', 'shows.partials.list', $shows);
}
}
根据剧集筛选节目:
public function getBlurayPaginated($perPage)
{
return $this->getByFormat('BD')->with('tagged')->paginate($perPage);
}
private function getByFormat($format)
{
return $this->show->whereHas('episodes', function ($q) use ($format) {
$q->whereHas('format', function ($q) use ($format) {
$q->where('format', '=', $format);
});
});
}
问题是我想以干净的方式执行此操作。当用户选择一种格式时,将应用该过滤器。目前,所有这些都分散在控制器中,没有多大意义。
我也想过在 routes.php
中做这样的事情:
Route::get('shows/format/{format}',['as' => 'shows.format','uses' => 'ShowsController@index']);
然后处理索引中的过滤,但这似乎也是一个奇怪的地方。
这种方法确实有效,但我不想以后再用它来搞砸自己。我正在计划一个简单的搜索,应该考虑过滤器。
换句话说,我如何组织代码,使从数据库获取数据时考虑已设置的过滤器? (可能是会话状态?)
Route::get('shows/format/{format}',[
'as' => 'shows.format',
'uses' => 'ShowsController@index'
]);
我认为您的方向是正确的。我什至会生成一个 factory 并将其注入控制器。这个工厂的目的是构建一个格式化程序,为您的视图提供正确的数据:
// ShowController
public function __construct(ShowFormatFactory $factory, ShowRepository $shows)
{
$this->factory = $factory;
// NB: using a repository here just for illustrative purposes.
$this->shows = $shows;
}
public function index($format = null)
{
$formatter = $this->factory->make($format);
return View::make('shows.index', [
'formatter' => $formatter,
'shows' => $this->shows->all(),
]);
}
// ShowFormatFactory
class ShowFormatFactory
{
public function make($format)
{
switch($format) {
case 'blueray':
return new BluerayFormat(); break;
case 'dvd': /* Fallthrough for default option */
default:
return new BluerayFormat(); break;
}
}
}
// ShowFormatInterface
interface ShowFormatInterface
{
public function format(Show $show);
}
// BluerayFormat
class BluerayFormat implements ShowFormatInterface
{
public function format(Show $show)
{
return $show->blueray_format;
}
}
然后在您看来,既然您保证有一个对象可以为您提供给定节目所要求的格式,那么只需将其命名为:
@foreach($shows as $show)
<div class="show">
Chosen Format: {{ $formatter->format($show) }}
</div>
@endforeach
此解决方案是可测试和可扩展的,允许您稍后添加其他格式。如果这样做,您需要在工厂中为每种不同的格式添加一个离散的 case
语句,并编写相当纤细的 ~5-7 行 class 来支持新格式。
我有一个 netflix 风格的电视节目项目,我正在构建一个 Shows
页面,我想按格式过滤该页面。每个节目都包含剧集,剧集可以是电视、DVD 和 BD 格式。
目前我正在使用单独的路由和控制器进行过滤,这些路由和控制器扩展了基础 ShowsController
。
Route::get('shows/view/{type}', ['as' => 'shows.viewtype', 'uses' => 'ShowsController@viewType',]);
Route::get('shows/bluray',['as' => 'shows.bluray','uses' => 'ShowsBlurayController@index']);
Route::get('shows/dvd',['as' => 'shows.dvd','uses' => 'ShowsDVDController@index']);
Route::get('shows/tv',['as' => 'shows.tv','uses' => 'ShowsTVController@index']);
格式控制器之一的示例
class ShowsBlurayController extends ShowsController
{
public function index()
{
// Set user state for browsing bluray
Session::push('user.showtype', 'bluray');
$shows = $this->show->getBlurayPaginated(16);
return $this->getIndexView(compact('shows'));
}
}
我使用 getIndexView()
方法(在 ShowsController
中)来确定 2 个可用视图之一:poster
和 list
。
public function getIndexView($shows)
{
$viewType = get_session_or_cookie('show_viewtype', 'list');
if ($viewType == 'posters') {
return View::make('shows.index', $shows)
->nest('showsView', 'shows.partials.posters', $shows);
} else {
return View::make('shows.index', $shows)
->nest('showsView', 'shows.partials.list', $shows);
}
}
根据剧集筛选节目:
public function getBlurayPaginated($perPage)
{
return $this->getByFormat('BD')->with('tagged')->paginate($perPage);
}
private function getByFormat($format)
{
return $this->show->whereHas('episodes', function ($q) use ($format) {
$q->whereHas('format', function ($q) use ($format) {
$q->where('format', '=', $format);
});
});
}
问题是我想以干净的方式执行此操作。当用户选择一种格式时,将应用该过滤器。目前,所有这些都分散在控制器中,没有多大意义。
我也想过在 routes.php
中做这样的事情:
Route::get('shows/format/{format}',['as' => 'shows.format','uses' => 'ShowsController@index']);
然后处理索引中的过滤,但这似乎也是一个奇怪的地方。
这种方法确实有效,但我不想以后再用它来搞砸自己。我正在计划一个简单的搜索,应该考虑过滤器。
换句话说,我如何组织代码,使从数据库获取数据时考虑已设置的过滤器? (可能是会话状态?)
Route::get('shows/format/{format}',[
'as' => 'shows.format',
'uses' => 'ShowsController@index'
]);
我认为您的方向是正确的。我什至会生成一个 factory 并将其注入控制器。这个工厂的目的是构建一个格式化程序,为您的视图提供正确的数据:
// ShowController
public function __construct(ShowFormatFactory $factory, ShowRepository $shows)
{
$this->factory = $factory;
// NB: using a repository here just for illustrative purposes.
$this->shows = $shows;
}
public function index($format = null)
{
$formatter = $this->factory->make($format);
return View::make('shows.index', [
'formatter' => $formatter,
'shows' => $this->shows->all(),
]);
}
// ShowFormatFactory
class ShowFormatFactory
{
public function make($format)
{
switch($format) {
case 'blueray':
return new BluerayFormat(); break;
case 'dvd': /* Fallthrough for default option */
default:
return new BluerayFormat(); break;
}
}
}
// ShowFormatInterface
interface ShowFormatInterface
{
public function format(Show $show);
}
// BluerayFormat
class BluerayFormat implements ShowFormatInterface
{
public function format(Show $show)
{
return $show->blueray_format;
}
}
然后在您看来,既然您保证有一个对象可以为您提供给定节目所要求的格式,那么只需将其命名为:
@foreach($shows as $show)
<div class="show">
Chosen Format: {{ $formatter->format($show) }}
</div>
@endforeach
此解决方案是可测试和可扩展的,允许您稍后添加其他格式。如果这样做,您需要在工厂中为每种不同的格式添加一个离散的 case
语句,并编写相当纤细的 ~5-7 行 class 来支持新格式。