PHPackages                             vis/articles\_l5 - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. vis/articles\_l5

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

vis/articles\_l5
================

Articles handler package for L5

1.2.1(8y ago)032proprietaryPHP

Since Jun 6Pushed 8y ago1 watchersCompare

[ Source](https://github.com/KHlushchenko/articles_l5)[ Packagist](https://packagist.org/packages/vis/articles_l5)[ RSS](/packages/vis-articles-l5/feed)WikiDiscussions master Synced 3d ago

READMEChangelogDependenciesVersions (16)Used By (0)

Articles
========

[](#articles)

Пакет для Laravel 5.2+ предназначенный работы с материалами, которые можно предоставить в виде "Каталог статей - Статья".

Разделы

1. [Установка](#%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0)
2. [Спецификация нефильтруемых статей](#%D0%A1%D0%BF%D0%B5%D1%86%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D1%8F-%D0%BD%D0%B5%D1%84%D0%B8%D0%BB%D1%8C%D1%82%D1%80%D1%83%D0%B5%D0%BC%D1%8B%D1%85-%D1%81%D1%82%D0%B0%D1%82%D0%B5%D0%B9)
3. [Спецификация фильтруемых статей](#%D0%A1%D0%BF%D0%B5%D1%86%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D1%8F-%D1%84%D0%B8%D0%BB%D1%8C%D1%82%D1%80%D1%83%D0%B5%D0%BC%D1%8B%D1%85-%D1%81%D1%82%D0%B0%D1%82%D0%B5%D0%B9)

Установка
---------

[](#установка)

Выполняем

```
    composer require "vis/articles_l5":"1.*"
```

Спецификация нефильтруемых статей
---------------------------------

[](#спецификация-нефильтруемых-статей)

Для использования функционала нефильтруемых статей необходимо:

1. Создать модель, которая наследует Vis\\Articles\\Models\\AbstractArticle, которая в свою очередь наследует BaseModel

```
    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]);
        }
    }
```

**Описание свойств:**

Путь к папке с view templates
Если значение 'sub\_folder.package\_articles', тогда view должны лежать в папке /resources/views/pages/sub\_folder/package\_articles
Значение: путь к папке через точки

```
    protected $viewFolder = 'package_articles';
```

Путь к папке с view templates
Значение: название\_поля:порядок, по умолчанию: created\_at:desc

```
    protected $sortOrder = "created_at:desc";
```

Количество статей на странице каталога
Значение: целое число, по умолчанию: 12

```
    protected $perPage = 25;
```

Название опции в CMS, которая содержит количество статей на странице каталога. Если указано, то параметр $perPage игнорируется
Значение: строка с названием опции в CMS

```
    protected $perPageSettingName = 'kol_statei-v-kataloge-novostei';
```

Массив названий дополнительных Eloquent связей, которые необходимо загрузить в каталоге
Необходим для реализации Lazy Eager loading на страницах каталогов Значение: массив $relationsInCatalog\['', ...\]

```
    protected $relationsInCatalog = [];
```

Массив названий дополнительных Eloquent связей, которые необходимо загрузить в статье
Необходим для реализации Lazy Eager loading на страницах статей Значение: массив $relationsInArticle\['', ...\]

```
    protected $relationsInArticle = [];
```

**Описание методов:**

Метод получения свойства $viewFolder

```
    public function getViewFolder(): string;
```

Метод получения свойства $sortOrder

```
    public function getSortOrder(): string;
```

Метод получения свойства $perPage

```
    public function getPerPage(): int;
```

Метод получения свойства $relationsInCatalog

```
    public function getRelationsInCatalog(): array;
```

Метод получения свойства $RelationsInArticle

```
    public function getRelationsInArticle(): array;
```

Метод-фильтр выведения статей по признаку is\_main = 1

```
    public function scopeIsMain($query);
```

Метод-фильтр сортировки статей
Значение: строка $order = 'created\_at:desc'

```
    public function scopeFilterCustomOrder($query, string $order);
```

2. Создать контроллер, который наследует Vis\\Articles\\Controllers\\AbstractSimpleArticleController

```
    use Vis\Articles\Controllers\AbstractSimpleArticleController;

    class PackageArticlesController extends AbstractSimpleArticleController
    {
        protected $model = "PackageArticle";
    }
```

**Описание свойств:**

Название модели, которая будет использоваться
Значение: строка с названием модели

```
     protected $model = "PackageArticle";
```

3. Создать шаблон в \\config\\builder\\tree.php

```
    'articles_catalog' => array(
        'action' => 'PackageArticlesController@showCatalog',
        'node_definition' => 'node',
        'check' => function() {
            return true;
        },
        'title' => 'Каталог статей',
    ),
```

4. Определить именной роут, по которому будут доступны статьи

```
    Route::get('/test-articles-catalog/{slug}-{id}', [
        'as' => 'package_article',
        'uses' => 'PackageArticlesController@showArticle'
    ]);
```

5. Создать два шаблона **article.blade.php** и **catalog.blade.php** в соответствующей параметру $viewFolder папке. Пример article.blade.php

```
@extends('layouts.default')

@section('main')

                {{$page->t('title')}}

@stop
```

Пример catalog.blade.php

```
@extends('layouts.default')

@section('main')

                @foreach($articles as $key => $article)

                                    {{$article->t('title')}}

                @endforeach

@stop
```

Спецификация фильтруемых статей
-------------------------------

[](#спецификация-фильтруемых-статей)

Часть параметров наследуется от нефильтруемой модели, их описание опущено.
Для использования функционала фильтруемых статей необходимо:

1. Создать модель, которая наследует Vis\\Articles\\Models\\AbstractFilterableArticle, которая в свою очередь наследует BaseModel

```
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');
    }
```

**Описание дополнительных свойств:**

Фильтры порядка сортировки
Значение: массив $sortOptions\['name' =&gt; '', 'description' =&gt; '','value' =&gt; ''\]

```
    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' =&gt; '', 'description' =&gt; '','value' =&gt; ''\]

```
    protected $countOptions = [
        ['name' => '15','description' => 'По 15', 'value' => 15 ],
        ['name' => 'all','description' => 'Все', 'value' => 99999999 ],
    ];
```

Путь к папке с view templates
Значение: название\_поля:порядок, по умолчанию: created\_at:desc

Название поля используемого для фильтрации по дате
Значение: строка с названием\_поля, по умолчанию: created\_at

```
    protected $dateField = 'created_at';
```

**Описание дополнительных методов:**Метод получения свойства $sortOptions

```
    public function getSortOptions(): array;
```

Метод получения свойства $countOptions

```
    public function getCountOptions(): array;
```

Метод получения свойства $dateField

```
    public function getDateField(): string;
```

Метод-фильтр по связи с другой моделью
Значение: строка $relationName = 'filterModel', объект $relationSelected

```
    public function scopeFilterRelation($query, $relationName, $relationSelected);
```

Метод-фильтр статей по дню
Значение: целое число $year, целое число $month, целое число $day

```
    public function scopeFilterDateDay($query, int $day = 0);
```

Метод-фильтр статей по месяцу
Значение: целое число $year, целое число $month, целое число $day

```
    public function scopeFilterDateMonth($query, int $month = 0);
```

Метод-фильтр статей по году
Значение: целое число $year, целое число $month, целое число $day

```
    public function scopeFilterDateYear($query, int $year = 0);
```

Метод-фильтр статей по точной дате Y-M-D
Значение: целое число $year, целое число $month, целое число $day

```
    public function scopeFilterDateStrict($query, int $year = 0, int $month = 0, int $day = 0)
```

Метод-фильтр по промежутку дат
Значение: Объект Carbon\\Carbon $dateFrom, Объект Carbon\\Carbon $dateTo

```
    public function scopeFilterDateRange($query, Carbon $dateFrom, Carbon $dateTo);
```

2. Создать контроллер, который наследует Vis\\Articles\\Controllers\\AbstractFilterableArticleController.
    Определить в нём методы ShowSingle, ShowCatalog

```
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

}
```

4. Создать шаблон в \\config\\builder\\tree.php

```
    'filterable_catalog' => array(
        'action' => 'PackageFilteredArticlesController@showCatalog',
        'node_definition' => 'node',
        'check' => function() {
            return true;
        },
        'title' => 'фильтруемый каталог',
    ),
```

Если модель фильтров является деревом, тогда создаем еще шаблон:

```
    'filterable_sub_catalog' => array(
        'action' => 'PackageFilteredArticlesController@showSubCatalog',
        'node_definition' => 'node',
        'check' => function() {
            return true;
        },
        'title' => 'фильтруемый подкаталог',
    ),
```

Если модель фильтров внешняя модель, тогда необходимо создать роут для отслеживания фильтра:

```
    Route::get('/test-filterable-articles-catalog-foreign/{catalog}', [
        'as' => 'test-filterable-articles-catalog-foreign',
        'uses' => 'PackageFilteredForeignArticlesController@showSubCatalog'
    ]);
```

Примечание. Для корректной работы у внешней модели-фильтра необходимо наличие поля slug.
Для его автоматического заполнения в definition`е этой модели можно определить

```
handler => 'Vis\Builder\Helpers\SlugHandler'
```

5. Определить именной роут, по которому будут доступны статьи

```
    Route::get('/test-filterable-articles-catalog/{catalog}/{slug}-{id}', [
        'as' => 'package_filterable_article',
        'uses' => 'PackageFilteredArticlesController@showArticle'
    ]);
```

6. Создать два шаблона **article.blade.php** и **catalog.blade.php** в соответствующей параметру $viewFolder папке.
    Аналогично нефильтруемым статьям
7. Создать шаблон фильтров, который необходимо будет подключить на странице каталога.
    Желательно разместить его в views/partials, для того чтобы можно было подключать один шаблон фильтров на всех каталогах.
    **Неполный** пример такого шаблона:

```

    {{__('Фильтры')}}

                {{__('Все')}}
                    @foreach($filters->getRelation('filterModel')->getOptions() as $filterOption)
                        current() == $filterOption->getUrl() ? 'selected' : ''}}>{{$filterOption->t('title')}}
                    @endforeach

                        @foreach($filters->getSort()->getOptions() as $sortOption)
                            getSort()->getSelected() ?'selected' : ''}}>{{$sortOption['description']}}
                        @endforeach

                        @foreach($filters->getCount()->getOptions() as $optionValue)
                            getCount()->getSelected() ? 'selected' : ''}}>{{$optionValue['description']}}
                        @endforeach

    'use strict';

    var Articles =
        {
            init: function ()
            {
                Articles.initSelects();
            },

            initSelects: function()
            {
                $(".filter-select").change(function() {
                    $(this).parents("form[name='filter_form']").submit();
                });

                $(".filter-url-select").change(function() {
                    location.href = $(this).find("option:selected").val();
                });

            },
        };

    jQuery(document).ready(function() {
        Articles.init();
    });

```

###  Health Score

29

—

LowBetter than 59% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity7

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity71

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~17 days

Recently: every ~38 days

Total

15

Last Release

3016d ago

Major Versions

0.2 → 1.02017-06-20

### Community

Maintainers

![](https://www.gravatar.com/avatar/4ccb895209ea7108142712514fcb896c4bd2d73e196343b566d15585a4d66136?d=identicon)[KGluschenko](/maintainers/KGluschenko)

---

Top Contributors

[![KHlushchenko](https://avatars.githubusercontent.com/u/6852568?v=4)](https://github.com/KHlushchenko "KHlushchenko (25 commits)")

### Embed Badge

![Health badge](/badges/vis-articles-l5/health.svg)

```
[![Health](https://phpackages.com/badges/vis-articles-l5/health.svg)](https://phpackages.com/packages/vis-articles-l5)
```

###  Alternatives

[kwn/number-to-words

Multi language standalone PHP number to words converter. Fully tested, open for extensions and new languages.

4235.0M21](/packages/kwn-number-to-words)[amphp/parallel-functions

Parallel processing made simple.

27910.3M26](/packages/amphp-parallel-functions)[illuminate/redis

The Illuminate Redis package.

8314.0M314](/packages/illuminate-redis)[sylius/fixtures-bundle

Configurable fixtures for Symfony applications.

517.7M12](/packages/sylius-fixtures-bundle)[cartalyst/converter

A framework agnostic measurement conversion and formatting package featuring multiple types of measurements and currency conversion.

88434.4k7](/packages/cartalyst-converter)[symfony/ux-leaflet-map

Symfony UX Map Leaflet Bridge

13146.6k1](/packages/symfony-ux-leaflet-map)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
