NodeModel::_sluggify()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 9
Ratio 90 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 1
dl 9
loc 10
rs 9.4285
c 0
b 0
f 0
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
     * @param int $id
27
     *
28
     * @return NodeModel|bool
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
     * @param $slug
42
     *
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
    public function getPublishData()
163
    {
164
        if ($return = $this->shadowCall('getPublishData')) {
165
            return $return;
166
        }
167
168
        return [
169
            '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...
170
            '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...
171
            'image'   => $this->getMediaAbsoluteUrl(),
172
            'url'     => $this->getUrl(false),
173
        ];
174
    }
175
176
    public function getPublishRecipients()
177
    {
178
        if ($return = $this->shadowCall('getPublishRecipients')) {
179
            return $return;
180
        }
181
        $users = new UserCollection();
182
        $addresses = [];
183
        foreach ($users as $user) {
184
            /* @var $user UserModel */
185
            $addresses[] = $user->getEmail();
186
        }
187
188
        return $addresses;
189
    }
190
191 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...
192
    {
193
        $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...
194
        $controller = Ajde_Controller::fromRoute(new Ajde_Core_Route('admin/node:panel'));
195
        $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...
196
197
        return $controller->invoke();
198
    }
199
200
    public function displayTreeName()
201
    {
202
        $nodetype = $this->has('nodetype_name') ? $this->get('nodetype_name') : $this->getNodetype()->displayField();
203
        $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...
204
        $ret = str_repeat('<span class="tree-spacer"></span>', max(0, $this->get('level') - 1));
205
        if ($this->get('level') > 0) {
206
            $ret = $ret.'<span class="tree-spacer last"></span>';
207
        }
208
        //$ret .= '<span class="badge">'. strtolower($nodetype) . '</span>';
209
        $ret .= '<span class="badge-icon" title="'.esc($nodetype).'"><i class="'.$icon.'"></i></span>';
210
        $ret .= ' <span class="title">'.clean($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...
211
212
        return $ret;
213
    }
214
215
    public function displayParentName()
216
    {
217
        $ret = '';
218
        $parentId = $this->has('parent') ? $this->getParent() : false;
219
        if ($parentId) {
220
            $parent = new self();
221
            $parent->ignoreAccessControl = true;
222
            $parent->loadByPK($parentId);
223
            $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...
224
        }
225
        $ret .= ' <span class="title">'.clean($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...
226
227
        return $ret;
228
    }
229
230
    public function displayRootName()
231
    {
232
        $ret = '';
233
        $root = $this->findRootNoAccessChecks();
234
        if ($root) {
235
            $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...
236
        }
237
        $ret .= ' <span class="title">'.clean($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...
238
239
        return $ret;
240
    }
241
242 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...
243
    {
244
        $timestamp = new DateTime($this->get('updated'));
245
        $timestamp = $timestamp->format('U');
246
247
        return Ajde_Component_String::time2str($timestamp);
248
    }
249
250
    public function displayPublished()
251
    {
252
        if ($this->getNodetype()->get('published')) {
253
            if (!$this->get('published')) {
254
                return "<i class='icon-remove' title='No' />";
255
            } else {
256
                if (($start = $this->get('published_start')) &&
257
                    strtotime($start) > time()
258
                ) {
259
                    return "<i class='icon-time' title='Queued' />";
260 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...
261
                    if (($end = $this->get('published_end')) &&
262
                        strtotime($end) < time()
263
                    ) {
264
                        return "<i class='icon-remove' title='Expired' />";
265
                    } else {
266
                        return "<i class='icon-ok' title='Yes' />";
267
                    }
268
                }
269
            }
270
        } else {
271
            return '';
272
        }
273
    }
274
275 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...
276
    {
277
        Ajde::app()->getDocument()->getLayout()->getParser()->getHelper()->requireCssPublic('core/flags.css');
278
279
        $lang = Ajde_Lang::getInstance();
280
        $currentLang = $this->get('lang');
281
        if ($currentLang) {
282
            $image = '<img src="" class="flag flag-'.strtolower(substr($currentLang, 3,
283
                    2)).'" alt="'.$currentLang.'" />';
284
285
            return $image.$lang->getNiceName($currentLang);
286
        }
287
288
        return '';
289
    }
290
291
    public function rowClass()
292
    {
293
        $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...
294
        if ($this->has('status')) {
295
            $class .= ' '.strtolower($this->get('status'));
296
        }
297
298
        return $class;
299
    }
300
301
    public function editRouteChild()
302
    {
303
        $childtype = '';
304
        if ($this->hasLoaded()) {
305
            $childtype = $this->getNodetype()->get('child_type');
306
        }
307
308
        return 'admin/node:view.crud?view[filter][nodetype]='.$childtype;
309
    }
310
311
    public function listRouteParent()
312
    {
313
        $parenttype = '';
314
        if ($this->hasLoaded()) {
315
            $parenttype = $this->getNodetype()->get('parent_type');
316
        }
317
318
        return 'admin/node:view.crud?view[filter][nodetype]='.$parenttype;
319
    }
320
321
    public function addChildButton()
322
    {
323
        if ($this->hasLoaded() && $childtype = $this->getNodetype()->get('child_type')) {
324
            $this->getNodetype()->loadParent('child_type');
325
326
            return '<i class="icon-plus icon-white" data-nodetype="'.$childtype.'"></i><span class="text-slide"> '.strtolower($this->getNodetype()->get('child_type')->getName()).'</span>';
327
        }
328
        if ($this->hasLoaded() && $childtype = $this->getNodetype()->get('children')) {
329
            return '<i class="icon-plus icon-white"></i>';
330
        }
331
332
        return false;
333
    }
334
335
    /**
336
     * BEFORE / AFTER FUNCTIONS.
337
     */
338
    public function afterSort()
339
    {
340
        $this->sortTree('NodeCollection');
341
    }
342
343
    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...
344
    {
345
        $this->updateRoot();
346
    }
347
348
    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...
349
    {
350
        // Update sort
351
        $this->sortTree('NodeCollection');
352
    }
353
354
    public function beforeDelete()
355
    {
356
        $this->shadowCall('beforeDelete');
357
    }
358
359
    public function beforeSave()
360
    {
361
        // filter slug
362
        $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...
363
364
        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...
365
            $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...
366
        }
367
368
        $this->added = new Ajde_Db_Function('added');
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...
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
    public function getShadowModel()
406
    {
407
        if (!isset($this->_shadowModel)) {
408
            $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...
409
            if (class_exists($modelName)) {
410
                $this->_shadowModel = new $modelName();
411
            } else {
412
                $this->_shadowModel = false;
413
            }
414
        }
415
416
        $this->shadowCopy();
417
418
        return $this->_shadowModel;
419
    }
420
421
    public function shadowCopy()
422
    {
423
        if ($this->_shadowModel) {
424
            $this->_shadowModel->populate($this->values());
425
            $this->_shadowModel->populateMeta($this->_metaValues);
426
        }
427
    }
428
429
    public function shadowCall($method)
430
    {
431
        $shadowModel = $this->getShadowModel();
432
        if ($shadowModel) {
433
            try {
434
                $rfmethod = new ReflectionMethod($shadowModel, $method);
435
                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...
436
                    return $shadowModel->$method();
437
                }
438
            } catch (Exception $e) {
439
                return false;
440
            }
441
        }
442
443
        return false;
444
    }
445
446
    /**
447
     * SLUG FUNCTIONS.
448
     */
449
    public function getSlug()
450
    {
451
        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...
452
            $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...
453
        }
454
455
        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...
456
    }
457
458 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...
459
    {
460
        $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...
461
462
        $ghost = new self();
463
        $uniqifier = 0;
464
465
        do {
466
            $ghost->reset();
467
            $slug = $this->_sluggify($name);
468
            $slug = $slug.($uniqifier > 0 ? '-'.$uniqifier : '');
469
            $ghost->loadBySlug($slug);
470
            $uniqifier++;
471
            if ($uniqifier >= 100) {
472
                throw new Ajde_Controller_Exception('Max recursion depth reached for setting slug');
473
            }
474
        } while ($ghost->hasLoaded());
475
476
        return $slug;
477
    }
478
479
    /**
480
     * @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...
481
     *
482
     * @deprecated use $this->slug = $this->_makeSlug();
483
     */
484
    private function _setSlug()
485
    {
486
        $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...
487
    }
488
489 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...
490
    {
491
        // @see http://stackoverflow.com/a/5240834
492
        $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...
493
        $slug = preg_replace("/[^a-zA-Z0-9\/_| -]/", '', $name);
494
        $slug = strtolower(trim($slug, '-'));
495
        $slug = preg_replace("/[\/_| -]+/", '-', $slug);
496
497
        return $slug;
498
    }
499
500
    public function loadBySlug($slug, $publishedCheck = false)
501
    {
502
        $this->loadByField('slug', $slug);
503
        if ($publishedCheck) {
504
            $this->filterPublished();
505
        }
506
507
        return $this->hasLoaded();
508
    }
509
510
    /**
511
     * PUBLISHED FUNCTIONS.
512
     */
513
    public function checkPublished()
514
    {
515
        if ($this->getNodetype()->get('published')) {
516
            if (!$this->get('published')) {
517
                return false;
518
            }
519
            if (($start = $this->get('published_start')) &&
520
                strtotime($start) > time()
521
            ) {
522
                return false;
523
            }
524 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...
525
                strtotime($end) < time()
526
            ) {
527
                return false;
528
            }
529
        }
530
531
        return true;
532
    }
