Completed
Push — master ( 8d79bf...db8467 )
by Vitaliy
04:23
created

Grid::setControlContainer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
namespace ViewComponents\Grids;
4
5
use Nayjest\Collection\Extended\ObjectCollectionReadInterface;
6
use RuntimeException;
7
use ViewComponents\Grids\Component\Column;
8
use ViewComponents\ViewComponents\Component\Html\Tag;
9
use ViewComponents\ViewComponents\Component\ManagedList;
10
use ViewComponents\ViewComponents\Component\ManagedList\RecordView;
11
use ViewComponents\ViewComponents\Component\Part;
12
use ViewComponents\Grids\Component\SolidRow;
13
14
/**
15
 * Grid component.
16
 */
17
class Grid extends ManagedList
18
{
19
    const TABLE_ID = 'table';
20
    const TABLE_HEADING_ID = 'table_heading';
21
    const TABLE_FOOTER_ID = 'table_footer';
22
    const TABLE_BODY_ID = 'table_body';
23
    const TITLE_ROW_ID = 'title_row';
24
    const CONTROL_ROW_ID = 'control_row';
25
26
    use GridPartsAccessTrait;
27
28
    /** @var  mixed|null */
29
    protected $currentRow;
30
31
    /**
32
     * Returns column collection (readonly).
33
     *
34
     * @return Column[]|ObjectCollectionReadInterface
35
     */
36
    public function getColumns()
37
    {
38
        return $this->getComponents()->filterByType(Column::class);
39
    }
40
41
    /**
42
     * Returns column with specified id,
43
     * throws exception if grid does not have specified column.
44
     *
45
     * @param string $id
46
     * @return Column
47
     */
48
    public function getColumn($id)
49
    {
50
        $column = $this->getComponent($id);
51
        if (!$column) {
52
            throw new RuntimeException("Column '$id' is not defined.");
53
        }
54
        if (!$column instanceof Column) {
55
            throw new RuntimeException("'$id' is not a column.");
56
        }
57
        return $column;
58
    }
59
60
    /**
61
     * Returns current grid row, used internally for grid rendering.
62
     *
63
     * @internal
64
     * @return mixed
65
     */
66
    public function getCurrentRow()
67
    {
68
        return $this->currentRow;
69
    }
70
71
    /**
72
     * Sets current grid row for rendering, used internally for grid rendering.
73
     *
74
     * @internal
75
     * @param mixed $currentRow
76
     * @return $this
77
     */
78
    public function setCurrentRow($currentRow)
79
    {
80
        $this->currentRow = $currentRow;
81
        return $this;
82
    }
83
84
    protected function makeDataInjector()
85
    {
86
        return [$this, 'setCurrentRow'];
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array($this, 'setCurrentRow'); (array<ViewComponents\Grids\Grid|string>) is incompatible with the return type of the parent method ViewComponents\ViewCompo...dList::makeDataInjector of type Closure.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
87
    }
88
89
    protected function makeDefaultComponents()
90
    {
91
        $components = parent::makeDefaultComponents();
92
        unset($components[ManagedList::RECORD_VIEW_ID]);
93
        $components[ManagedList::CONTROL_CONTAINER_ID]->setDestinationParentId(static::CONTROL_ROW_ID);
94
        $components[ManagedList::LIST_CONTAINER_ID]->setDestinationParentId(static::TABLE_BODY_ID);
95
        $components[ManagedList::SUBMIT_BUTTON_ID]->setDestinationParentId(static::CONTROL_ROW_ID);
96
        return array_merge(
97
            $components,
98
            [
99
                static::TABLE_ID => new Part(
100
                    new Tag('table'),
101
                    static::TABLE_ID,
102
                    static::FORM_ID
103
                ),
104
                static::TABLE_HEADING_ID => new Part(
105
                    new Tag('thead'),
106
                    static::TABLE_HEADING_ID,
107
                    static::TABLE_ID
108
                ),
109
                static::TITLE_ROW_ID => new Part(
110
                    new Tag('tr'),
111
                    static::TITLE_ROW_ID,
112
                    static::TABLE_HEADING_ID
113
                ),
114
                static::CONTROL_ROW_ID => new Part(
115
                    new SolidRow(),
116
                    static::CONTROL_ROW_ID,
117
                    static::TABLE_HEADING_ID
118
                ),
119
                static::TABLE_BODY_ID => new Part(new Tag('tbody'), static::TABLE_BODY_ID, static::TABLE_ID),
120
                static::RECORD_VIEW_ID => new RecordView(new Tag('tr')),
121
                static::TABLE_FOOTER_ID => new Part(new Tag('tfoot'), static::TABLE_FOOTER_ID, static::TABLE_ID),
122
            ]
123
        );
124
    }
125
126
    /**
127
     * Prepares component for rendering.
128
     */
129
    protected function prepare()
130
    {
131
        parent::prepare();
132
        $this->hideControlRowIfEmpty();
133
    }
134
135
    protected function hideControlRowIfEmpty()
136
    {
137
        $row = $this->getControlRow();
138
        $container = $this->getControlContainer();
139
        if (!$row
140
            || !$container
141
            || !$container->children()->isEmpty()
142
            || ($row->children()->count() > 2) // submit button + control_container
143
        ) {
144
            return;
145
        }
146
        /** @var Part $rowPart */
147
        $rowPart = $this->getComponent(static::CONTROL_ROW_ID, false);
148
        $rowPart->setView(null);
149
    }
150
}
151