Articles handler package for L5
Пакет для Laravel 5.2+ предназначенный работы с материалами, которые можно предоставить в виде "Каталог статей - Статья"., (*1)
Разделы 1. Установка 2. Спецификация нефильтруемых статей 3. Спецификация фильтруемых статей, (*2)
Выполняем, (*3)
composer require "vis/articles_l5":"1.*"
Для использования функционала нефильтруемых статей необходимо:, (*4)
use Vis\Articles\Models\AbstractArticle; class PackageArticle extends AbstractArticle { protected $table = 'package_articles'; protected $viewFolder = 'package_articles'; protected $sortOrder = "created_at:desc"; protected $perPage = 25; protected $perPageSettingName = 'kol_statei-v-kataloge-novostei'; protected $relationsInCatalog = []; protected $relationsInArticle = []; public function getUrl() { return route("package_article", [$this->getSlug(), $this->id]); } }
Описание свойств:, (*5)
Путь к папке с view templates Если значение 'sub_folder.package_articles', тогда view должны лежать в папке /resources/views/pages/sub_folder/package_articles Значение: путь к папке через точки, (*6)
protected $viewFolder = 'package_articles';
Путь к папке с view templates Значение: название_поля:порядок, по умолчанию: created_at:desc, (*7)
protected $sortOrder = "created_at:desc";
Количество статей на странице каталога Значение: целое число, по умолчанию: 12, (*8)
protected $perPage = 25;
Название опции в CMS, которая содержит количество статей на странице каталога. Если указано, то параметр $perPage игнорируется Значение: строка с названием опции в CMS, (*9)
protected $perPageSettingName = 'kol_statei-v-kataloge-novostei';
Массив названий дополнительных Eloquent связей, которые необходимо загрузить в каталоге Необходим для реализации Lazy Eager loading на страницах каталогов Значение: массив $relationsInCatalog['', ...], (*10)
protected $relationsInCatalog = [];
Массив названий дополнительных Eloquent связей, которые необходимо загрузить в статье Необходим для реализации Lazy Eager loading на страницах статей Значение: массив $relationsInArticle['', ...], (*11)
protected $relationsInArticle = [];
Описание методов:, (*12)
Метод получения свойства $viewFolder, (*13)
public function getViewFolder(): string;
Метод получения свойства $sortOrder, (*14)
public function getSortOrder(): string;
Метод получения свойства $perPage, (*15)
public function getPerPage(): int;
Метод получения свойства $relationsInCatalog, (*16)
public function getRelationsInCatalog(): array;
Метод получения свойства $RelationsInArticle, (*17)
public function getRelationsInArticle(): array;
Метод-фильтр выведения статей по признаку is_main = 1, (*18)
public function scopeIsMain($query);
Метод-фильтр сортировки статей Значение: строка $order = 'created_at:desc', (*19)
public function scopeFilterCustomOrder($query, string $order);
use Vis\Articles\Controllers\AbstractSimpleArticleController; class PackageArticlesController extends AbstractSimpleArticleController { protected $model = "PackageArticle"; }
Описание свойств:, (*20)
Название модели, которая будет использоваться Значение: строка с названием модели , (*21)
protected $model = "PackageArticle";
'articles_catalog' => array( 'action' => 'PackageArticlesController@showCatalog', 'node_definition' => 'node', 'check' => function() { return true; }, 'title' => 'Каталог статей', ),
Route::get('/test-articles-catalog/{slug}-{id}', [ 'as' => 'package_article', 'uses' => 'PackageArticlesController@showArticle' ]);
@extends('layouts.default') @section('main') <section class="article-section"> <div class="article-text"> <h1> {{$page->t('title')}} </h1> </div> </section> @stop
Пример catalog.blade.php, (*22)
@extends('layouts.default') @section('main') <section class="associations-page"> <div class="container"> <div class="associations-list"> @foreach($articles as $key => $article) <div class="associations-item"> <div class="text"> <div class="title"> <a href="{{$article->getUrl()}}"> {{$article->t('title')}} </a> </div> </div> </div> @endforeach </div> </div> </section> @stop
Часть параметров наследуется от нефильтруемой модели, их описание опущено. Для использования функционала фильтруемых статей необходимо:, (*23)
use Vis\Articles\Models\AbstractFilterableArticle; class PackageFilterableArticle extends AbstractFilterableArticle { protected $table = 'articles_filterable'; protected $viewFolder = 'package_filterable_articles'; protected $sortOrder = "created_at:desc"; protected $perPage = 25; protected $perPageSettingName = 'kol_statei-v-kataloge-novostei'; protected $sortOptions = [ ['name' => 'title', 'description' => 'По названию','value' => 'title:asc'], ['name' => 'new_first', 'description' => 'от новых к старым','value' => 'created_at:desc'], ['name' => 'old_first', 'description' => 'от старых к новым','value' => 'created_at:asc'], ]; protected $countOptions = [ ['name' => '15','description' => 'По 15', 'value' => 15 ], ['name' => 'all','description' => 'Все', 'value' => 99999999 ], ]; protected $dateField = 'created_at'; protected $relationsInCatalog = []; protected $relationsInArticle = []; public function getUrl() { return route("package_filterable_article", [$this->filterModel->getSlug(),$this->getSlug(), $this->id]); } public function filterModel() { return $this->belongsTo('Tree'); }
Описание дополнительных свойств:, (*24)
Фильтры порядка сортировки Значение: массив $sortOptions['name' => '', 'description' => '','value' => ''], (*25)
protected $sortOptions = [ ['name' => 'title', 'description' => 'По названию','value' => 'title:asc'], ['name' => 'new_first', 'description' => 'от новых к старым','value' => 'created_at:desc'], ['name' => 'old_first', 'description' => 'от старых к новым','value' => 'created_at:asc'], ];
Фильтры количества отображения на странице Значение: массив $countOptions['name' => '', 'description' => '','value' => ''], (*26)
protected $countOptions = [ ['name' => '15','description' => 'По 15', 'value' => 15 ], ['name' => 'all','description' => 'Все', 'value' => 99999999 ], ];
Путь к папке с view templates Значение: название_поля:порядок, по умолчанию: created_at:desc, (*27)
Название поля используемого для фильтрации по дате Значение: строка с названием_поля, по умолчанию: created_at, (*28)
protected $dateField = 'created_at';
Описание дополнительных методов: Метод получения свойства $sortOptions , (*29)
public function getSortOptions(): array;
Метод получения свойства $countOptions , (*30)
public function getCountOptions(): array;
Метод получения свойства $dateField , (*31)
public function getDateField(): string;
Метод-фильтр по связи с другой моделью Значение: строка $relationName = 'filterModel', объект $relationSelected, (*32)
public function scopeFilterRelation($query, $relationName, $relationSelected);
Метод-фильтр статей по дню Значение: целое число $year, целое число $month, целое число $day, (*33)
public function scopeFilterDateDay($query, int $day = 0);
Метод-фильтр статей по месяцу Значение: целое число $year, целое число $month, целое число $day, (*34)
public function scopeFilterDateMonth($query, int $month = 0);
Метод-фильтр статей по году Значение: целое число $year, целое число $month, целое число $day, (*35)
public function scopeFilterDateYear($query, int $year = 0);
Метод-фильтр статей по точной дате Y-M-D Значение: целое число $year, целое число $month, целое число $day, (*36)
public function scopeFilterDateStrict($query, int $year = 0, int $month = 0, int $day = 0)
Метод-фильтр по промежутку дат Значение: Объект Carbon\Carbon $dateFrom, Объект Carbon\Carbon $dateTo, (*37)
public function scopeFilterDateRange($query, Carbon $dateFrom, Carbon $dateTo);
use Vis\Articles\Controllers\AbstractFilterableArticleController; class PackageFilteredArticlesController extends AbstractFilterableArticleController { protected $model = "PackageFilterableArticle"; private function handleArticles() { $page = $this->node; $filters = $this->filter; $filters->addCount() ->addSort() ->addRelation('filterModel', $page) ->addDateRange() ->addDateDay() ->addDateMonth() ->addDateYear() ->addDateStrict() ->handle(); $sortOrder = $filters->getSort()->getSelected(); $perPage = $filters->getCount()->getSelected(); $filter = $filters->getRelation('filterModel')->getSelected() ?: $filters->getRelation('filterModel')->setSelectedToFirstOption()->getSelected(); $dateRange = $filters->getDateRange()->getSelected(); $dateDay = $filters->getDateDay()->getSelected(); $dateMonth = $filters->getDateMonth()->getSelected(); $dateYear = $filters->getDateYear()->getSelected(); $dateStrict = $filters->getDateStrict()->getSelected(); $articles = $this->model->active()->with('filterModel') ->filterRelation('filterModel', $filter) ->filterDateRange($dateRange['date-from'], $dateRange['date-to']) ->filterDateDay($dateDay) ->filterDateMonth($dateMonth) ->filterDateYear($dateYear) ->filterDateStrict($dateStrict['year'], $dateStrict['month'], $dateStrict['day']) ->filterCustomOrder($sortOrder) ->paginate($perPage); $articles->load($this->model->getRelationsInCatalog()); return view("pages." . $this->model->getViewFolder() . ".catalog", compact('page', 'articles', 'filters')); } public function showCatalog() { return $this->handleArticles(); } public function showSubCatalog($catalog) { if (!$this->node) { $this->node = $this->model->filterModel()->where('slug', $catalog)->active()->first(); if (!$this->node) { abort(404); } } return $this->handleArticles(); } public function showArticle($catalog, $slug, $id) { $page = $this->model->where('id', $id)->active()->with('filterModel')->first(); if (!$page) { abort(404); } if ($page->filterModel->getSlug() != $catalog) { return redirect($page->getUrl(), 302); } if ($page->getSlug() != $slug) { return redirect($page->getUrl(), 302); } $page->load($this->model->getRelationsInArticle()); return view("pages." . $this->model->getViewFolder() . ".article", compact('page')); } // end showSingle }
'filterable_catalog' => array( 'action' => 'PackageFilteredArticlesController@showCatalog', 'node_definition' => 'node', 'check' => function() { return true; }, 'title' => 'фильтруемый каталог', ),
Если модель фильтров является деревом, тогда создаем еще шаблон:, (*38)
'filterable_sub_catalog' => array( 'action' => 'PackageFilteredArticlesController@showSubCatalog', 'node_definition' => 'node', 'check' => function() { return true; }, 'title' => 'фильтруемый подкаталог', ),
Если модель фильтров внешняя модель, тогда необходимо создать роут для отслеживания фильтра:, (*39)
Route::get('/test-filterable-articles-catalog-foreign/{catalog}', [ 'as' => 'test-filterable-articles-catalog-foreign', 'uses' => 'PackageFilteredForeignArticlesController@showSubCatalog' ]);
Примечание. Для корректной работы у внешней модели-фильтра необходимо наличие поля slug. Для его автоматического заполнения в definition`е этой модели можно определить, (*40)
handler => 'Vis\Builder\Helpers\SlugHandler'
Route::get('/test-filterable-articles-catalog/{catalog}/{slug}-{id}', [ 'as' => 'package_filterable_article', 'uses' => 'PackageFilteredArticlesController@showArticle' ]);
Создать два шаблона article.blade.php и catalog.blade.php в соответствующей параметру $viewFolder папке. Аналогично нефильтруемым статьям, (*41)
Создать шаблон фильтров, который необходимо будет подключить на странице каталога. Желательно разместить его в views/partials, для того чтобы можно было подключать один шаблон фильтров на всех каталогах. Неполный пример такого шаблона:, (*42)
{{__('Фильтры')}}