• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Cecilapp / Cecil / 26414009793

25 May 2026 06:15PM UTC coverage: 82.54%. First build
26414009793

Pull #2383

github

web-flow
Merge e6b723fa2 into 4904a42be
Pull Request #2383: refactor: asset handling and add renderer extensions

282 of 358 new or added lines in 10 files covered. (78.77%)

3503 of 4244 relevant lines covered (82.54%)

0.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.7
/src/Renderer/Extension/Collection.php
1
<?php
2

3
/**
4
 * This file is part of Cecil.
5
 *
6
 * (c) Arnaud Ligny <arnaud@ligny.fr>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11

12
declare(strict_types=1);
13

14
namespace Cecil\Renderer\Extension;
15

16
use Cecil\Builder;
17
use Cecil\Collection\CollectionInterface;
18
use Cecil\Collection\Page\Collection as PagesCollection;
19
use Cecil\Collection\Page\Page;
20
use Cecil\Collection\Page\Type;
21
use Twig\Extension\AbstractExtension;
22

23
/**
24
 * Collection Twig extension.
25
 *
26
 * Provides filters for filtering and sorting page collections in Twig templates.
27
 */
28
class Collection extends AbstractExtension
29
{
30
    /** @var Builder */
31
    protected $builder;
32

33
    public function __construct(Builder $builder)
34
    {
35
        $this->builder = $builder;
1✔
36
    }
37

38
    public function getFilters(): array
39
    {
40
        return [
1✔
41
            new \Twig\TwigFilter('sort_by_title', [$this, 'sortByTitle']),
1✔
42
            new \Twig\TwigFilter('sort_by_date', [$this, 'sortByDate']),
1✔
43
            new \Twig\TwigFilter('sort_by_weight', [$this, 'sortByWeight']),
1✔
44
            new \Twig\TwigFilter('filter_by', [$this, 'filterBy']),
1✔
45
        ];
1✔
46
    }
47

48
    /**
49
     * Filters by Section.
50
     */
51
    public function filterBySection(PagesCollection $pages, string $section): CollectionInterface
52
    {
NEW
53
        return $this->filterBy($pages, 'section', $section);
×
54
    }
55

56
    /**
57
     * Filters a pages collection by variable's name/value.
58
     */
59
    public function filterBy(PagesCollection $pages, string $variable, string $value): CollectionInterface
60
    {
61
        $filteredPages = $pages->filter(function (Page $page) use ($variable, $value) {
1✔
62
            // is a dedicated getter exists?
63
            $method = 'get' . ucfirst($variable);
1✔
64
            if (method_exists($page, $method) && $page->$method() == $value) {
1✔
NEW
65
                return $page->getType() == Type::PAGE->value && !$page->isVirtual() && true;
×
66
            }
67
            // or a classic variable
68
            if ($page->getVariable($variable) == $value) {
1✔
69
                return $page->getType() == Type::PAGE->value && !$page->isVirtual() && true;
1✔
70
            }
71
        });
1✔
72

73
        return $filteredPages;
1✔
74
    }
75

76
    /**
77
     * Sorts a collection by title.
78
     */
79
    public function sortByTitle(\Traversable $collection): array
80
    {
81
        $sort = \SORT_ASC;
1✔
82

83
        $collection = iterator_to_array($collection);
1✔
84
        array_multisort(array_keys(/** @scrutinizer ignore-type */ $collection), $sort, \SORT_NATURAL | \SORT_FLAG_CASE, $collection);
1✔
85

86
        return $collection;
1✔
87
    }
88

89
    /**
90
     * Sorts a collection by weight.
91
     *
92
     * @param \Traversable|array $collection
93
     */
94
    public function sortByWeight($collection): array
95
    {
96
        $callback = function ($a, $b) {
1✔
97
            if (!isset($a['weight'])) {
1✔
98
                $a['weight'] = 0;
1✔
99
            }
100
            if (!isset($b['weight'])) {
1✔
NEW
101
                $b['weight'] = 0;
×
102
            }
103
            if ($a['weight'] == $b['weight']) {
1✔
104
                return 0;
1✔
105
            }
106

107
            return $a['weight'] < $b['weight'] ? -1 : 1;
1✔
108
        };
1✔
109

110
        if (!\is_array($collection)) {
1✔
111
            $collection = iterator_to_array($collection);
1✔
112
        }
113
        usort(/** @scrutinizer ignore-type */ $collection, $callback);
1✔
114

115
        return $collection;
1✔
116
    }
117

118
    /**
119
     * Sorts by creation date (or 'updated' date): the most recent first.
120
     */
121
    public function sortByDate(\Traversable $collection, string $variable = 'date', bool $descTitle = false): array
122
    {
123
        $callback = function ($a, $b) use ($variable, $descTitle) {
1✔
124
            if ($a[$variable] == $b[$variable]) {
1✔
125
                // if dates are equal and "descTitle" is true
126
                if ($descTitle && (isset($a['title']) && isset($b['title']))) {
1✔
NEW
127
                    return strnatcmp($b['title'], $a['title']);
×
128
                }
129

130
                return 0;
1✔
131
            }
132

133
            return $a[$variable] > $b[$variable] ? -1 : 1;
1✔
134
        };
1✔
135

136
        $collection = iterator_to_array($collection);
1✔
137
        usort(/** @scrutinizer ignore-type */ $collection, $callback);
1✔
138

139
        return $collection;
1✔
140
    }
141
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc