Completed
Push — master ( e24a08...649c71 )
by Joshua
9s
created

AbstractModel   D

Complexity

Total Complexity 83

Size/Duplication

Total Lines 644
Duplicated Lines 4.19 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 5
Bugs 1 Features 2
Metric Value
wmc 83
c 5
b 1
f 2
lcom 1
cbo 8
dl 27
loc 644
rs 4.6921

35 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A __clone() 0 7 1
D apply() 0 37 10
A clear() 0 16 4
A createEmbedFor() 0 11 2
A get() 0 9 3
A getChangeSet() 0 8 1
A getMetadata() 0 4 1
A getState() 0 4 1
A getStore() 0 4 1
C initialize() 0 34 11
A isAttribute() 0 4 1
A isDirty() 0 7 3
A isEmbed() 0 4 1
A isEmbedHasMany() 0 7 2
A isEmbedHasOne() 0 7 2
A pushEmbed() 0 14 3
A removeEmbed() 11 11 2
A rollback() 0 8 1
A set() 0 9 3
A usesMixin() 0 4 1
A applyDefaultAttrValues() 0 11 4
A convertAttributeValue() 0 4 1
A doDirtyCheck() 0 5 1
A filterNotSavedProperties() 6 10 4
A getAttribute() 0 8 2
A getCalculatedAttribute() 0 9 1
A getDataType() 0 4 1
A getEmbed() 0 12 3
A isCalculatedAttribute() 0 7 2
A setAttribute() 0 11 2
A setEmbed() 0 10 3
A setEmbedHasOne() 10 10 2
A touch() 0 4 1
A validateEmbedSet() 0 6 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 AbstractModel 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 AbstractModel, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace As3\Modlr\Models;
4
5
use As3\Modlr\Metadata\Interfaces\AttributeInterface;
6
use As3\Modlr\Store\Store;
7
8
/**
9
 * Represents a record from a persistence (database) layer.
10
 * Can either be a root record, or an embedded fragment of a root record.
11
 *
12
 * @author Jacob Bare <[email protected]>
13
 */