533
534
    public function filterPublished()
535
    {
536
        if (false === $this->checkPublished()) {
537
            $this->reset();
538
        }
539
    }
540
541 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...
542
    {
543
        $return = parent::_load($sql, $values, $populate);
544
        if ($return && Ajde::app()->getRequest()->getParam('filterPublished', false) == true) {
545
            $this->filterPublished();
546
        }
547
548
        return $return;
549
    }
550
551
    /**
552
     * TREE FUNCTIONS.
553
     */
554
555
    /**
556
     * @param bool $returnModel
557
     *
558
     * @return NodeModel|bool
559
     */
560
    public function getRoot($returnModel = true)
561
    {
562
        if ($this->hasNotEmpty('root')) {
563
            if ($returnModel) {
564
                $this->loadParent('root');
565
566
                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...
567
            } else {
568
                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...
569
            }
570
        } else {
571
            if ($returnModel) {
572
                return $this;
573
            } else {
574
                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...
575
            }
576
        }
577
    }
578
579
    /**
580
     * @return NodeModel|bool
581
     */
582
    public function findRootNoAccessChecks($load = true)
583
    {
584
        return $this->findRoot(false, $load);
585
    }
586
587
    /**
588
     * @param bool $accessChecks
589
     * @param bool $load
590
     *
591
     * @return bool|NodeModel
592
     */
