StreamModel   F
last analyzed

Complexity

Total Complexity 65

Size/Duplication

Total Lines 707
Duplicated Lines 2.55 %

Coupling/Cohesion

Components 5
Dependencies 15

Importance

Changes 0
Metric Value
dl 18
loc 707
rs 2.6666
c 0
b 0
f 0
wmc 65
lcom 5
cbo 15

49 Methods

Rating   Name   Duplication   Size   Complexity  
A boot() 0 6 1
C make() 18 89 11
A compile() 0 4 1
A flushCache() 0 8 1
A fireFieldTypeEvents() 0 15 2
A create() 0 8 1
A getId() 0 4 1
A getNamespace() 0 4 1
A getSlug() 0 4 1
A getPrefix() 0 4 1
A getName() 0 4 1
A getDescription() 0 4 1
A getConfig() 0 14 3
A mergeConfig() 0 6 1
A isLocked() 0 4 1
A isHidden() 0 4 1
A isSortable() 0 4 1
A isSearchable() 0 4 1
A isTrashable() 0 4 1
A isTranslatable() 0 4 1
A getTitleColumn() 0 4 1
A getTitleField() 0 4 1
A getAssignments() 0 4 1
A getAssignmentFieldSlugs() 0 6 1
A getDateAssignments() 0 6 1
A getUniqueAssignments() 0 6 1
A getRequiredAssignments() 0 6 1
A getUnlockedAssignments() 0 6 1
A getTranslatableAssignments() 0 6 1
A getRelationshipAssignments() 0 6 1
A getAssignment() 0 4 1
A hasAssignment() 0 4 1
A getField() 0 8 2
A getFieldType() 0 8 2
A getFieldTypeQuery() 0 8 2
A getEntryTableName() 0 4 1
A getEntryTranslationsTableName() 0 4 1
A getEntryModel() 0 4 1
A getEntryModelName() 0 7 1
A getForeignKey() 0 4 1
A setConfigAttribute() 0 4 1
A getConfigAttribute() 0 4 1
A setLockedAttribute() 0 4 1
A setHiddenAttribute() 0 4 1
A setSortableAttribute() 0 4 1
A setTrashableAttribute() 0 4 1
A setTranslatableAttribute() 0 4 1
A getPresenter() 0 4 1
A assignments() 0 7 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like StreamModel often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use StreamModel, and based on these observations, apply Extract Interface, too.

1
<?php namespace Anomaly\Streams\Platform\Stream;
2
3
use Anomaly\Streams\Platform\Addon\FieldType\FieldType;
4
use Anomaly\Streams\Platform\Addon\FieldType\FieldTypeQuery;
5
use Anomaly\Streams\Platform\Assignment\AssignmentCollection;
6
use Anomaly\Streams\Platform\Assignment\AssignmentModel;
7
use Anomaly\Streams\Platform\Assignment\AssignmentModelTranslation;
8
use Anomaly\Streams\Platform\Assignment\Contract\AssignmentInterface;
9
use Anomaly\Streams\Platform\Collection\CacheCollection;
10
use Anomaly\Streams\Platform\Entry\Contract\EntryInterface;
11
use Anomaly\Streams\Platform\Entry\EntryModel;
12
use Anomaly\Streams\Platform\Field\Contract\FieldInterface;
13
use Anomaly\Streams\Platform\Field\FieldModel;
14
use Anomaly\Streams\Platform\Field\FieldModelTranslation;
15
use Anomaly\Streams\Platform\Model\EloquentCollection;
16
use Anomaly\Streams\Platform\Model\EloquentModel;
17
use Anomaly\Streams\Platform\Stream\Command\CompileStream;
18
use Anomaly\Streams\Platform\Stream\Command\MergeStreamConfig;
19
use Anomaly\Streams\Platform\Stream\Contract\StreamInterface;
20
use Robbo\Presenter\PresentableInterface;
21
use Robbo\Presenter\Robbo;
22
23
/**
24
 * Class StreamModel
25
 *
26
 * @link    http://pyrocms.com/
27
 * @author  PyroCMS, Inc. <[email protected]>
28
 * @author  Ryan Thompson <[email protected]>
29
 */
