Completed
Push — master ( a4fdfe...a232d7 )
by Joram van den
04:04
created

NodeModel::featuredImage()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 0
loc 14
rs 9.2
cc 4
eloc 7
nc 4
nop 1
1
<?php
2
3
/**
4
 * @property bool ignoreAccessControl
5
 */
6
class NodeModel extends Ajde_Model_With_AclI18nRevision
7
{
8
    protected $_autoloadParents = false;
9
    protected $_displayField    = 'title';
10
    protected $_hasMeta         = true;
11
12
    protected $_shadowModel;
13
14
    protected $_ignoreFieldInRevision        = ['updated', 'added', 'level', 'sort', 'lang_root'];
15
    protected $_ignoreFieldInRevisionIfEmpty = ['slug'];
16
17
    public static $_parentAclCache = [];
18
19
    public function __construct()
20
    {
21
        parent::__construct();
22
        $this->registerEvents();
23
    }
24
25
    /**
26
     *
27
     * @param int $id
28
     * @return NodeModel|boolean
29
     */
30
    public static function fromPk($id)
31
    {
32
        $node = new self();
33
        if ($node->loadByPK($id)) {
34
            return $node;
35
        }
36
37
        return false;
38
    }
39
40
    /**
41
     *
42
     * @param $slug
43
     * @return bool|NodeModel
44
     */
45
    public static function fromSlug($slug)
46
    {
47
        $node = new self();
48
        if ($node->loadBySlug($slug)) {
49
            return $node;
50
        }
51
52
        return false;
53
    }
54
55
    public function __wakeup()
56
    {
57
        parent::__wakeup();
58
        $this->registerEvents();
59
    }
60
61
    public function registerEvents()
62
    {
63
        if (!Ajde_Event::has($this, 'afterCrudSave', 'postCrudSave')) {
64
            Ajde_Event::register($this, 'beforeCrudSave', 'preCrudSave');
65
            Ajde_Event::register($this, 'afterCrudSave', 'postCrudSave');
66
        }
67
    }
68
69
    public function beforeValidate()
70
    {
71
        // required fields
72
        $nodetype = $this->getNodetype();
73
        if ($nodetype->get('required_subtitle')) {
74
            $this->addValidator('subtitle', new Ajde_Model_Validator_Required());
75
        }
76
        if ($nodetype->get('required_content')) {
77
            $this->addValidator('content', new Ajde_Model_Validator_Required());
78
        }
79
        if ($nodetype->get('required_summary')) {
80
            $this->addValidator('summary', new Ajde_Model_Validator_Required());
81
        }
82
        if ($nodetype->get('required_media')) {
83
            $this->addValidator('media', new Ajde_Model_Validator_Required());
84
        }
85
        if ($nodetype->get('required_tag')) {
86
            $validator = new Ajde_Model_Validator_HasChildren();
87
            $validator->setReferenceOptions('node_tag', 'node', 'tag');
88
            $this->addValidator('tag', $validator);
89
        }
90
        if ($nodetype->get('required_additional_media')) {
91
            $validator = new Ajde_Model_Validator_HasChildren();
92
            $validator->setReferenceOptions('node_media', 'node', 'media');
93
            $this->addValidator('additional_media', $validator);
94
        }
95
        if ($nodetype->get('required_children')) {
96
            $this->addValidator('parent', new Ajde_Model_Validator_Required());
97
        }
98
        if ($nodetype->get('required_content')) {
99
            $this->addValidator('content', new Ajde_Model_Validator_Required());
100
        }
101
        if ($nodetype->get('required_related_nodes')) {
102
            $validator = new Ajde_Model_Validator_HasChildren();
103
            $validator->setReferenceOptions('node_related', 'node', 'related node');
104
            $this->addValidator('related_nodes', $validator);
105
        }
106
107
        // slug
108
        $this->addValidator('slug', new Ajde_Model_Validator_Unique());
109
110
        return true;
111
    }
112
113
    public function getAclParam()
114
    {
115
        return ($this->has('nodetype') ? (string)$this->get('nodetype') : '');
116
    }
117
118
    public function validateOwner($uid, $gid)
0 ignored issues
show
Unused Code introduced by
The parameter $gid is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
119
    {
120
        return ((string)$this->get('user')) == $uid;
121
    }
122
123
    public function validateParent($uid, $gid)
0 ignored issues
show
Unused Code introduced by
The parameter $gid is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
124
    {
125
        $rootId = $this->getRoot(false);
126
        if (isset(self::$_parentAclCache[$rootId])) {
127
            $users = self::$_parentAclCache[$rootId];
128
        } else {
129
            $root                      = new self();
130
            $root->ignoreAccessControl = true;
131
            $root->loadByPK($rootId);
132
            $users                          = $root->findChildUsersAsUidArray();
133
            self::$_parentAclCache[$rootId] = $users;
134
        }
135
136
        return in_array($uid, $users);
137
    }
138
139 View Code Duplication
    public function findChildUsers()
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...
140
    {
141
        $collection = new UserCollection();
142
        $collection->addFilter(new Ajde_Filter_Join('user_node', 'user_node.user', 'user.id'));
143
        $collection->addFilter(new Ajde_Filter_Where('user_node.node', Ajde_Filter::FILTER_EQUALS, $this->getPK()));
144
145
        return $collection;
146
    }
147
148
    public function findChildUsersAsUidArray()
149
    {
150
        $users = $this->findChildUsers();
151
        $ids   = [];
152
        foreach ($users as $user) {
153
            $ids[] = $user->_data['id'];
154
        }
155
156
        return $ids;
157
    }
158
159
    /**
160
     * DISPLAY FUNCTIONS
161
     */
162
163
    public function getPublishData()
164
    {
165
        if ($return = $this->shadowCall('getPublishData')) {
166
            return $return;
167
        }
168
169
        return [
170
            'title'   => $this->getTitle(),
0 ignored issues
show
Documentation Bug introduced by
The method getTitle does not exist on object<NodeModel>? 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...
171
            'message' => $this->getSummary(),
0 ignored issues
show
Documentation Bug introduced by
The method getSummary does not exist on object<NodeModel>? 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...
172
            'image'   => $this->getMediaAbsoluteUrl(),
173
            'url'     => $this->getUrl(false)
174
        ];
175
    }
176
177
    public function getPublishRecipients()
178
    {
179
        if ($return = $this->shadowCall('getPublishRecipients')) {
180
            return $return;
181
        }
182
        $users     = new UserCollection();
183
        $addresses = [];
184
        foreach ($users as $user) {
185
            /* @var $user UserModel */
186
            $addresses[] = $user->getEmail();
187
        }
188
189
        return $addresses;
190
    }
191
192 View Code Duplication
    public function displayPanel()
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...
193
    {
194
        $nodetype   = (string)$this->get('nodetype');
0 ignored issues
show
Unused Code introduced by
$nodetype is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
195
        $controller = Ajde_Controller::fromRoute(new Ajde_Core_Route('admin/node:panel'));
196
        $controller->setItem($this);
0 ignored issues
show
Documentation Bug introduced by
The method setItem 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...
197
198
        return $controller->invoke();
199
    }
200
201
    public function displayTreeName()
202
    {
203
        $nodetype = $this->has('nodetype_name') ? $this->get('nodetype_name') : $this->getNodetype()->displayField();
204
        $icon     = $this->has('nodetype_icon') ? $this->get('nodetype_icon') : $this->getNodetype()->getIcon();
0 ignored issues
show
Documentation Bug introduced by
The method getIcon does not exist on object<NodetypeModel>? 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...
205
        $ret      = str_repeat('<span class="tree-spacer"></span>', max(0, $this->get('level') - 1));
206
        if ($this->get('level') > 0) {
207
            $ret = $ret . '<span class="tree-spacer last"></span>';
208
        }
209
        //$ret .= '<span class="badge">'. strtolower($nodetype) . '</span>';
210
        $ret .= '<span class="badge-icon" title="' . _e($nodetype) . '"><i class="' . $icon . '"></i></span>';
211
        $ret .= ' <span class="title">' . _c($this->title) . '</span>';
0 ignored issues
show
Documentation introduced by
The property title does not exist on object<NodeModel>. 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...
212
213
        return $ret;
214
    }
215
216
    public function displayParentName()
217
    {
218
        $ret      = '';
219
        $parentId = $this->has('parent') ? $this->getParent() : false;
220
        if ($parentId) {
221
            $parent                      = new self();
222
            $parent->ignoreAccessControl = true;
223
            $parent->loadByPK($parentId);
224
            $ret .= '<span class="badge">' . strtolower($parent->getTitle()) . '</span>';
0 ignored issues
show
Documentation Bug introduced by
The method getTitle does not exist on object<NodeModel>? 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...
225
        }
226
        $ret .= ' <span class="title">' . _c($this->title) . '</span>';
0 ignored issues
show
Documentation introduced by
The property title does not exist on object<NodeModel>. 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...
227
228
        return $ret;
229
    }
230
231
    public function displayRootName()
232
    {
233
        $ret  = '';
234
        $root = $this->findRootNoAccessChecks();
235
        if ($root) {
236
            $ret .= '<span class="badge">' . strtolower($root->getTitle()) . '</span>';
0 ignored issues
show
Documentation Bug introduced by
The method getTitle does not exist on object<NodeModel>? 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...
237
        }
238
        $ret .= ' <span class="title">' . _c($this->title) . '</span>';
0 ignored issues
show
Documentation introduced by
The property title does not exist on object<NodeModel>. 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...
239
240
        return $ret;
241
    }
242
243 View Code Duplication
    public function displayAgo()
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...
244
    {
245
        $timestamp = new DateTime($this->get('updated'));
246
        $timestamp = $timestamp->format('U');
247
248
        return Ajde_Component_String::time2str($timestamp);
249
    }
250
251
    public function displayPublished()
252
    {
253
        if ($this->getNodetype()->get('published')) {
254
            if (!$this->get('published')) {
255
                return "<i class='icon-remove' title='No' />";
256
            } else {
257
                if (($start = $this->get('published_start')) &&
258
                    strtotime($start) > time()
259
                ) {
260
                    return "<i class='icon-time' title='Queued' />";
261 View Code Duplication
                } else {
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...
262
                    if (($end = $this->get('published_end')) &&
263
                        strtotime($end) < time()
264
                    ) {
265
                        return "<i class='icon-remove' title='Expired' />";
266
                    } else {
267
                        return "<i class='icon-ok' title='Yes' />";
268
                    }
269
                }
270
            }
271
        } else {
272
            return "";
273
        }
274
    }
275
276 View Code Duplication
    public function displayLang()
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...
277
    {
278
        Ajde::app()->getDocument()->getLayout()->getParser()->getHelper()->requireCssPublic('core/flags.css');
279
280
        $lang        = Ajde_Lang::getInstance();
281
        $currentLang = $this->get('lang');
282
        if ($currentLang) {
283
            $image = '<img src="" class="flag flag-' . strtolower(substr($currentLang, 3,
284
                    2)) . '" alt="' . $currentLang . '" />';
285
286
            return $image . $lang->getNiceName($currentLang);
287
        }
288
289
        return '';
290
    }
291
292
    public function rowClass()
293
    {
294
        $class = strtolower($this->getNodetype()->getName());
0 ignored issues
show
Documentation Bug introduced by
The method getName does not exist on object<NodetypeModel>? 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...
295
        if ($this->has('status')) {
296
            $class .= ' ' . strtolower($this->get('status'));
297
        }
298
299
        return $class;
300
    }
301
302
    public function editRouteChild()
303
    {
304
        $childtype = '';
305
        if ($this->hasLoaded()) {
306
            $childtype = $this->getNodetype()->get('child_type');
307
        }
308
309
        return 'admin/node:view.crud?view[filter][nodetype]=' . $childtype;
310
    }
311
312
    public function listRouteParent()
313
    {
314
        $parenttype = '';
315
        if ($this->hasLoaded()) {
316
            $parenttype = $this->getNodetype()->get('parent_type');
317
        }
318
319
        return 'admin/node:view.crud?view[filter][nodetype]=' . $parenttype;
320
    }
321
322
    public function addChildButton()
323
    {
324
        if ($this->hasLoaded() && $childtype = $this->getNodetype()->get('child_type')) {
325
            $this->getNodetype()->loadParent('child_type');
326
327
            return '<i class="icon-plus icon-white" data-nodetype="' . $childtype . '"></i><span class="text-slide"> ' . strtolower($this->getNodetype()->get('child_type')->getName()) . '</span>';
328
        }
329
        if ($this->hasLoaded() && $childtype = $this->getNodetype()->get('children')) {
330
            return '<i class="icon-plus icon-white"></i>';
331
        }
332
333
        return false;
334
    }
335
336
    /**
337
     * BEFORE / AFTER FUNCTIONS
338
     */
339
340
    public function afterSort()
341
    {
342
        $this->sortTree('NodeCollection');
343
    }
344
345
    public function preCrudSave(Ajde_Controller $controller, Ajde_Crud $crud)
0 ignored issues
show
Unused Code introduced by
The parameter $controller is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $crud is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
346
    {
347
        $this->updateRoot();
348
    }
349
350
    public function postCrudSave(Ajde_Controller $controller, Ajde_Crud $crud)
0 ignored issues
show
Unused Code introduced by
The parameter $controller is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $crud is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
351
    {
352
        // Update sort
353
        $this->sortTree('NodeCollection');
354
    }
355
356
    public function beforeDelete()
357
    {
358
        $this->shadowCall('beforeDelete');
359
    }
360
361
    public function beforeSave()
362
    {
363
        // filter slug
364
        $this->slug = $this->_sluggify($this->slug);
0 ignored issues
show
Documentation introduced by
The property slug does not exist on object<NodeModel>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write 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.");
        }
    }

}