593
    public function findRoot($accessChecks = true, $load = true)
594
    {
595
        $node = new self();
596
        if ($accessChecks === false) {
597
            $node->ignoreAccessControl = true;
598
        }
599
        $lastParent = $this->getPK();
600
        $parent = $this->has('parent') ? $this->getParent(false) : false;
601
        while ($parent) {
602
            $lastParent = $parent;
603
            $node->loadByPK($parent);
604
            $parent = $node->has('parent') ? $node->getParent(false) : false;
605
        }
606
        if ($lastParent === $this->getPK()) {
607
            return $this;
608
        } else {
609
            if ($lastParent) {
610
                if ($load) {
611
                    $root = new self();
612
                    if (!$accessChecks) {
613
                        $root->ignoreAccessControl = true;
614
                    }
615
                    $root->loadByPK($lastParent);
616
617
                    return $root;
618
                } else {
619
                    return (string) $lastParent;
620
                }
621
            }
622
        }
623
624
        // TODO: we can never reach this?
625
        return false;
626
    }
627
628
    public function updateRoot()
629
    {
630
        // Update root
631
        $root = $this->findRootNoAccessChecks(false);
632
        $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...
633
634
        // go through all direct descendants
635
        $collection = new NodeCollection();
636
        $collection->ignoreAccessControl = true;
637
        $collection->autoRedirect = false;
638
        $collection->filterChildrenOfParent($root);
639
        foreach ($collection as $child) {
640
            $child->setRoot(($child->getPK() != $root) ? $root : null);
641
            $child->save();
642
        }
643
    }
