Completed
Push — master ( b6c8d3...3080e4 )
by Klochok
11:00
created

IndexAction::getDefaultRules()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 22
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 22
ccs 0
cts 16
cp 0
rs 9.2
cc 1
eloc 16
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
use yii\web\Controller;
21
22
/**
23
 * Class IndexAction.
24
 */
25
class IndexAction extends SearchAction
26
{
27
    /**
28
     * @var string view to render
29
     */
30
    protected $_view;
31
    /**
32
     * @var RepresentationCollectionFinder
33
     */
34
    private $representationCollectionFinder;
35
36
    public function setView($value)
37
    {
38
        $this->_view = $value;
39
    }
40
41
    public function getView()
42
    {
43
        if ($this->_view === null) {
44
            $this->_view = lcfirst(Inflector::id2camel($this->id));
45
        }
46
47
        return $this->_view;
48
    }
49
50
    public function __construct(string $id, Controller $controller, RepresentationCollectionFinder $representationCollectionFinder, array $config = [])
51
    {
52
        parent::__construct($id, $controller, $config);
53
        $this->representationCollectionFinder = $representationCollectionFinder;
54
    }
55
56
    /**
57
     * @var array The map of filters for the [[hipanel\base\FilterStorage|FilterStorage]]
58
     */
59
    public $filterStorageMap = [];
60
61
    protected function getDefaultRules()
62
    {
63
        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...
64
            'html | pjax' => [
65
                'save' => false,
66
                'flash' => false,
67
                'success' => [
68
                    'class' => RenderAction::class,
69
                    'view' => $this->getView(),
70
                    'data' => $this->data,
71
                    'params' => function () {
72
                        return [
73
                            'model' => $this->getSearchModel(),
74
                            'dataProvider' => $this->getDataProvider(),
75
                            'representationCollection' => $this->ensureRepresentationCollection(),
76
                            'uiModel' => $this->getUiModel(),
77
                        ];
78
                    },
79
                ],
80
            ],
81
        ], parent::getDefaultRules());
82
    }
83
84
    public function getUiModel()
85
    {
86
        return $this->controller->indexPageUiOptionsModel;
87
    }
88
89
    /**
90
     * Method tries to guess representation collection class name and create object
91
     * Creates empty collection when no specific representation exists.
92
     *
93
     * @return RepresentationCollection|RepresentationCollectionInterface
94
     */
95
    protected function ensureRepresentationCollection()
96
    {
97
        return $this->representationCollectionFinder->findOrFallback();
98
    }
99
100
    /**
101
     * {@inheritdoc}
102
     */
103
    public function getDataProvider()
104
    {
105
        if ($this->dataProvider === null) {
106
            $request = Yii::$app->request;
107
108
            $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...
109
            $requestFilters = $request->get($formName) ?: $request->get() ?: $request->post();
110
111
            // Don't save filters for ajax requests, because
112
            // the request is probably triggered with select2 or smt similar
113
            if ($request->getIsPjax() || !$request->getIsAjax()) {
114
                $filterStorage = new FilterStorage(['map' => $this->filterStorageMap]);
115
116
                if ($request->getIsPost() && $request->post('clear-filters')) {
117
                    $filterStorage->clearFilters();
118
                }
119
120
                $filterStorage->set($requestFilters);
121
122
                // Apply filters from storage only when request does not contain any data
123
                if (empty($requestFilters)) {
124
                    $requestFilters = $filterStorage->get();
125
                }
126
            }
127
128
            $search = ArrayHelper::merge($this->findOptions, $requestFilters);
129
130
            $this->returnOptions[$this->controller->modelClassName()] = ArrayHelper::merge(
131
                ArrayHelper::remove($search, 'return', []),
132
                ArrayHelper::remove($search, 'rename', [])
133
            );
134
135
            if ($formName !== '') {
136
                $search = [$formName => $search];
137
            }
138
            $this->dataProvider = $this->getSearchModel()->search($search, $this->dataProviderOptions);
139
140
            // Set sort
141
            if ($this->getUiModel()->sort) {
142
                $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...
143
            }
144
145
            // Set pageSize
146
            if ($this->getUiModel()->per_page) {
147
                $this->dataProvider->setPagination(['pageSize' => $this->getUiModel()->per_page]);
148
            }
149
        }
150
151
        return $this->dataProvider;
152
    }
153
}
154