Since the property has write access only, you can use the @property-write 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 slug does not exist on object<NodeModel>. 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...
365
366
        if (empty($this->slug)) {
0 ignored issues
show
Documentation introduced by
The property slug does not exist on object<NodeModel>. 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...
367
            $this->slug = new Ajde_Db_Function('slug');
0 ignored issues
show
Documentation introduced by
The property slug does not exist on object<NodeModel>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write 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.");
        }
    }

}

Since the property has write access only, you can use the @property-write 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...
368
        }
369
370
        $this->shadowCall('beforeSave');
371
    }
372
373
    public function beforeInsert()
374
    {
375
        // Added
376
        $this->added = new Ajde_Db_Function("NOW()");
0 ignored issues
show
Documentation introduced by
The property added does not exist on object<NodeModel>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write 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.");
        }
    }

}

Since the property has write access only, you can use the @property-write 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...
377
378
        // Sort
379
        //		$collection = new NodeCollection();
380
        //		$min = 999;
381
        //		foreach($collection as $item) {
382
        //			$min = ($item->sort < $min) ? $item->sort : $min;
383
        //		}
384
        //		$this->sort = $min - 1;
385
386
        // Slug
387
        $this->slug = $this->_makeSlug();
0 ignored issues
show
Documentation introduced by
The property slug does not exist on object<NodeModel>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write 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.");
        }
    }

}