644
645
    /**
646
     * @return NodeCollection
647
     */
648 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...
649
    {
650
        $collection = new NodeCollection();
651
        $collection->addFilter(new Ajde_Filter_Join('node_related', 'node.id', 'related'));
652
        $collection->addFilter(new Ajde_Filter_Where('node_related.node', Ajde_Filter::FILTER_EQUALS, $this->getPK()));
653
        $collection->orderBy('node_related.sort');
654
655
        return $collection;
656
    }
657
658
    /**
659
     * @return MediaCollection
660
     */
661
    public function getAdditionalMedia()
662
    {
663
        $collection = new MediaCollection();
664
        $collection->addFilter(new Ajde_Filter_Join('node_media', 'node_media.media', 'media.id'));
665
        $collection->addFilter(new Ajde_Filter_Join('node', 'node.id', 'node_media.node'));
666
        $collection->addFilter(new Ajde_Filter_Where('node_media.node', Ajde_Filter::FILTER_EQUALS, $this->getPK()));
667
        $collection->orderBy('node_media.sort');
668
669
        return $collection;
670
    }
671
672
    /**
673
     * @return NodeModel
674
     */
675
    public function getParent($load = true)
676
    {
677
        if ($load) {
678
            $this->loadParent('parent');
679
680
            return $this->get('parent');
681
        }
682
683
        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...
684
    }
685
686
    /**
687
     * @return NodeCollection
688
     */
689
    public function getChildren()
690
    {
691
        $collection = new NodeCollection();
692
        $collection->filterByParent($this->getPK());
693
        $collection->orderBy('sort');
694
695
        return $collection;
696
    }
697
698
    public function getNext($loop = true)
699
    {
700
        return $this->getSibling('next', $loop);
701
    }
702
703
    public function getPrev($loop = true)
704
    {
705
        return $this->getSibling('prev', $loop);
706
    }
707
708
    public function getSibling($dir, $loop = true)
709
    {
710
        if ($dir == 'next') {
711
            $filter = Ajde_Filter::FILTER_GREATER;
712
            $order = Ajde_Query::ORDER_ASC;
713
        } else {
714
            $filter = Ajde_Filter::FILTER_LESS;
715
            $order = Ajde_Query::ORDER_DESC;
716
        }
717
718
        if ($this->has('parent')) {
719
            $siblings = new NodeCollection();
720
            $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...
721
            $siblings->addFilter(new Ajde_Filter_Where('parent', Ajde_Filter::FILTER_EQUALS,
722
                (string) $this->get('parent')));
723
            $siblings->orderBy('sort', $order);
724
            $siblings->limit(1);
725
            if ($siblings->count()) {
726
                return $siblings->current();
727
            }
728
        }
729
        // Not found, loop?
730
        if ($loop === true) {
731
            $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...
732
            $siblings->addFilter(new Ajde_Filter_Where('parent', Ajde_Filter::FILTER_EQUALS,
733
                (string) $this->get('parent')));
734
            $siblings->orderBy('sort', $order);
735
            $siblings->limit(1);
736
            if ($siblings->count()) {
737
                return $siblings->current();
738
            }
739
        }
740
741
        // No sibling
742
        return false;
743
    }
744
745
    /***
746
     * GETTERS
747
     */
748
749
    /**
750
     * @return bool|string
751
     *
752
     * @deprecated
753
     */
754
    public function getPath()
755
    {
756
        return $this->getUrl();
757
    }
758
759
    public function getUrl($relative = true)
760
    {
761
        if ($this->getPK()) {
762
            $url = $this->getFullUrl();
763
764
            return $relative ? $url : config('app.rootUrl').$url;
765
        }
766
767
        return false;
768
    }