14
abstract class AbstractModel
15
{
16
    /**
17
     * The model's attributes
18
     *
19
     * @var Attributes
20
     */
21
    protected $attributes;
22
23
    /**
24
     * The Model's has-one embeds
25
     *
26
     * @var Embeds\HasOne
27
     */
28
    protected $hasOneEmbeds;
29
30
    /**
31
     * The Model's has-many embeds
32
     *
33
     * @var Embeds\HasMany
34
     */
35
    protected $hasManyEmbeds;
36
37
    /**
38
     * The metadata that defines this Model.
39
     *
40
     * @var AttributeInterface
41
     */
42
    protected $metadata;
43
44
    /**
45
     * The model state.
46
     *
47
     * @var State
48
     */
49
    protected $state;
50
51
    /**
52
     * The Model Store for handling lifecycle operations.
53
     *
54
     * @var Store
55
     */
56
    protected $store;
57
58
    /**
59
     * Constructor.
60
     *
61
     * @param   AttributeInterface  $metadata
62
     * @param   Store               $store
63
     * @param   array|null          $properties
64
     */
65
    public function __construct(AttributeInterface $metadata, Store $store, array $properties = null)
66
    {
67
        $this->state = new State();
68
        $this->metadata = $metadata;
69
        $this->store = $store;
70
        $this->initialize($properties);
71
    }
72
73
    /**
74
     * Cloner.
75
     * Ensures sub objects are also cloned.
76
     *
77
     */
78
    public function __clone()
79
    {
80
        $this->attributes = clone $this->attributes;
81
        $this->hasOneEmbeds = clone $this->hasOneEmbeds;
82
        $this->hasManyEmbeds = clone $this->hasManyEmbeds;
83
        $this->state = clone $this->state;
84
    }
85
86
    /**
87
     * Applies an array of raw model properties to the model instance.
88
     *
89
     * @todo    Confirm that we want this method. It's currently used for creating and updating via the API adapter. Also see initialize()
90
     * @param   array   $properties     The properties to apply.
91
     * @return  self
92
     */
93
    public function apply(array $properties)
94
    {
95
        $properties = $this->applyDefaultAttrValues($properties);
96
        foreach ($properties as $key => $value) {
97
            if (true === $this->isAttribute($key)) {
98
                $this->set($key, $value);
99
                continue;
100
            }
101
102
            if (true === $this->isEmbedHasOne($key)) {
103
                if (empty($value)) {
104
                    $this->clear($key);
105
                    continue;
106
                }
107
                $embed = $this->get($key) ?: $this->createEmbedFor($key, $value);
0 ignored issues
show
Unused Code introduced by
The call to AbstractModel::createEmbedFor() has too many arguments starting with $value.

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...
108
                $embed->apply($value);
109
                $this->set($key, $embed);
110
                continue;
111
            }
112
        }
113
114
        foreach ($this->getMetadata()->getEmbeds() as $key => $embeddedPropMeta) {
115
            if (true === $embeddedPropMeta->isOne() || !isset($properties[$key])) {
116
                continue;
117
            }
118
119
            // @todo This will always mark the model as dirty, even if the applied embed values are the same as the original.
120
            $this->clear($key);
121
            $collection = $this->getStore()->createEmbedCollection($embeddedPropMeta, $properties[$key]);
122
            foreach ($collection as $value) {
123
                $this->pushEmbed($key, $value);
0 ignored issues
show
Compatibility introduced by
$value of type object<As3\Modlr\Models\AbstractModel> is not a sub-type of object<As3\Modlr\Models\Embed>. It seems like you assume a child class of the class As3\Modlr\Models\AbstractModel to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
124
            }
125
        }
126
127
        $this->doDirtyCheck();
128
        return $this;
129
    }
130
131
    /**
132
     * Clears a property value.
133
     * For an attribute, will set the value to null.
134
     * For collections, will clear the collection contents.
135
     *
136
     * @api
137
     * @param   string  $key    The property key.
138
     * @return  self
139
     */
140
    public function clear($key)
141
    {
142
        if (true === $this->isAttribute($key)) {
143
            return $this->setAttribute($key, null);
144
        }
145
        if (true === $this->isEmbedHasOne($key)) {
146
            return $this->setEmbedHasOne($key, null);
147
        }
148
        if (true === $this->isEmbedHasMany($key)) {
149
            $collection = $this->hasManyEmbeds->get($key);
150
            $collection->clear();
151
            $this->doDirtyCheck();
152
            return $this;
153
        }
154
        return $this;
155
    }
156
157
    /**
158
     * Creates a new Embed model instance for the provided property key.
159
     *
160
     * @param   string  $key
161
     * @return  Embed
162
     * @throws  \RuntimeException
163
     */
164
    public function createEmbedFor($key)
165
    {
166
        if (false === $this->isEmbed($key)) {
167
            throw new \RuntimeException(sprintf('Unable to create an Embed instance for property key "%s" - the property is not an embed.', $key));
168
        }
169
170
        $embedMeta = $this->getMetadata()->getEmbed($key)->embedMeta;
171
        $embed = $this->getStore()->loadEmbed($embedMeta, []);
172
        $embed->getState()->setNew();
173
        return $embed;
174
    }
175
176
    /**
177
     * Gets a model property.
178
     * Returns null if the property does not exist on the model or is not set.
179
     *
180
     * @api
181
     * @param   string  $key    The property field key.
182
     * @return  Model|Model[]|Embed|Collections\EmbedCollection|null|mixed
183
     */
184
    public function get($key)
185
    {
186
        if (true === $this->isAttribute($key)) {
187
            return $this->getAttribute($key);
188
        }
189
        if (true === $this->isEmbed($key)) {
190
            return $this->getEmbed($key);
191
        }
192
    }
193
194
    /**
195
     * Gets the current change set of properties.
196
     *
197
     * @api
198
     * @return  array
199
     */
200
    public function getChangeSet()
201
    {
202
        return [
203
            'attributes'    => $this->filterNotSavedProperties($this->attributes->calculateChangeSet()),
204
            'embedOne'      => $this->hasOneEmbeds->calculateChangeSet(),
205
            'embedMany'     => $this->hasManyEmbeds->calculateChangeSet(),
206
        ];
207
    }
208
209
    /**
210
     * Gets the metadata for this model.
211
     *
212
     * @api
213
     * @return  AttributeInterface
214
     */
215
    public function getMetadata()
216
    {
217
        return $this->metadata;
218
    }
219
220
    /**
221
     * Gets the model state object.
222
     *
223
     * @todo    Should this be public? State setting should likely be locked from the outside world.
224
     * @return  State
225
     */
226
    public function getState()
227
    {
228
        return $this->state;
229
    }
230
231
    /**
232
     * Gets the model store.
233
     *
234
     * @api
235
     * @return  Store
236
     */
237
    public function getStore()
238
    {
239
        return $this->store;
240
    }
241
242
    /**
243
     * Initializes the model and loads its attributes and relationships.
244
     *
245
     * @todo    Made public so collections can initialize models. Not sure if we want this??
246
     * @param   array|null      $properties     The db properties to apply.
247
     * @return  self
248
     */
249
    public function initialize(array $properties = null)
250
    {
251
        $attributes = [];
252
        $embedOne = [];
253
        $embedMany = [];
254
255
        if (null !== $properties) {
256
            $attributes = $this->applyDefaultAttrValues($attributes);
257
            foreach ($properties as $key => $value) {
258
                if (true === $this->isAttribute($key)) {
259
                    // Load attribute.
260
                    $attributes[$key] = $this->convertAttributeValue($key, $value);
261
                } else if (true === $this->isEmbedHasOne($key)) {
262
                    // Load embed one.
263
                    $embedOne[$key] = $this->getStore()->loadEmbed($this->getMetadata()->getEmbed($key)->embedMeta, $value);
264
                }
265
            }
266
        }
267
268
        foreach ($this->getMetadata()->getEmbeds() as $key => $embeddedPropMeta) {
269
            // Always load embedded collections, regardless if data is set.
270
            if (true === $embeddedPropMeta->isOne()) {
271
                continue;
272
            }
273
            $embeds = !isset($properties[$key]) ? [] : $properties[$key];
274
            $embedMany[$key] = $this->getStore()->createEmbedCollection($embeddedPropMeta, $embeds);
275
        }
276
277
        $this->attributes    = (null === $this->attributes) ? new Attributes($attributes) : $this->attributes->replace($attributes);
278
        $this->hasOneEmbeds  = (null === $this->hasOneEmbeds) ? new Embeds\HasOne($embedOne) : $this->hasOneEmbeds->replace($embedOne);
279
        $this->hasManyEmbeds = (null === $this->hasManyEmbeds) ? new Embeds\HasMany($embedMany) : $this->hasManyEmbeds->replace($embedMany);
280
        $this->doDirtyCheck();
281
        return $this;
282
    }
283
284
    /**
285
     * Determines if a property key is an attribute.
286
     *
287
     * @api
288
     * @param   string  $key    The property key.
289
     * @return  bool
290
     */
291
    public function isAttribute($key)
292
    {
293
        return $this->getMetadata()->hasAttribute($key);
294
    }
295
296
    /**
297
     * Determines if the model is currently dirty.
298
     *
299
     * @api
300
     * @return  bool
301
     */
302
    public function isDirty()
303
    {
304
        return true === $this->attributes->areDirty()
305
            || true === $this->hasOneEmbeds->areDirty()
306
            || true === $this->hasManyEmbeds->areDirty()
307
        ;
308
    }
309
310
    /**
311
     * Determines if a property key is an embedded property.
312
     *
313
     * @api
314
     * @param   string  $key    The property key.
315
     * @return  bool
316
     */
317
    public function isEmbed($key)
318
    {
319
        return $this->getMetadata()->hasEmbed($key);
320
    }
321
322
    /**
323
     * Determines if a property key is a has-many embed.
324
     *
325
     * @api
326
     * @param   string  $key    The property key.
327
     * @return  bool
328
     */
329
    public function isEmbedHasMany($key)
330
    {
331
        if (false === $this->isEmbed($key)) {
332
            return false;
333
        }
334
        return $this->getMetadata()->getEmbed($key)->isMany();
335
    }
336
337
    /**
338
     * Determines if a property key is a has-one embed.
339
     *
340
     * @api
341
     * @param   string  $key    The property key.
342
     * @return  bool
343
     */
344
    public function isEmbedHasOne($key)
345
    {
346
        if (false === $this->isEmbed($key)) {
347
            return false;
348
        }
349
        return $this->getMetadata()->getEmbed($key)->isOne();
350
    }
351
352
    /**
353
     * Pushes an Embed into a has-many embed collection.
354
     * This method must be used for has-many embeds. Direct set is not supported.
355
     * To completely replace call clear() first and then pushEmbed() the new Embeds.
356
     *
357
     * @api
358
     * @param   string  $key
359
     * @param   Embed   $embed
360
     * @return  self
361
     */
362
    public function pushEmbed($key, Embed $embed)
363
    {
364
        if (true === $this->isEmbedHasOne($key)) {
365
            return $this->setEmbedHasOne($key, $embed);
366
        }
367
        if (false === $this->isEmbedHasMany($key)) {
368
            return $this;
369
        }
370
        $this->touch();
371
        $collection = $this->hasManyEmbeds->get($key);
372
        $collection->push($embed);
373
        $this->doDirtyCheck();
374
        return $this;
375
    }
376
377
    /**
378
     * Removes a specific Embed from a has-many embed collection.
379
     *
380
     * @api
381
     * @param   string  $key    The has-many embed key.
382
     * @param   Embed   $embed  The embed to remove from the collection.
383
     * @return  self
384
     */
385 View Code Duplication
    public function removeEmbed($key, Embed $embed)
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...
386
    {
387
        if (false === $this->isEmbedHasMany($key)) {
388
            return $this;
389
        }
390
        $this->touch();
391
        $collection = $this->hasManyEmbeds->get($key);
392
        $collection->remove($embed);
393
        $this->doDirtyCheck();
394
        return $this;
395
    }
396
397
    /**
398
     * Rolls back a model to its original values.
399
     *
400
     * @api
401
     * @return  self
402
     */
403
    public function rollback()
404
    {
405
        $this->attributes->rollback();
406
        $this->hasOneEmbeds->rollback();
407
        $this->hasManyEmbeds->rollback();
408
        $this->doDirtyCheck();
409
        return $this;
410
    }
411
412
    /**
413
     * Sets a model property.
414
     *
415
     * @api
416
     * @param   string  $key            The property field key.
417
     * @param   Model|Embed|null|mixed  The value to set.
418
     * @return  self.
0 ignored issues
show
Documentation introduced by
The doc-type self. could not be parsed: Unknown type name "self." at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
419
     */
420
    public function set($key, $value)
421
    {
422
        if (true === $this->isAttribute($key)) {
423
            return $this->setAttribute($key, $value);
424
        }
425
        if (true === $this->isEmbed($key)) {
426
            return $this->setEmbed($key, $value);
427
        }
428
    }
429
430
    /**
431
     * Determines if the model uses a particlar mixin.
432
     *
433
     * @api
434
     * @param   string  $name
435
     * @return  bool
436
     */
437
    public function usesMixin($name)
438
    {
439
        return $this->getMetadata()->hasMixin($name);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface As3\Modlr\Metadata\Interfaces\AttributeInterface as the method hasMixin() does only exist in the following implementations of said interface: As3\Modlr\Metadata\EmbedMetadata, As3\Modlr\Metadata\EntityMetadata.

Let’s take a look at an example:

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

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

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

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

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

Available Fixes

  1. Change the type-hint for the parameter:

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

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

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
440
    }
441
442
    /**
443
     * Applies default attribute values from metadata, if set.
444
     *
445
     * @param   array   $attributes     The attributes to apply the defaults to.
446
     * @return  array
447
     */
448
    protected function applyDefaultAttrValues(array $attributes = [])
449
    {
450
        // Set defaults for each attribute.
451
        foreach ($this->getMetadata()->getAttributes() as $key => $attrMeta) {
452
            if (!isset($attrMeta->defaultValue) || isset($attributes[$key])) {
453
                continue;
454
            }
455
            $attributes[$key] = $this->convertAttributeValue($key, $attrMeta->defaultValue);
456
        }
457
        return $attributes;
458
    }
459
460
    /**
461
     * Converts an attribute value to the appropriate data type.
462
     *
463
     * @param   string  $key
464
     * @param   mixed   $value
465
     * @return  mixed
466
     */
467
    protected function convertAttributeValue($key, $value)
468
    {
469
        return $this->store->convertAttributeValue($this->getDataType($key), $value);
470
    }
471
472
    /**
473
     * Does a dirty check and sets the state to this model.
474
     *
475
     * @return  self
476
     */
477
    protected function doDirtyCheck()
478
    {
479
        $this->getState()->setDirty($this->isDirty());
480
        return $this;
481
    }
482
483
    /**
484
     * Removes properties marked as non-saved.
485
     *
486
     * @param   array   $properties
487
     * @return  array
488
     */
489
    protected function filterNotSavedProperties(array $properties)
490
    {
491 View Code Duplication
        foreach ($this->getMetadata()->getAttributes() as $fieldKey => $propMeta) {
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...
492
            if (true === $propMeta->shouldSave() || !isset($properties[$fieldKey])) {
493
                continue;
494
            }
495
            unset($properties[$fieldKey]);
496
        }
497
        return $properties;
498
    }
499
500
    /**
501
     * Gets an attribute value.
502
     *
503
     * @param   string  $key    The attribute key (field) name.
504
     * @return  mixed
505
     */
506
    protected function getAttribute($key)
507
    {
508
        if (true === $this->isCalculatedAttribute($key)) {
509
            return $this->getCalculatedAttribute($key);
510
        }
511
        $this->touch();
512
        return $this->attributes->get($key);
513
    }
514
515
    /**
516
     * Gets a calculated attribute value.
517
     *
518
     * @param   string  $key    The attribute key (field) name.
519
     * @return  mixed
520
     */
521
    protected function getCalculatedAttribute($key)
522
    {
523
        $attrMeta = $this->getMetadata()->getAttribute($key);
524
        $class  = $attrMeta->calculated['class'];
525
        $method = $attrMeta->calculated['method'];
526
527
        $value = $class::$method($this);
528
        return $this->convertAttributeValue($key, $value);
529
    }
530
531
    /**
532
     * Gets a data type from an attribute key.
533
     *
534
     * @param   string  $key The attribute key.
535
     * @return  string
536
     */
537
    protected function getDataType($key)
538
    {
539
        return $this->getMetadata()->getAttribute($key)->dataType;
540
    }
541
542
    /**
543
     * Gets an embed value.
544
     *
545
     * @param   string  $key    The embed key (field) name.
546
     * @return  Embed|Collections\EmbedCollection|null
547
     */
548
    protected function getEmbed($key)
549
    {
550
        if (true === $this->isEmbedHasOne($key)) {
551
            $this->touch();
552
            return $this->hasOneEmbeds->get($key);
553
        }
554
        if (true === $this->isEmbedHasMany($key)) {
555
            $this->touch();
556
            return $this->hasManyEmbeds->get($key);
557
        }
558
        return null;
559
    }
560
561
    /**
562
     * Determines if an attribute key is calculated.
563
     *
564
     * @param   string  $key    The attribute key.
565
     * @return  bool
566
     */
567
    protected function isCalculatedAttribute($key)
568
    {
569
        if (false === $this->isAttribute($key)) {
570
            return false;
571
        }
572
        return $this->getMetadata()->getAttribute($key)->isCalculated();
573
    }
574
575
    /**
576
     * Sets an attribute value.
577
     * Will convert the value to the proper, internal PHP/Modlr data type.
578
     * Will do a dirty check immediately after setting.
579
     *
580
     * @param   string  $key    The attribute key (field) name.
581
     * @param   mixed   $value  The value to apply.
582
     * @return  self
583
     */
584
    protected function setAttribute($key, $value)
585
    {
586
        if (true === $this->isCalculatedAttribute($key)) {
587
            return $this;
588
        }
589
        $this->touch();
590
        $value = $this->convertAttributeValue($key, $value);
591
        $this->attributes->set($key, $value);
592
        $this->doDirtyCheck();
593
        return $this;
594
    }
595
596
    /**
597
     * Sets an embed value.
598
     *
599
     * @param   string      $key
600
     * @param   Embed|null  $value
601
     * @return  self
602
     */
603
    protected function setEmbed($key, $value)
604
    {
605
        if (true === $this->isEmbedHasOne($key)) {
606
            return $this->setEmbedHasOne($key, $value);
607
        }
608
        if (true === $this->isEmbedHasMany($key)) {
609
            throw new \RuntimeException('You cannot set a hasMany embed directly. Please access using pushEmbed(), clear(), and/or remove()');
610
        }
611
        return $this;
612
    }
613
614
    /**
615
     * Sets a has-one embed.
616
     *
617
     * @param   string      $key    The embed key (field) name.
618
     * @param   Embed|null  $embed  The embed to relate.
619
     * @return  self
620
     */
621 View Code Duplication
    protected function setEmbedHasOne($key, Embed $embed = null)
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...
622
    {
623
        if (null !== $embed) {
624
            $this->validateEmbedSet($key, $embed->getName());
625
        }
626
        $this->touch();
627
        $this->hasOneEmbeds->set($key, $embed);
628
        $this->doDirtyCheck();
629
        return $this;
630
    }
631
632
    /**
633
     * Touches the model.
634
     * Must be handled the the extending class.
635
     *
636
     * @param   bool    $force  Whether to force the load, even if the model is currently loaded.
637
     * @return  self
638
     */
639
    protected function touch($force = false)
640
    {
641
        return $this;
642
    }
643
644
    /**
645
     * Validates that the model type (from a Model or Collection instance) can be set to the relationship field.
646
     *
647
     * @param   string  $embedKey   The embed field key.
648
     * @param   string  $embedName  The embed name that is being set.
649
     * @return  self
650
     */
651
    protected function validateEmbedSet($embedKey, $embedName)
652
    {
653
        $embededPropMeta = $this->getMetadata()->getEmbed($embedKey);
654
        $this->getStore()->validateEmbedSet($embededPropMeta->embedMeta, $embedName);
655
        return $this;
656
    }
657
}
658