Since the property has write access only, you can use the @property-write 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...
388
389
        $this->shadowCall('beforeInsert');
390
    }
391
392
    public function afterInsert()
393
    {
394
        $this->shadowCall('afterInsert');
395
    }
396
397
    public function afterSave()
398
    {
399
        $this->shadowCall('afterSave');
400
    }
401
402
    /**
403
     * Shadow model
404
     */
405
406
    public function getShadowModel()
407
    {
408
        if (!isset($this->_shadowModel)) {
409
            $modelName = ucfirst($this->getNodetype()->getName()) . 'NodeModel';
0 ignored issues
show
Documentation Bug introduced by
The method getName does not exist on object<NodetypeModel>? 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...
410
            if (class_exists($modelName)) {
411
                $this->_shadowModel = new $modelName();
412
            } else {
413
                $this->_shadowModel = false;
414
            }
415
        }
416
417
        $this->shadowCopy();
418
419
        return $this->_shadowModel;
420
    }
421
422
    public function shadowCopy()
423
    {
424
        if ($this->_shadowModel) {
425
            $this->_shadowModel->populate($this->values());
426
            $this->_shadowModel->populateMeta($this->_metaValues);
427
        }
428
    }
429
430
    public function shadowCall($method)
431
    {
432
        $shadowModel = $this->getShadowModel();
433
        if ($shadowModel) {
434
            try {
435
                $rfmethod = new ReflectionMethod($shadowModel, $method);
436
                if ($rfmethod->getDeclaringClass()->getName() == get_class($shadowModel)) {
0 ignored issues
show
introduced by
Consider using $rfmethod->class. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
437
                    return $shadowModel->$method();
438
                }
439
            } catch (Exception $e) {
440
                return false;
441
            }
442
        }
443
444
        return false;
445
    }
