Completed
Push — master ( 3ba3ea...845ba8 )
by Dmitry
08:38
created

IndexAction::ensureRepresentationCollection()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 0
cts 1
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
/**
3
 * HiPanel core package.
4
 *
5
 * @link      https://hipanel.com/
6
 * @package   hipanel-core
7
 * @license   BSD-3-Clause
8
 * @copyright Copyright (c) 2014-2017, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hipanel\actions;
12
13
use hipanel\base\FilterStorage;
14
use hipanel\grid\RepresentationCollectionFinder;
15
use hiqdev\higrid\representations\RepresentationCollection;
16
use hiqdev\higrid\representations\RepresentationCollectionInterface;
17
use Yii;
18
use yii\helpers\ArrayHelper;
19
use yii\helpers\Inflector;
20
21
/**
22
 * Class IndexAction.
23
 */
24
class IndexAction extends SearchAction
25
{
26
    /**
27
     * @var string view to render
28
     */
29
    protected $_view;
30
31
    public function setView($value)
32
    {
33
        $this->_view = $value;
34
    }
35
36
    public function getView()
37
    {
38
        if ($this->_view === null) {
39
            $this->_view = lcfirst(Inflector::id2camel($this->id));
40
        }
41
42
        return $this->_view;
43
    }
44
45
    /**
46
     * @var array The map of filters for the [[hipanel\base\FilterStorage|FilterStorage]]
47
     */
48
    public $filterStorageMap = [];
49
50
    protected function getDefaultRules()
51
    {
52
        return array_merge([
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array_merge(array...nt::getDefaultRules()); (array<string,array>) is incompatible with the return type of the parent method hipanel\actions\SearchAction::getDefaultRules of type array<string,array<strin...rray<string,callable>>>.

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...
53
            'html | pjax' => [
54
                'save' => false,
55
                'flash' => false,
56
                'success' => [
57
                    'class' => RenderAction::class,
58
                    'view' => $this->getView(),
59
                    'data' => $this->data,
60
                    'params' => function () {
61
                        return [
62
                            'model' => $this->getSearchModel(),
63
                            'dataProvider' => $this->getDataProvider(),
64
                            'representationCollection' => $this->ensureRepresentationCollection(),
65
                            'uiModel' => $this->getUiModel(),
66
                        ];
67
                    },
68
                ],
69
            ],
70
        ], parent::getDefaultRules());
71
    }
72
73
    public function getUiModel()
74
    {
75
        return $this->controller->indexPageUiOptionsModel;
76
    }
77
78
    /**
79
     * Method tries to guess representation collection class name and create object
80
     * Creates empty collection when no specific representation exists.
81
     *
82
     * @return RepresentationCollection|RepresentationCollectionInterface
83
     */
84
    protected function ensureRepresentationCollection()
85
    {
86
        return RepresentationCollectionFinder::forCurrentRoute()->findOrFail();
87
    }
88
89
    /**
90
     * {@inheritdoc}
91
     */
92
    public function getDataProvider()
93
    {
94
        if ($this->dataProvider === null) {
95
            $request = Yii::$app->request;
96
97
            $formName = $this->getSearchModel()->formName();
0 ignored issues
show
Bug introduced by
It seems like formName() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
98
            $requestFilters = $request->get($formName) ?: $request->get() ?: $request->post();
99
100
            // Don't save filters for ajax requests, because
101
            // the request is probably triggered with select2 or smt similar
102
            if ($request->getIsPjax() || !$request->getIsAjax()) {
103
                $filterStorage = new FilterStorage(['map' => $this->filterStorageMap]);
104
105
                if ($request->getIsPost() && $request->post('clear-filters')) {
106
                    $filterStorage->clearFilters();
107
                }
108
109
                $filterStorage->set($requestFilters);
110
111
                // Apply filters from storage only when request does not contain any data
112
                if (empty($requestFilters)) {
113
                    $requestFilters = $filterStorage->get();
114
                }
115
            }
116
117
            $search = ArrayHelper::merge($this->findOptions, $requestFilters);
118
119
            $this->returnOptions[$this->controller->modelClassName()] = ArrayHelper::merge(
120
                ArrayHelper::remove($search, 'return', []),
121
                ArrayHelper::remove($search, 'rename', [])
122
            );
123
124
            if ($formName !== '') {
125
                $search = [$formName => $search];
126
            }
127
            $this->dataProvider = $this->getSearchModel()->search($search, $this->dataProviderOptions);
128
129
            // Set sort
130
            if ($this->getUiModel()->sort) {
131
                $this->dataProvider->setSort(['defaultOrder' => [$this->getUiModel()->sortAttribute => $this->getUiModel()->sortDirection]]);
0 ignored issues
show
Documentation introduced by
The property sortAttribute does not exist on object<hipanel\models\IndexPageUiOptions>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Documentation introduced by
The property sortDirection does not exist on object<hipanel\models\IndexPageUiOptions>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
132
            }
133
134
            // Set pageSize
135
            if ($this->getUiModel()->per_page) {
136
                $this->dataProvider->setPagination(['pageSize' => $this->getUiModel()->per_page]);
137
            }
138
        }
139
140
        return $this->dataProvider;
141
    }
142
}
143