769
770
    public function getFullUrl()
771
    {
772
        if (($parent = $this->getParent()) && $parent->hasLoaded()) {
773
            return $parent->getFullUrl().'/'.$this->getSlug();
774
        }
775
776
        return $this->getSlug();
777
    }
778
779
    /**
780
     * @return NodetypeModel
781
     */
782
    public function getNodetype()
783
    {
784
        $this->loadParent('nodetype');
785
786
        return parent::getNodetype();
787
    }
788
789
    /**
790
     * @return MediaModel
791
     */
792
    public function getMedia()
793
    {
794
        $this->loadParent('media');
795
796
        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...
797
    }
798
799
    public function getMediaTag(
800
        $width = null,
801
        $height = null,
802
        $crop = null,
803
        $class = null,
804
        $attributes = [],
805
        $lazy = false
806
    ) {
807
        if ($this->hasNotEmpty('media')) {
808
            return $this->getMedia()->getTag($width, $height, $crop, $class, $attributes, $lazy);
809
        }
810
811
        return '';
812
    }
813
814
    public function getMediaLazyTag($width = null, $height = null, $crop = null, $class = null, $attributes = [])
815
    {
816
        return $this->getMediaTag($width, $height, $crop, $class, $attributes, true);
817
    }
818
819
    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...
820
    {
821
        if ($this->hasNotEmpty('media')) {
822
            return $this->getMedia()->getFilename($width, $height, $crop);
823
        }
824
825
        return '';
826
    }
827
828
    public function getMediaAbsoluteUrl()
829
    {
830
        if ($this->hasNotEmpty('media')) {
831
            return $this->getMedia()->getAbsoluteUrl();
832
        }
833
834
        return false;
835
    }
836
837
    public function getTags()
838
    {
839
        $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...
840
        $crossReferenceTable = 'node_tag';
841
842
        $subQuery = new Ajde_Db_Function('(SELECT tag FROM '.$crossReferenceTable.' WHERE node = '.$this->getPK().')');
843
        $collection = new TagCollection();
844
        $collection->addFilter(new Ajde_Filter_Where('id', Ajde_Filter::FILTER_IN, $subQuery));
845
846
        return $collection;
847
    }
848
849
    /** META **/
850
    public function getMetaValues()
851
    {
852
        if (empty($this->_metaValues)) {
853
            $meta = [];
854
            if ($this->hasLoaded()) {
855
                $sql = '
856
					SELECT node_meta.*, nodetype_meta.sort AS sort
857
					FROM node_meta
858
					INNER JOIN nodetype_meta ON nodetype_meta.meta = node_meta.meta
859
						AND nodetype_meta.nodetype = ?
860
					WHERE node = ?
861
					ORDER BY sort ASC';
862
                $statement = $this->getConnection()->prepare($sql);
863
                $statement->execute([(string) $this->getNodetype(), $this->getPK()]);
864
                $results = $statement->fetchAll(PDO::FETCH_ASSOC);
865 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...
866
                    if (isset($meta[$result['meta']])) {
867
                        if (is_array($meta[$result['meta']])) {
868
                            $meta[$result['meta']][] = $result['value'];
869
                        } else {
870
                            $meta[$result['meta']] = [
871
                                $meta[$result['meta']],
872
                                $result['value'],
873
                            ];
874
                        }
875
                    } else {
876
                        $meta[$result['meta']] = $result['value'];
877
                    }
878
                }
879
            }
880
            $this->_metaValues = $meta;
881
        }
882
883
        return $this->_metaValues;
884
    }
885
886
    public function featuredImage($width = 800)
887
    {
888
        if ($this->hasNotEmpty('media')) {
889
            return $this->getMedia()->getFilename($width);
890
        }
891
892
        foreach ($this->getChildren() as $child) {
893
            if ($child->hasNotEmpty('media')) {
894
                return $child->getMedia()->getFilename($width);
895
            }
896
        }
897
898
        return false;
899
    }
900
}
901