446
447
    /**
448
     * SLUG FUNCTIONS
449
     */
450
451
    public function getSlug()
452
    {
453
        if (!$this->hasSlug()) {
0 ignored issues
show
Documentation Bug introduced by
The method hasSlug does not exist on object<NodeModel>? 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...
454
            $this->slug = $this->_makeSlug();
0 ignored issues
show
Documentation introduced by
The property slug does not exist on object<NodeModel>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write 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.");
        }
    }

}

Since the property has write access only, you can use the @property-write 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...
455
        }
456
457
        return $this->slug;
0 ignored issues
show
Documentation introduced by
The property slug does not exist on object<NodeModel>. 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...
458
    }
459
460 View Code Duplication
    private function _makeSlug()
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...
461
    {
462
        $name = $this->title;
0 ignored issues
show
Documentation introduced by
The property title does not exist on object<NodeModel>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write 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.");
        }
    }

}

Since the property has write access only, you can use the @property-write 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...
463
464
        $ghost     = new self();
465
        $uniqifier = 0;
466
467
        do {
468
            $ghost->reset();
469
            $slug = $this->_sluggify($name);
470
            $slug = $slug . ($uniqifier > 0 ? '-' . $uniqifier : '');
471
            $ghost->loadBySlug($slug);
472
            $uniqifier++;
473
            if ($uniqifier >= 100) {
474
                throw new Ajde_Controller_Exception('Max recursion depth reached for setting slug');
475
            }
476
        } while ($ghost->hasLoaded());