30
class StreamModel extends EloquentModel implements StreamInterface, PresentableInterface
31
{
32
33
    /**
34
     * The cache minutes.
35
     *
36
     * @var int
37
     */
38
    protected $cacheMinutes = 99999;
39
40
    /**
41
     * The foreign key for translations.
42
     *
43
     * @var string
44
     */
45
    protected $translationForeignKey = 'stream_id';
46
47
    /**
48
     * The translation model.
49
     *
50
     * @var string
51
     */
52
    protected $translationModel = 'Anomaly\Streams\Platform\Stream\StreamModelTranslation';
53
54
    /**
55
     * Translatable attributes.
56
     *
57
     * @var array
58
     */
59
    protected $translatedAttributes = [
60
        'name',
61
        'description',
62
    ];
63
64
    /**
65
     * The model's database table name.
66
     *
67
     * @var string
68
     */
69
    protected $table = 'streams_streams';
70
71
    /**
72
     * The streams store.
73
     *
74
     * @var StreamStore
75
     */
76
    protected static $store;
77
78
    /**
79
     * Boot the model.
80
     */
81
    protected static function boot()
82
    {
83
        self::$store = app('Anomaly\Streams\Platform\Stream\StreamStore');
84
85
        parent::boot();
86
    }
87
88
    /**
89
     * Make a Stream instance from the provided compile data.
90
     *
91
     * @param  array $data
92
     * @return StreamInterface
93
     */
94
    public function make(array $data)
95
    {
96
        $payload = $data;
97
98
        if ($stream = self::$store->get($data)) {
99
            return $stream;
100
        }
101
102
        $assignments = [];
103
104
        $streamModel        = new StreamModel();
105
        $streamTranslations = new EloquentCollection();
106
107
        $data['config'] = serialize(array_get($data, 'config', []));
108
109
        if ($translations = array_pull($data, 'translations')) {
110
            foreach ($translations as $attributes) {
111
                $translation = new StreamModelTranslation();
112
                $translation->setRawAttributes($attributes);
113
114
                $streamTranslations->push($translation);
115
            }
116
        }
117
118
        $streamModel->setRawAttributes($data);
119
120
        $streamModel->setRelation('translations', $streamTranslations);
121
122
        unset($this->translations);
123
124
        if (array_key_exists('assignments', $data)) {
125
            foreach ($data['assignments'] as $assignment) {
126
                if (isset($assignment['field'])) {
127
                    $assignment['field']['config'] = unserialize($assignment['field']['config']);
128
129
                    $fieldModel        = new FieldModel();
130
                    $fieldTranslations = new EloquentCollection();
131
132 View Code Duplication
                    if (isset($assignment['field']['translations'])) {
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...
133
                        foreach (array_pull($assignment['field'], 'translations') as $attributes) {
134
                            $translation = new FieldModelTranslation();
135
                            $translation->setRawAttributes($attributes);
136
137
                            $fieldTranslations->push($translation);
138
                        }
139
                    }
140
141
                    $assignment['field']['config'] = serialize($assignment['field']['config']);
142
143
                    $fieldModel->setRawAttributes($assignment['field']);
144
145
                    $fieldModel->setRelation('translations', $fieldTranslations);
146
147
                    unset($assignment['field']);
148
149
                    $assignmentModel        = new AssignmentModel();
150
                    $assignmentTranslations = new EloquentCollection();
151
152 View Code Duplication
                    if (isset($assignment['translations'])) {
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...
153
                        foreach (array_pull($assignment, 'translations') as $attributes) {
154
                            $translation = new AssignmentModelTranslation();
155
                            $translation->setRawAttributes($attributes);
156
157
                            $assignmentTranslations->push($translation);
158
                        }
159
                    }
160
161
                    $assignmentModel->setRawAttributes($assignment);
162
                    $assignmentModel->setRawAttributes($assignment);
163
164
                    $assignmentModel->setRelation('field', $fieldModel);
165
                    $assignmentModel->setRelation('stream', $streamModel);
166
                    $assignmentModel->setRelation('translations', $assignmentTranslations);
167
168
                    $assignments[] = $assignmentModel;
169
                }
170
            }
171
        }
172
173
        $assignmentsCollection = new AssignmentCollection($assignments);
174
175
        $streamModel->setRelation('assignments', $assignmentsCollection);
176
177
        $streamModel->assignments = $assignmentsCollection;
0 ignored issues
show
Documentation introduced by
The property assignments does not exist on object<Anomaly\Streams\P...orm\Stream\StreamModel>. 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...
178
179
        self::$store->put($payload, $streamModel);
180
181
        return $streamModel;
182
    }
183
184
    /**
185
     * Compile the entry models.
186
     *
187
     * @return mixed
188
     */
189
    public function compile()
190
    {
191
        $this->dispatch(new CompileStream($this));
192
    }
193
194
    /**
195
     * Flush the entry stream's cache.
196
     *
197
     * @return StreamInterface
198
     */
199
    public function flushCache()
200
    {
201
        (new CacheCollection())->setKey($this->getCacheCollectionKey())->flush();
202
        (new CacheCollection())->setKey((new FieldModel())->getCacheCollectionKey())->flush();
203
        (new CacheCollection())->setKey((new AssignmentModel())->getCacheCollectionKey())->flush();
204
205
        return $this;
206
    }
207
208
    /**
209
     * Fire field type events.
210
     *
211
     * @param       $trigger
212
     * @param array $payload
213
     */
214
    public function fireFieldTypeEvents($trigger, $payload = [])
215
    {
216
        $assignments = $this->getAssignments();
217
218
        /* @var AssignmentInterface $assignment */
219
        foreach ($assignments->notTranslatable() as $assignment) {
220
221
            $fieldType = $assignment->getFieldType();
222
223
            $payload['stream']    = $this;
224
            $payload['fieldType'] = $fieldType;
225
226
            $fieldType->fire($trigger, $payload);
227
        }
228
    }
229
230
    /**
231
     * Because the stream record holds translatable data
232
     * we have a conflict. The streams table has translations
233
     * but not all streams are translatable. This helps avoid
234
     * the translatable conflict during specific procedures.
235
     *
236
     * @param  array $attributes
237
     * @return static
238
     */
239
    public static function create(array $attributes = [])
240
    {
241
        $model = parent::create($attributes);
242
243
        $model->saveTranslations();
244
245
        return $model;
246
    }
247
248
    /**
249
     * Get the ID.
250
     *
251
     * @return mixed
252
     */
253
    public function getId()
254
    {
255
        return $this->getKey();
256
    }
257
258
    /**
259
     * Get the namespace.
260
     *
261
     * @return mixed
262
     */
263
    public function getNamespace()
264
    {
265
        return $this->namespace;
0 ignored issues
show
Documentation introduced by
The property namespace does not exist on object<Anomaly\Streams\P...orm\Stream\StreamModel>. 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...
266
    }
267
268
    /**
269
     * Get the slug.
270
     *
271
     * @return mixed
272
     */
273
    public function getSlug()
274
    {
275
        return $this->slug;
0 ignored issues
show
Documentation introduced by
The property slug does not exist on object<Anomaly\Streams\P...orm\Stream\StreamModel>. 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...
276
    }
277
278
    /**
279
     * Get the prefix.
280
     *
281
     * @return mixed
282
     */
283
    public function getPrefix()
284
    {
285
        return $this->prefix;
0 ignored issues
show
Documentation introduced by
The property prefix does not exist on object<Anomaly\Streams\P...orm\Stream\StreamModel>. 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...
286
    }
287
288
    /**
289
     * Get the name.
290
     *
291
     * @return string
292
     */
293
    public function getName()
294
    {
295
        return $this->name;
0 ignored issues
show
Documentation introduced by
The property name does not exist on object<Anomaly\Streams\P...orm\Stream\StreamModel>. 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...
296
    }
297
298
    /**
299
     * Get the description.
300
     *
301
     * @return string
302
     */
303
    public function getDescription()
304
    {
305
        return $this->description;
0 ignored issues
show
Documentation introduced by
The property description does not exist on object<Anomaly\Streams\P...orm\Stream\StreamModel>. 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...
306
    }
307
308
    /**
309
     * Get the config.
310
     *
311
     * @param  null $key
312
     * @param  null $default
313
     * @return mixed
314
     */
315
    public function getConfig($key = null, $default = null)
316
    {
317
        if (!isset($this->cache['cache'])) {
318
            $this->dispatch(new MergeStreamConfig($this));
319
        }
320
321
        $this->cache['cache'] = $this->config;
0 ignored issues
show
Documentation introduced by
The property config does not exist on object<Anomaly\Streams\P...orm\Stream\StreamModel>. 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...
322
323
        if ($key) {
324
            return array_get($this->config, $key, $default);
0 ignored issues
show
Documentation introduced by
The property config does not exist on object<Anomaly\Streams\P...orm\Stream\StreamModel>. 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...
325
        }
326
327
        return $this->config;
0 ignored issues
show
Documentation introduced by
The property config does not exist on object<Anomaly\Streams\P...orm\Stream\StreamModel>. 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...
328
    }
329
330
    /**
331
     * Merge configuration.
332
     *
333
     * @param  array $config
334
     * @return $this
335
     */
336
    public function mergeConfig(array $config)
337
    {
338
        $this->config = array_merge((array)$this->config, $config);
0 ignored issues
show
Documentation introduced by
The property config does not exist on object<Anomaly\Streams\P...orm\Stream\StreamModel>. 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...
339
340
        return $this;
341
    }
342
343
    /**
344
     * Get the locked flag.
345
     *
346
     * @return bool
347
     */
348
    public function isLocked()
349
    {
350
        return $this->locked;
0 ignored issues
show
Documentation introduced by
The property locked does not exist on object<Anomaly\Streams\P...orm\Stream\StreamModel>. 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...
351
    }
352
353
    /**
354
     * Get the hidden flag.
355
     *
356
     * @return bool
357
     */
358
    public function isHidden()
359
    {
360
        return $this->hidden;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->hidden; (array) is incompatible with the return type declared by the interface Anomaly\Streams\Platform...reamInterface::isHidden of type 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...
361
    }
362
363
    /**
364
     * Get the sortable flag.
365
     *
366
     * @return bool
367
     */
368
    public function isSortable()
369
    {
370
        return $this->sortable;
0 ignored issues
show
Documentation introduced by
The property sortable does not exist on object<Anomaly\Streams\P...orm\Stream\StreamModel>. 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...
371
    }
372
373
    /**
374
     * Get the searchable flag.
375
     *
376
     * @return bool
377
     */
378
    public function isSearchable()
379
    {
380
        return $this->searchable;
0 ignored issues
show
Documentation introduced by
The property searchable does not exist on object<Anomaly\Streams\P...orm\Stream\StreamModel>. 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...
381
    }
382
383
    /**
384
     * Get the trashable flag.
385
     *
386
     * @return bool
387
     */
388
    public function isTrashable()
389
    {
390
        return $this->trashable;
0 ignored issues
show
Documentation introduced by
The property trashable does not exist on object<Anomaly\Streams\P...orm\Stream\StreamModel>. 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...
391
    }
392
393
    /**
394
     * Get the translatable flag.
395
     *
396
     * @return bool
397
     */
398
    public function isTranslatable()
399
    {
400
        return $this->translatable;
0 ignored issues
show
Documentation introduced by
The property translatable does not exist on object<Anomaly\Streams\P...orm\Stream\StreamModel>. 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...
401
    }
402
403
    /**
404
     * Get the title column.
405
     *
406
     * @return mixed
407
     */
408
    public function getTitleColumn()
409
    {
410
        return $this->title_column;
0 ignored issues
show
Documentation introduced by
The property title_column does not exist on object<Anomaly\Streams\P...orm\Stream\StreamModel>. 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...
411
    }
412
413
    /**
414
     * Get the title field.
415
     *
416
     * @return null|FieldInterface
417
     */
418
    public function getTitleField()
419
    {
420
        return $this->getField($this->getTitleColumn());
421
    }
422
423
    /**
424
     * Get the related assignments.
425
     *
426
     * @return AssignmentCollection
427
     */
428
    public function getAssignments()
429
    {
430
        return $this->assignments;
0 ignored issues
show
Documentation introduced by
The property assignments does not exist on object<Anomaly\Streams\P...orm\Stream\StreamModel>. 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...
431
    }
432
433
    /**
434
     * Get the field slugs for assigned fields.
435
     *
436
     * @param  null $prefix
437
     * @return array
438
     */
439
    public function getAssignmentFieldSlugs($prefix = null)
440
    {
441
        $assignments = $this->getAssignments();
442
443
        return $assignments->fieldSlugs($prefix);
444
    }
445
446
    /**
447
     * Get the related date assignments.
448
     *
449
     * @return AssignmentCollection
450
     */
451
    public function getDateAssignments()
452
    {
453
        $assignments = $this->getAssignments();
454
455
        return $assignments->dates();
456
    }
457
458
    /**
459
     * Get the unique translatable assignments.
460
     *
461
     * @return AssignmentCollection
462
     */
463
    public function getUniqueAssignments()
464
    {
465
        $assignments = $this->getAssignments();
466
467
        return $assignments->indexed();
468
    }
469
470
    /**
471
     * Get the only required assignments.
472
     *
473
     * @return AssignmentCollection
474
     */
475
    public function getRequiredAssignments()
476
    {
477
        $assignments = $this->getAssignments();
478
479
        return $assignments->required();
480
    }
481
482
    /**
483
     * Get the related unlocked assignments.
484
     *
485
     * @return AssignmentCollection
486
     */
487
    public function getUnlockedAssignments()
488
    {
489
        $assignments = $this->getAssignments();
490
491
        return $assignments->unlocked();
492
    }
493
494
    /**
495
     * Get the related translatable assignments.
496
     *
497
     * @return AssignmentCollection
498
     */
499
    public function getTranslatableAssignments()
500
    {
501
        $assignments = $this->getAssignments();
502
503
        return $assignments->translatable();
504
    }
505
506
    /**
507
     * Get the related relationship assignments.
508
     *
509
     * @return AssignmentCollection
510
     */
511
    public function getRelationshipAssignments()
512
    {
513
        $assignments = $this->getAssignments();
514
515
        return $assignments->relations();
516
    }
517
518
    /**
519
     * Get an assignment by it's field's slug.
520
     *
521
     * @param  $fieldSlug
522
     * @return AssignmentInterface
523
     */
524
    public function getAssignment($fieldSlug)
525
    {
526
        return $this->getAssignments()->findByFieldSlug($fieldSlug);
527
    }
528
529
    /**
530
     * Return whether a stream
531
     * has a field assigned.
532
     *
533
     * @param $fieldSlug
534
     * @return bool
535
     */
536
    public function hasAssignment($fieldSlug)
537
    {
538
        return (bool)$this->getAssignment($fieldSlug);
539
    }
540
541
    /**
542
     * Get a stream field by it's slug.
543
     *
544
     * @param  $slug
545
     * @return mixed
546
     */
547
    public function getField($slug)
548
    {
549
        if (!$assignment = $this->getAssignment($slug)) {
550
            return null;
551
        }
552
553
        return $assignment->getField();
554
    }
555
556
    /**
557
     * Get a field's type by the field's slug.
558
     *
559
     * @param                 $fieldSlug
560
     * @param  EntryInterface $entry
561
     * @param  null|string    $locale
562
     * @return FieldType
563
     */
564
    public function getFieldType($fieldSlug, EntryInterface $entry = null, $locale = null)
565
    {
566
        if (!$assignment = $this->getAssignment($fieldSlug)) {
567
            return null;
568
        }
569
570
        return $assignment->getFieldType($entry, $locale);
0 ignored issues
show
Documentation introduced by
$entry is of type null|object<Anomaly\Stre...ontract\EntryInterface>, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Unused Code introduced by
The call to AssignmentInterface::getFieldType() has too many arguments starting with $locale.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
571
    }
572
573
    /**
574
     * Get a field's query utility by the field's slug.
575
     *
576
     * @param                 $fieldSlug
577
     * @param  EntryInterface $entry
578
     * @param  null|string    $locale
579
     * @return FieldTypeQuery
580
     */
581
    public function getFieldTypeQuery($fieldSlug, EntryInterface $entry = null, $locale = null)
582
    {
583
        if (!$fieldType = $this->getFieldType($fieldSlug, $entry, $locale)) {
584
            return null;
585
        }
586
587
        return $fieldType->getQuery();
588
    }
589
590
    /**
591
     * Get the entry table name.
592
     *
593
     * @return string
594
     */
595
    public function getEntryTableName()
596
    {
597
        return $this->getPrefix() . $this->getSlug();
598
    }
599
600
    /**
601
     * Get the entry translations table name.
602
     *
603
     * @return string
604
     */
605
    public function getEntryTranslationsTableName()
606
    {
607
        return $this->getEntryTableName() . '_translations';
608
    }
609
610
    /**
611
     * Get the entry model.
612
     *
613
     * @return EntryModel
614
     */
615
    public function getEntryModel()
616
    {
617
        return app($this->getEntryModelName());
618
    }
619
620
    /**
621
     * Get the entry name.
622
     *
623
     * @return EntryModel
624
     */
625
    public function getEntryModelName()
626
    {
627
        $slug      = ucfirst(camel_case($this->getSlug()));
628
        $namespace = ucfirst(camel_case($this->getNamespace()));
629
630
        return "Anomaly\\Streams\\Platform\\Model\\{$namespace}\\{$namespace}{$slug}EntryModel";
631
    }
632
633
    /**
634
     * Get the foreign key.
635
     *
636
     * @return string
637
     */
638
    public function getForeignKey()
639
    {
640
        return str_singular($this->getSlug()) . '_id';
641
    }
642
643
    /**
644
     * Set the config attribute.
645
     *
646
     * @param $config
647
     */
648
    public function setConfigAttribute($config)
649
    {
650
        $this->attributes['config'] = serialize((array)$config);
651
    }
652
653
    /**
654
     * Get the config attribute.
655
     *
656
     * @param  $viewOptions
657
     * @return mixed
658
     */
659
    public function getConfigAttribute($config)
660
    {
661
        return unserialize($config);
662
    }
663
664
    /**
665
     * Set the locked attribute.
666
     *
667
     * @param $locked
668
     */
669
    public function setLockedAttribute($locked)
670
    {
671
        $this->attributes['locked'] = filter_var($locked, FILTER_VALIDATE_BOOLEAN);
672
    }
673
674
    /**
675
     * Set the hidden attribute.
676
     *
677
     * @param $hidden
678
     */
679
    public function setHiddenAttribute($hidden)
680
    {
681
        $this->attributes['hidden'] = filter_var($hidden, FILTER_VALIDATE_BOOLEAN);
682
    }
683
684
    /**
685
     * Set the sortable attribute.
686
     *
687
     * @param $sortable
688
     */
689
    public function setSortableAttribute($sortable)
690
    {
691
        $this->attributes['sortable'] = filter_var($sortable, FILTER_VALIDATE_BOOLEAN);
692
    }
693
694
    /**
695
     * Set the trashable attribute.
696
     *
697
     * @param $trashable
698
     */
699
    public function setTrashableAttribute($trashable)
700
    {
701
        $this->attributes['trashable'] = filter_var($trashable, FILTER_VALIDATE_BOOLEAN);
702
    }
703
704
    /**
705
     * Set the translatable attribute.
706
     *
707
     * @param $translatable
708
     */
709
    public function setTranslatableAttribute($translatable)
710
    {
711
        $this->attributes['translatable'] = filter_var($translatable, FILTER_VALIDATE_BOOLEAN);
712
    }
713
714
    /**
715
     * Return a created presenter.
716
     *
717
     * @return \Robbo\Presenter\Presenter
718
     */
719
    public function getPresenter()
720
    {
721
        return new StreamPresenter($this);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \Anomaly\Stre...StreamPresenter($this); (Anomaly\Streams\Platform\Stream\StreamPresenter) is incompatible with the return type declared by the interface Robbo\Presenter\PresentableInterface::getPresenter of type Robbo\Presenter\Robbo\Presenter\Presenter.

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...
722
    }
723
724
    /**
725
     * Return the assignments relation.
726
     *
727
     * @return mixed
728
     */
729
    public function assignments()
730
    {
731
        return $this->hasMany(
732
            'Anomaly\Streams\Platform\Assignment\AssignmentModel',
733
            'stream_id'
734
        )->orderBy('sort_order');
735
    }
736
}
737