Ajde_Crud::_getCustomTemplateBase()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
class Ajde_Crud extends Ajde_Object_Standard
4
{
5
    protected $_model = null;
6
    protected $_collection = null;
7
8
    protected $_fields = null;
9
10
    //protected $_operation = null;
11
    protected $_operation = 'list';
12
13
    protected $_templateData = [];
14
15
    public function __construct($model, $options = [])
16
    {
17
        if ($model instanceof Ajde_Model) {
18
            $this->_model = $model;
19
        } else {
20
            $modelName = $this->toCamelCase($model, true).'Model';
21
            $this->_model = new $modelName();
22
        }
23
        if ($options instanceof Ajde_Crud_Options) {
24
            $options = $options->getArray();
25
        }
26
        $this->setOptions($options);
27
    }
28
29
    public function __toString()
30
    {
31
        try {
32
            $output = $this->output();
33
        } catch (Exception $e) {
34
            $output = Ajde_Exception_Handler::handler($e);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $output is correct as \Ajde_Exception_Handler::handler($e) (which targets Ajde_Exception_Handler::handler()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Documentation introduced by
$e is of type object<Exception>, but the function expects a object<Throwable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
35
        }
36
37
        return (string) $output;
38
    }
39
40
    /**
41
     * @throws Ajde_Exception
42
     *
43
     * @return mixed
44
     */
45
    public function output()
46
    {
47
        $controller = Ajde_Controller::fromRoute(new Ajde_Core_Route('_core/crud:'.$this->getOperation()));
48
        $controller->setCrudInstance($this);
0 ignored issues
show
Documentation Bug introduced by
The method setCrudInstance does not exist on object<Ajde_Controller>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
49
50
        return $controller->invoke();
51
    }
52
53
    public function export($format = 'excel')
54
    {
55
        /* @var $exporter Ajde_Crud_Export_Interface */
56
57
        $exporterClass = 'Ajde_Crud_Export_'.ucfirst($format);
58
        $exporter = new $exporterClass();
59
60
        $table = [];
61
62
        $fieldsToShow = $this->getFieldNames();
63
64
        $headers = [];
65
66
        $this->getCollection()->getView()->setPageSize(9999999999);
0 ignored issues
show
Documentation Bug introduced by
The method setPageSize does not exist on object<Ajde_Collection_View>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
67
68
        $items = $this->getItems();
69
70
        foreach ($fieldsToShow as $fieldName) {
71
72
            // JSON
73
            if ($items->count() && ($first = current($items->items())) && $first->isFieldJson($fieldName)) {
74
                $maxJsonFields = 0;
75
                $useJsonFields = [];
76
                foreach ($items as $model) {
77
                    $jsonFields = (array) @json_decode($model->has($fieldName) ? $model->get($fieldName) : '');
78
                    if (count($jsonFields) > $maxJsonFields) {
79
                        $useJsonFields = array_keys($jsonFields);
80
                        $maxJsonFields = count($jsonFields);
81
                    }
82
                }
83
                foreach ($useJsonFields as $key) {
84
                    $headers[] = $key;
85
                }
86
                // Normal
87
            } else {
88
                $field = $this->getField($fieldName);
89
                $headers[] = $field->getLabel();
90
            }
91
        }
92
93
        $table[] = $headers;
94
95
        foreach ($items as $model) {
96
            /* @var $model Ajde_Model */
97
            $this->fireCrudLoadedOnModel($model);
98
99
            $row = [];
100
101
            foreach ($fieldsToShow as $fieldName) {
102
                $field = $this->getField($fieldName);
103
                $value = $model->has($fieldName) ? $model->get($fieldName) : false;
104
105
                // JSON
106
                if ($model->isFieldJson($fieldName)) {
107
                    foreach (($jsonFields = (array) @json_decode($value)) as $item) {
108
                        $row[] = $item;
109
                    }
110
                    for ($i = 0; $i < ($maxJsonFields - count($jsonFields)); $i++) {
0 ignored issues
show
Bug introduced by
The variable $maxJsonFields does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
111
                        $row[] = '';
112
                    }
113
                } else {
114
                    if ($this->getField($fieldName) instanceof Ajde_Crud_Field_Sort) {
115
                        $row[] = $value;
116
                        // Display function
117
                        //                } elseif ($field->hasFunction() && $field->getFunction()) {
118
                        //                    $displayFunction = $field->getFunction();
119
                        //                    $displayFunctionArgs = $field->hasFunctionArgs() ? $field->getFunctionArgs() : array();
120
                        //                    $funcValue = call_user_func_array(array($model, $displayFunction), $displayFunctionArgs);
121
                        //                    $row[] = $funcValue;
122
                        // Linked Model (not loaded)
123
                    } elseif ($value instanceof Ajde_Model && !$value->hasLoaded()) {
124
                        $row[] = '(not set)';
125
                        // Linked Model
126
                    } elseif ($value instanceof Ajde_Model && $value->hasLoaded()) {
127
                        $row[] = $value->get($value->getDisplayField());
128
                        // Boolean
129
                    } elseif ($field instanceof Ajde_Crud_Field_Boolean) {
130
                        $row[] = $value;
131
                        // File
132
                    } elseif ($this->getField($fieldName) instanceof Ajde_Crud_Field_File) {
133
                        $row[] = config('app.rootUrl').$field->getSaveDir().$value;
0 ignored issues
show
Documentation Bug introduced by
The method getSaveDir does not exist on object<Ajde_Crud_Field_Sort>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
134
                        // Text value
135
                    } else {
136
                        $row[] = strip_tags($value);
137
                    }
138
                }
139
            }
140
141
            $table[] = $row;
142
        }
143
144
        $exporter->prepare($this->getSessionName(), $table);
145
146
        return $exporter;
147
    }
148
149
    /**
150
     * GETTERS & SETTERS.
151
     */
152
153
    /**
154
     * @return string
155
     */
156
    public function getAction()
157
    {
158
        if (!$this->hasAction()) {
0 ignored issues
show
Documentation Bug introduced by
The method hasAction does not exist on object<Ajde_Crud>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
159
            $this->setAction('list');
160
        }
161
162
        return parent::getAction();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Ajde_Object_Standard as the method getAction() does only exist in the following sub-classes of Ajde_Object_Standard: AclController, AdminAclController, AdminCmsController, AdminController, AdminEmailController, AdminFormController, AdminMediaController, AdminMenuController, AdminNodeController, AdminSetupController, AdminShopController, AdminSystemController, AdminTagController, AdminUserController, Ajde_Acl_Controller, Ajde_Api_Controller, Ajde_Controller, Ajde_Core_Route, Ajde_Crud, Ajde_Layout, Ajde_Resource_Local, Ajde_Template, Ajde_User_Controller, Ajde_View, ApiController, ApiV1Controller, FormController, LangController, MainController, MediaController, NodeController, ShopCartController, ShopController, ShopTransactionController, UserController, UserSsoController, _coreComponentController, _coreController, _coreCrudController, _coreDebuggerController. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
163
    }
164
165
    public function setAction($value)
166
    {
167
        if (substr($value, 0, 4) === 'edit' || substr($value, 0, 4) === 'list') {
168
            $this->setOperation(substr($value, 0, 4));
169
        }
170
        parent::setAction($value);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Ajde_Object_Standard as the method setAction() does only exist in the following sub-classes of Ajde_Object_Standard: Ajde_Crud, Ajde_Crud_Options_Edit, Ajde_Layout, Ajde_Template, Ajde_View. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
171
    }
172
173
    public function setOperation($operation)
174
    {
175
        $this->_operation = $operation;
176
    }
177
178
    public function getOperation()
179
    {
180
        //		if (!isset($this->_operation)) {
181
        //			if (Ajde::app()->getRequest()->has('new')) {
182
        //				$this->setOperation('new');
183
        //			} else if (Ajde::app()->getRequest()->has('edit')) {
184
        //				$this->setOperation('edit');
185
        //			} else {
186
        //				$this->setOperation('list');
187
        //			}
188
        //		}
189
        return $this->_operation;
190
    }
191
192
    /**
193
     * OPTIONS.
194
     *
195
     * @param            $name
196
     * @param bool|mixed $default
197
     *
198
     * @return array|bool
199
     */
200
    public function getOption($name, $default = false)
201
    {
202
        $path = explode('.', $name);
203
        $options = $this->getOptions();
204
        foreach ($path as $key) {
205
            if (isset($options[$key])) {
206
                $options = $options[$key];
207
            } else {
208
                return $default;
209
            }
210
        }
211
212
        return $options;
213
    }
214
215
    public function setOption($name, $value)
216
    {
217
        $path = explode('.', $name);
218
        $options = $this->getOptions();
219
        $wc = &$options;
220
        foreach ($path as $key) {
221
            if (!isset($wc[$key])) {
222
                $wc[$key] = [];
223
            }
224
            $wc = &$wc[$key];
225
        }
226
        $wc = $value;
227
        $this->setOptions($options);
228
    }
229
230
    /**
231
     * @return array
232
     */
233
    public function getOptions($key = null)
234
    {
235
        if (isset($key)) {
236
            $options = parent::getOptions();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Ajde_Object_Standard as the method getOptions() does only exist in the following sub-classes of Ajde_Object_Standard: Ajde_Crud. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
237
238
            return issetor($options[$key], []);
239
        } else {
240
            return parent::getOptions();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Ajde_Object_Standard as the method getOptions() does only exist in the following sub-classes of Ajde_Object_Standard: Ajde_Crud. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
241
        }
242
    }
243
244
    public function setOptions($value)
245
    {
246
        parent::setOptions($value);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Ajde_Object_Standard as the method setOptions() does only exist in the following sub-classes of Ajde_Object_Standard: Ajde_Collection_View, Ajde_Crud, Ajde_Crud_Cms_Meta_Decorator, Ajde_Crud_Options_Fields_Field, Ajde_Publisher_Twitter. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
247
    }
248
249
    /**
250
     * MISC.
251
     */
252
    public function setItem($value)
253
    {
254
        parent::setItem($value);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Ajde_Object_Standard as the method setItem() does only exist in the following sub-classes of Ajde_Object_Standard: Ajde_Crud. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
255
    }
256
257
    public function setCustomTemplateModule($value)
258
    {
259
        parent::setCustomTemplateModule($value);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Ajde_Object_Standard as the method setCustomTemplateModule() does only exist in the following sub-classes of Ajde_Object_Standard: Ajde_Crud. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
260
    }
261
262
    public function getCustomTemplateModule()
263
    {
264
        if (parent::hasCustomTemplateModule()) {
0 ignored issues
show
Bug introduced by
The method hasCustomTemplateModule() does not seem to exist on object<Ajde_Object_Standard>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Comprehensibility Bug introduced by
It seems like you call parent on a different method (hasCustomTemplateModule() instead of getCustomTemplateModule()). Are you sure this is correct? If so, you might want to change this to $this->hasCustomTemplateModule().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
265
            return parent::getCustomTemplateModule();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Ajde_Object_Standard as the method getCustomTemplateModule() does only exist in the following sub-classes of Ajde_Object_Standard: Ajde_Crud. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
266
        }
267
268
        return (string) $this->getModel()->getTable();
269
    }
270
271
    public function setEditAction($value)
272
    {
273
        parent::setEditAction($value);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Ajde_Object_Standard as the method setEditAction() does only exist in the following sub-classes of Ajde_Object_Standard: Ajde_Crud. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
274
    }
275
276
    public function getEditAction()
277
    {
278
        if (parent::hasEditAction()) {
0 ignored issues
show
Bug introduced by
The method hasEditAction() does not seem to exist on object<Ajde_Object_Standard>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Comprehensibility Bug introduced by
It seems like you call parent on a different method (hasEditAction() instead of getEditAction()). Are you sure this is correct? If so, you might want to change this to $this->hasEditAction().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
279
            return parent::getEditAction();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Ajde_Object_Standard as the method getEditAction() does only exist in the following sub-classes of Ajde_Object_Standard: Ajde_Crud. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
280
        }
281
282
        return false;
283
    }
284
285
    public function setNewAction($value)
286
    {
287
        parent::setNewAction($value);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Ajde_Object_Standard as the method setNewAction() does only exist in the following sub-classes of Ajde_Object_Standard: Ajde_Crud. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
288
    }
289
290
    public function getNewAction()
291
    {
292
        if (parent::hasNewAction()) {
0 ignored issues
show
Bug introduced by
The method hasNewAction() does not seem to exist on object<Ajde_Object_Standard>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Comprehensibility Bug introduced by
It seems like you call parent on a different method (hasNewAction() instead of getNewAction()). Are you sure this is correct? If so, you might want to change this to $this->hasNewAction().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
293
            return parent::getNewAction();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Ajde_Object_Standard as the method getNewAction() does only exist in the following sub-classes of Ajde_Object_Standard: Ajde_Crud. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
294
        }
295
296
        return false;
297
    }
298
299
    public function setListAction($value)
300
    {
301
        parent::setListAction($value);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Ajde_Object_Standard as the method setListAction() does only exist in the following sub-classes of Ajde_Object_Standard: Ajde_Crud. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
302
    }
303
304
    public function getListAction()
305
    {
306
        if (parent::hasListAction()) {
0 ignored issues
show
Bug introduced by
The method hasListAction() does not seem to exist on object<Ajde_Object_Standard>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Comprehensibility Bug introduced by
It seems like you call parent on a different method (hasListAction() instead of getListAction()). Are you sure this is correct? If so, you might want to change this to $this->hasListAction().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
307
            return parent::getListAction();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Ajde_Object_Standard as the method getListAction() does only exist in the following sub-classes of Ajde_Object_Standard: Ajde_Crud. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
308
        }
309
310
        return false;
311
    }
312
313
    /**
314
     * @return Ajde_Collection
315
     */
316
    public function getCollection()
317
    {
318
        if (!isset($this->_collection)) {
319
            $collectionName = str_replace('Model', '', get_class($this->getModel())).'Collection';
320
            $this->_collection = new $collectionName();
321
        }
322
323
        return $this->_collection;
324
    }
325
326
    /**
327
     * @return Ajde_Model
328
     */
329
    public function getModel()
330
    {
331
        return $this->_model;
332
    }
333
334
    /**
335
     * @return string
336
     */
337
    public function getHash()
338
    {
339
        return spl_object_hash($this);
340
    }
341
342
    /**
343
     * HELPERS.
344
     */
345
    public function loadItem($id = null)
346
    {
347
        $model = $this->getModel();
348
        if (isset($id)) {
349
            $model->loadByPK($id);
350
        }
351
        $this->setItem($model);
352
353
        return $this->getItem();
354
    }
355
356
    /**
357
     * @return Ajde_Model
358
     */
359
    public function getItem()
360
    {
361
        if ($this->isNew()) {
362
            $this->fireCrudLoadedOnModel($this->getModel());
363
364
            return $this->getModel();
365
        }
366
        if (!$this->getModel()->getPK()) {
367
            $model = $this->getModel();
368
            if (!$model->loadByPK($this->getId())) {
0 ignored issues
show
Documentation Bug introduced by
The method getId does not exist on object<Ajde_Crud>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
369
                Ajde_Http_Response::redirectNotFound();
370
            } else {
371
                if (!$model->getAutoloadParents()) {
372
                    $model->loadParents();
373
                }
374
            }
375
            $this->fireCrudLoadedOnModel($this->getModel());
376
        }
377
378
        return $this->getModel();
379
    }
380
381
    public function isNew()
382
    {
383
        return !$this->hasId() || $this->getId() === false || is_null($this->getId());
0 ignored issues
show
Documentation Bug introduced by
The method hasId does not exist on object<Ajde_Crud>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
Documentation Bug introduced by
The method getId does not exist on object<Ajde_Crud>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
384
    }
385
386
    /**
387
     * @return Ajde_Collection
388
     */
389
    public function getItems()
390
    {
391
        $collection = $this->getCollection();
392
393
        // Collection view
394
        if ($collection->hasView()) {
395
            $collection->applyView();
396
        }
397
398
        $collection->load();
399
400
        // TODO: this should be done with JOIN
401
        if ($this->getModel()->getAutoloadParents()) {
402
            $collection->loadParents();
403
        }
404
405
        return $collection;
406
    }
407
408
    public function fireCrudLoadedOnModel($model)
409
    {
410
        Ajde_Event::trigger($model, 'afterCrudLoaded');
411
    }
412
413
    public function getFields()
414
    {
415
        if (!isset($this->_fields)) {
416
            $this->loadFields();
417
        }
418
419
        return $this->_fields;
420
    }
421
422
    public function setReadOnlyForAllFields()
423
    {
424
        foreach ($this->getModel()->getTable()->getFieldNames() as $fieldName) {
425
            $this->setOption('fields.'.$fieldName.'.readonly', true);
426
        }
427
    }
428
429
    public function loadFields()
430
    {
431
        $fields = [];
432
        $allFields = $this->getDeclaredFieldNames();
433
434
        $fieldsArray = $this->getModel()->getTable()->getFieldProperties();
435
        // TODO: changed getItem to getModel, any side effects?
436
        $parents = $this->getModel()->getTable()->getParents();
437
438
        foreach ($allFields as $fieldName) {
439
            $fieldProperties = [];
440
            if (isset($fieldsArray[$fieldName])) {
441
                $fieldProperties = $fieldsArray[$fieldName];
442
            }
443
            $fieldOptions = $this->getFieldOptions($fieldName, $fieldProperties);
444
            $fieldOptions['name'] = $fieldName;
445
            if (in_array($fieldOptions['name'], $parents)) {
446
                $fieldOptions['type'] = 'fk';
447
            }
448
            $field = $this->createField($fieldOptions);
449
            $fields[$fieldName] = $field;
450
        }
451
452
        return $this->_fields = $fields;
453
    }
454
455
    public function createField($fieldOptions)
456
    {
457
        if (!isset($fieldOptions['type'])) {
458
            $fieldOptions['type'] = 'text';
459
        }
460
        $fieldClass = Ajde_Core_ExternalLibs::getClassname('Ajde_Crud_Field_'.ucfirst($fieldOptions['type']));
461
        $field = new $fieldClass($this, $fieldOptions);
462
        if ($this->getOperation() === 'edit') {
463
            if (!$field->hasValue() || $field->hasEmpty('value')) {
464
                if ($this->isNew() && $field->hasNotEmpty('default')) {
465
                    $field->setValue($field->getDefault());
466
                } elseif (!$this->isNew() && $this->getItem()->has($field->getName())) {
467
                    $field->setValue($this->getItem()->get($field->getName()));
468
                } else {
469
                    $field->setValue(false);
470
                }
471
            }
472
        }
473
474
        return $field;
475
    }
476
477
    /**
478
     * @param string $fieldName
479
     *
480
     * @throws Ajde_Exception
481
     *
482
     * @return Ajde_Crud_Field
483
     */
484
    public function getField($fieldName, $strict = true)
485
    {
486
        if (!isset($this->_fields)) {
487
            $this->getFields();
488
        }
489
        if (isset($this->_fields[$fieldName])) {
490
            return $this->_fields[$fieldName];
491
        } else {
492
            if ($strict === true) {
493
                // TODO:
494
                throw new Ajde_Exception($fieldName.' is not a field in '.(string) $this->getModel()->getTable());
495
            } else {
496
                return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Ajde_Crud::getField of type Ajde_Crud_Field.

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...
497
            }
498
        }
499
    }
500
501
    public function getDeclaredFieldNames()
502
    {
503
        $fields = $this->getFieldNames();
504
        foreach ($this->getFieldNamesFromOptions() as $optionField) {
505
            if (!in_array($optionField, $fields)) {
506
                $fields[] = $optionField;
507
            }
508
        }
509
510
        return $fields;
511
    }
512
513
    public function getFieldNamesFromOptions()
514
    {
515
        return array_keys($this->getOptions('fields'));
516
    }
517
518
    public function getFieldOptions($fieldName, $fieldProperties = [])
519
    {
520
        $fieldsOptions = $this->getOptions('fields');
521
        $fieldOptions = issetor($fieldsOptions[$fieldName], []);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $fieldOptions is correct as issetor($fieldsOptions[$fieldName], array()) (which targets issetor()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
522
523
        return array_merge($fieldProperties, $fieldOptions);
524
    }
525
526
    public function getFieldNames()
527
    {
528
        $model = $this->getModel();
529
530
        return $model->getTable()->getFieldNames();
531
    }
532
533
    public function getFieldLabels()
534
    {
535
        $model = $this->getModel();
536
537
        return $model->getTable()->getFieldLabels();
538
    }
539
540
    public function setSessionName($name)
541
    {
542
        parent::setSessionName($name);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Ajde_Object_Standard as the method setSessionName() does only exist in the following sub-classes of Ajde_Object_Standard: Ajde_Crud. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
543
    }
544
545
    public function getSessionName()
546
    {
547
        if (parent::hasSessionName()) {
0 ignored issues
show
Bug introduced by
The method hasSessionName() does not seem to exist on object<Ajde_Object_Standard>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Comprehensibility Bug introduced by
It seems like you call parent on a different method (hasSessionName() instead of getSessionName()). Are you sure this is correct? If so, you might want to change this to $this->hasSessionName().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
548
            return parent::getSessionName();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Ajde_Object_Standard as the method getSessionName() does only exist in the following sub-classes of Ajde_Object_Standard: Ajde_Crud. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
549
        } else {
550
            return (string) $this->getModel()->getTable();
551
        }
552
    }
553
554
    /**
555
     * @param array       $viewParams
556
     * @param bool|string $persist
557
     *
558
     * @return Ajde_Collection_View
559
     */
560
    public function getCollectionView($viewParams = [], $persist = 'auto')
561
    {
562
        if (!$this->getCollection()->hasView()) {
563
            $viewSession = new Ajde_Session('AC.Crud.View');
564
            $sessionName = $this->getSessionName();
565
566
            if ($viewSession->has($sessionName)) {
567
                $crudView = $viewSession->get($sessionName);
568
            } else {
569
                $crudView = new Ajde_Collection_View($sessionName, $this->getOption('list.view', []));
0 ignored issues
show
Bug introduced by
It seems like $this->getOption('list.view', array()) targeting Ajde_Crud::getOption() can also be of type boolean; however, Ajde_Collection_View::__construct() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
570
                $crudView->setColumns($this->getOption('list.show', $this->getFieldNames()));
571
            }
572
573
            // somehow, when altering crudView, the instance in the session gets updated as well, and we don't want that
574
            $crudView = clone $crudView;
575
576
            if (empty($viewParams)) {
577
                $viewParams = Ajde::app()->getRequest()->getParam('view', []);
578
                // if we have params, but no columns, assume a reset
579
                if (!empty($viewParams) && !isset($viewParams['columns'])) {
580
                    $viewParams['columns'] = $this->getOption('list.show', $this->getFieldNames());
581
                }
582
            }
583
            $crudView->setOptions($viewParams);
584
585
            if (($persist == 'auto' && $this->getOperation() == 'list') || $persist === true) {
586
                $viewSession->set($sessionName, $crudView);
587
            }
588
589
            $this->getCollection()->setView($crudView);
590
        }
591
592
        return $this->getCollection()->getView();
593
    }
594
595
    /**
596
     * RENDERING.
597
     */
598
    public function getTemplate()
599
    {
600
        $template = new Ajde_Template(MODULE_DIR.'_core/', 'crud/'.$this->getOperation());
601
        Ajde::app()->getDocument()->autoAddResources($template);
0 ignored issues
show
Bug introduced by
The method autoAddResources() does not exist on Ajde_Document. Did you maybe mean addResource()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
602
        if ($this->getOperation() !== $this->getAction()) {
603
            $template = new Ajde_Template(MODULE_DIR.'_core/', 'crud/'.$this->getAction());
604
        }
605 View Code Duplication
        if ($this->_hasCustomTemplate()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
606
            $base = $this->_getCustomTemplateBase();
607
            $action = $this->_getCustomTemplateAction();
608
            $template = new Ajde_Template($base, $action);
609
        }
610
        $template->assignArray($this->_templateData);
611
612
        return $template;
613
    }
614
615
    public function setTemplateData($array)
616
    {
617
        $this->_templateData = (array) $array;
618
    }
619
620 View Code Duplication
    private function _hasCustomTemplate()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
621
    {
622
        $base = $this->_getCustomTemplateBase();
623
        $action = $this->_getCustomTemplateAction();
624
625
        return Ajde_Template::exist($base, $action) !== false;
626
    }
627
628
    private function _getCustomTemplateBase()
629
    {
630
        return MODULE_DIR.$this->getCustomTemplateModule().DIRECTORY_SEPARATOR;
631
    }
632
633
    private function _getCustomTemplateAction()
634
    {
635
        return 'crud/'.(string) $this->getModel()->getTable().DIRECTORY_SEPARATOR.$this->getAction();
636
    }
637
}
638