477
478
        return $slug;
479
    }
480
481
    /**
482
     * @param bool $breadcrumb
0 ignored issues
show
Bug introduced by
There is no parameter named $breadcrumb. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
483
     * @deprecated use $this->slug = $this->_makeSlug();
484
     */
485
    private function _setSlug()
486
    {
487
        $this->slug = $this->_makeSlug();
0 ignored issues
show
Documentation introduced by
The property slug does not exist on object<NodeModel>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write 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.");
        }
    }

}

Since the property has write access only, you can use the @property-write 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...
488
    }
489
490 View Code Duplication
    private function _sluggify($name)
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...
491
    {
492
        // @see http://stackoverflow.com/a/5240834
493
        $slug = iconv('UTF-8', 'ASCII//TRANSLIT', $name);
0 ignored issues
show
Unused Code introduced by
$slug is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
494
        $slug = preg_replace("/[^a-zA-Z0-9\/_| -]/", '', $name);
495
        $slug = strtolower(trim($slug, '-'));
496
        $slug = preg_replace("/[\/_| -]+/", '-', $slug);
497
498
        return $slug;
499
    }
500
501
    public function loadBySlug($slug, $publishedCheck = false)
502
    {
503
        $this->loadByField('slug', $slug);
504
        if ($publishedCheck) {
505
            $this->filterPublished();
506
        }
507
508
        return $this->hasLoaded();
509
    }
510
511
    /**
512
     * PUBLISHED FUNCTIONS
513
     */
514
515
    public function checkPublished()
516
    {
517
        if ($this->getNodetype()->get('published')) {
518
            if (!$this->get('published')) {
519
                return false;
520
            }
521
            if (($start = $this->get('published_start')) &&
522
                strtotime($start) > time()
523
            ) {
524
                return false;
525
            }
526 View Code Duplication
            if (($end = $this->get('published_end')) &&
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...
527
                strtotime($end) < time()
528
            ) {
529
                return false;
530
            }
531
        }
532
533
        return true;
534
    }
535
536
    public function filterPublished()
537
    {
538
        if (false === $this->checkPublished()) {
539
            $this->reset();
540
        }
541
    }
542
543 View Code Duplication
    protected function _load($sql, $values, $populate = true)
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...
544
    {
545
        $return = parent::_load($sql, $values, $populate);
546
        if ($return && Ajde::app()->getRequest()->getParam('filterPublished', false) == true) {
547
            $this->filterPublished();
548
        }
549
550
        return $return;
551
    }
552
553
    /**
554
     * TREE FUNCTIONS
555
     */
556
557
    /**
558
     *
559
     * @param boolean $returnModel
560
     * @return NodeModel|boolean
561
     */
562
    public function getRoot($returnModel = true)
563
    {
564
        if ($this->hasNotEmpty('root')) {
565
            if ($returnModel) {
566
                $this->loadParent('root');
567
568
                return parent::getRoot();
0 ignored issues
show
Bug introduced by
The method getRoot() does not exist on Ajde_Model_With_AclI18nRevision. Did you maybe mean getRootLang()?

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...
569
            } else {
570
                return (string)parent::getRoot();
0 ignored issues
show
Bug introduced by
The method getRoot() does not exist on Ajde_Model_With_AclI18nRevision. Did you maybe mean getRootLang()?

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...
Bug Best Practice introduced by
The return type of return (string) parent::getRoot(); (string) is incompatible with the return type documented by NodeModel::getRoot of type NodeModel|boolean.

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...
571
            }
572
        } else {
573
            if ($returnModel) {
574
                return $this;
575
            } else {
576
                return (string)$this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return (string) $this; (string) is incompatible with the return type documented by NodeModel::getRoot of type NodeModel|boolean.

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...
577
            }
578
        }
579
    }
580
581
    /**
582
     *
583
     * @return NodeModel|boolean
584
     */
585
    public function findRootNoAccessChecks($load = true)
586
    {
587
        return $this->findRoot(false, $load);
588
    }
589
590
    /**
591
     *
592
     * @param bool $accessChecks
593
     * @param bool $load
594
     * @return bool|NodeModel
595
     */
596
    public function findRoot($accessChecks = true, $load = true)
597
    {
598
        $node = new self();
599
        if ($accessChecks === false) {
600
            $node->ignoreAccessControl = true;
601
        }
602
        $lastParent = $this->getPK();
603
        $parent     = $this->has('parent') ? $this->getParent(false) : false;
604
        while ($parent) {
605
            $lastParent = $parent;
606
            $node->loadByPK($parent);
607
            $parent = $node->has('parent') ? $node->getParent(false) : false;
608
        }
609
        if ($lastParent === $this->getPK()) {
610
            return $this;
611
        } else {
612
            if ($lastParent) {
613
                if ($load) {
614
                    $root = new self();
615
                    if (!$accessChecks) {
616
                        $root->ignoreAccessControl = true;
617
                    }
618
                    $root->loadByPK($lastParent);
619
620
                    return $root;
621
                } else {
622
                    return (string)$lastParent;
623
                }
624
            }
625
        }
626
627
        // TODO: we can never reach this?
628
        return false;
629
    }
630
631
    public function updateRoot()
632
    {
633
        // Update root
634
        $root = $this->findRootNoAccessChecks(false);
635
        $this->setRoot(($this->getPK() != $root) ? $root : null);
0 ignored issues
show
Documentation Bug introduced by
The method setRoot does not exist on object<NodeModel>? 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...
636
637
        // go through all direct descendants
638
        $collection                      = new NodeCollection();
639
        $collection->ignoreAccessControl = true;
640
        $collection->autoRedirect        = false;
641
        $collection->filterChildrenOfParent($root);
642
        foreach ($collection as $child) {
643
            $child->setRoot(($child->getPK() != $root) ? $root : null);
644
            $child->save();
645
        }
646
    }
647
648
    /**
649
     *
650
     * @return NodeCollection
651
     */
652 View Code Duplication
    public function getRelatedNodes()
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...
653
    {
654
        $collection = new NodeCollection();
655
        $collection->addFilter(new Ajde_Filter_Join('node_related', 'node.id', 'related'));
656
        $collection->addFilter(new Ajde_Filter_Where('node_related.node', Ajde_Filter::FILTER_EQUALS, $this->getPK()));
657
        $collection->orderBy('node_related.sort');
658
659
        return $collection;
660
    }
661
662
    /**
663
     *
664
     * @return MediaCollection
665
     */
666
    public function getAdditionalMedia()
667
    {
668
        $collection = new MediaCollection();
669
        $collection->addFilter(new Ajde_Filter_Join('node_media', 'node_media.media', 'media.id'));
670
        $collection->addFilter(new Ajde_Filter_Join('node', 'node.id', 'node_media.node'));
671
        $collection->addFilter(new Ajde_Filter_Where('node_media.node', Ajde_Filter::FILTER_EQUALS, $this->getPK()));
672
        $collection->orderBy('node_media.sort');
673
674
        return $collection;
675
    }
676
677
    /**
678
     *
679
     * @return NodeModel
680
     */
681
    public function getParent($load = true)
682
    {
683
        if ($load) {
684
            $this->loadParent('parent');
685
686
            return $this->get('parent');
687
        }
688
689
        return (string)$this->get('parent');
0 ignored issues
show
Bug Best Practice introduced by
The return type of return (string) $this->get('parent'); (string) is incompatible with the return type documented by NodeModel::getParent of type NodeModel.

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...
690
    }
691
692
    /**
693
     *
694
     * @return NodeCollection
695
     */
696
    public function getChildren()
697
    {
698
        $collection = new NodeCollection();
699
        $collection->filterByParent($this->getPK());
700
        $collection->orderBy('sort');
701
702
        return $collection;
703
    }
704
705
    public function getNext($loop = true)
706
    {
707
        return $this->getSibling('next', $loop);
708
    }
709
710
    public function getPrev($loop = true)
711
    {
712
        return $this->getSibling('prev', $loop);
713
    }
714
715
    public function getSibling($dir, $loop = true)
716
    {
717
        if ($dir == 'next') {
718
            $filter = Ajde_Filter::FILTER_GREATER;
719
            $order  = Ajde_Query::ORDER_ASC;
720
        } else {
721
            $filter = Ajde_Filter::FILTER_LESS;
722
            $order  = Ajde_Query::ORDER_DESC;
723
        }
724
725
        if ($this->has('parent')) {
726
            $siblings = new NodeCollection();
727
            $siblings->addFilter(new Ajde_Filter_Where('sort', $filter, $this->sort));
0 ignored issues
show
Documentation introduced by
The property sort does not exist on object<NodeModel>. 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...
728
            $siblings->addFilter(new Ajde_Filter_Where('parent', Ajde_Filter::FILTER_EQUALS,
729
                (string)$this->get('parent')));
730
            $siblings->orderBy('sort', $order);
731
            $siblings->limit(1);
732
            if ($siblings->count()) {
733
                return $siblings->current();
734
            }
735
        }
736
        // Not found, loop?
737
        if ($loop === true) {
738
            $siblings->reset();
0 ignored issues
show
Bug introduced by
The variable $siblings 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...
739
            $siblings->addFilter(new Ajde_Filter_Where('parent', Ajde_Filter::FILTER_EQUALS,
740
                (string)$this->get('parent')));
741
            $siblings->orderBy('sort', $order);
742
            $siblings->limit(1);
743
            if ($siblings->count()) {
744
                return $siblings->current();
745
            }
746
        }
747
748
        // No sibling
749
        return false;
750
    }
751
752
    /***
753
     * GETTERS
754
     */
755
756
    /**
757
     * @return bool|string
758
     * @deprecated
759
     */
760
    public function getPath()
761
    {
762
        return $this->getUrl();
763
    }
764
765
    public function getUrl($relative = true)
766
    {
767
        if ($this->getPK()) {
768
            $url = $this->getFullUrl();
769
770
            return $relative ? $url : Config::get('site_root') . $url;
771
        }
772
773
        return false;
774
    }
775
776
    public function getFullUrl()
777
    {
778
        if (($parent = $this->getParent()) && $parent->hasLoaded()) {
779
            return $parent->getFullUrl() . '/' . $this->getSlug();
780
        }
781
782
        return $this->getSlug();
783
    }
784
785
    /**
786
     *
787
     * @return NodetypeModel
788
     */
789
    public function getNodetype()
790
    {
791
        $this->loadParent('nodetype');
792
793
        return parent::getNodetype();
794
    }
795
796
    /**
797
     *
798
     * @return MediaModel
799
     */
800
    public function getMedia()
801
    {
802
        $this->loadParent('media');
803
804
        return parent::getMedia();
0 ignored issues
show
Bug introduced by
The method getMedia() does not exist on Ajde_Model_With_AclI18nRevision. Did you maybe mean getMediaModelFromMetaValue()?

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...
805
    }
806
807
    public function getMediaTag(
808
        $width = null,
809
        $height = null,
810
        $crop = null,
811
        $class = null,
812
        $attributes = [],
813
        $lazy = false
814
    ) {
815
        if ($this->hasNotEmpty('media')) {
816
            return $this->getMedia()->getTag($width, $height, $crop, $class, $attributes, $lazy);
817
        }
818
819
        return '';
820
    }
821
822
    public function getMediaLazyTag($width = null, $height = null, $crop = null, $class = null, $attributes = [])
823
    {
824
        return $this->getMediaTag($width, $height, $crop, $class, $attributes, true);
825
    }
826
827
    public function getMediaFilename($width = null, $height = null, $crop = null, $class = null, $attributes = [])
0 ignored issues
show
Unused Code introduced by
The parameter $class is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $attributes is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
828
    {
829
        if ($this->hasNotEmpty('media')) {
830
            return $this->getMedia()->getFilename($width, $height, $crop);
831
        }
832
833
        return '';
834
    }
835
836
    public function getMediaAbsoluteUrl()
837
    {
838
        if ($this->hasNotEmpty('media')) {
839
            return $this->getMedia()->getAbsoluteUrl();
840
        }
841
842
        return false;
843
    }
844
845
    public function getTags()
846
    {
847
        $id                  = $this->getPK();
0 ignored issues
show
Unused Code introduced by
$id is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
848
        $crossReferenceTable = 'node_tag';
849
850
        $subQuery   = new Ajde_Db_Function('(SELECT tag FROM ' . $crossReferenceTable . ' WHERE node = ' . $this->getPK() . ')');
851
        $collection = new TagCollection();
852
        $collection->addFilter(new Ajde_Filter_Where('id', Ajde_Filter::FILTER_IN, $subQuery));
853
854
        return $collection;
855
    }
856
857
    /** META **/
858
859
    public function getMetaValues()
860
    {
861
        if (empty($this->_metaValues)) {
862
            $meta = [];
863
            if ($this->hasLoaded()) {
864
                $sql       = "
865
					SELECT node_meta.*, nodetype_meta.sort AS sort
866
					FROM node_meta
867
					INNER JOIN nodetype_meta ON nodetype_meta.meta = node_meta.meta
868
						AND nodetype_meta.nodetype = ?
869
					WHERE node = ?
870
					ORDER BY sort ASC";
871
                $statement = $this->getConnection()->prepare($sql);
872
                $statement->execute([(string)$this->getNodetype(), $this->getPK()]);
873
                $results = $statement->fetchAll(PDO::FETCH_ASSOC);
874 View Code Duplication
                foreach ($results as $result) {
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...
875
                    if (isset($meta[$result['meta']])) {
876
                        if (is_array($meta[$result['meta']])) {
877
                            $meta[$result['meta']][] = $result['value'];
878
                        } else {
879
                            $meta[$result['meta']] = [
880
                                $meta[$result['meta']],
881
                                $result['value']
882
                            ];
883
                        }
884
                    } else {
885
                        $meta[$result['meta']] = $result['value'];
886
                    }
887
                }
888
            }
889
            $this->_metaValues = $meta;
890
        }
891
892
        return $this->_metaValues;
893
    }
894
895
    public function featuredImage($width = 800)
896
    {
897
        if ($this->hasNotEmpty('media')) {
898
            return $this->getMedia()->getFilename($width);
899
        }
900
901
        foreach ($this->getChildren() as $child) {
902
            if ($child->hasNotEmpty('media')) {
903
                return $child->getMedia()->getFilename($width);
904
            }
905
        }
906
907
        return false;
908
    }
909
}
910