Completed
Pull Request — master (#79)
by Jacob
02:58
created

InverseCollection   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 120
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 10
c 1
b 0
f 0
lcom 1
cbo 1
dl 0
loc 120
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A clear() 0 4 1
A allWithoutLoad() 0 5 1
A getIdentifiers() 0 7 2
A getOwner() 0 4 1
A getQueryField() 0 4 1
A isDirty() 0 4 1
A push() 0 4 1
A remove() 0 4 1
1
<?php
2
3
namespace As3\Modlr\Models\Collections;
4
5
use As3\Modlr\Metadata\EntityMetadata;
6
use As3\Modlr\Models\AbstractModel;
7
use As3\Modlr\Models\Model;
8
use As3\Modlr\Store\Store;
9
10
/**
11
 * Model collection that contains record representations from a persistence (database) layer.
12
 *
13
 * @author Jacob Bare <[email protected]>
14
 */
15
class InverseCollection extends ModelCollection
16
{
17
    /**
18
     * The owning model of the inverse relationship.
19
     *
20
     * @var Model
21
     */
22
    private $owner;
23
24
    /**
25
     * The inverse relationship query field.
26
     *
27
     * @var string
28
     */
29
    private $inverseField;
30
31
    /**
32
     * {@inheritDoc}
33
     */
34
    protected $loaded = false;
35
36
    /**
37
     * {@inheritDoc}
38
     * @param   Model   $owner
39
     * @param   string  $inverseField
40
     */
41
    public function __construct(EntityMetadata $metadata, Store $store, Model $owner, $inverseField)
42
    {
43
        parent::__construct($metadata, $store, []);
44
        $this->owner = $owner;
45
        $this->inverseField = $inverseField;
46
    }
47
48
    /**
49
     * {@inheritdoc}
50
     *
51
     * Overwritten to prevent modification.
52
     *
53
     * @throws  \BadMethodCallException
54
     */
55
    public function clear()
56
    {
57
       throw new \BadMethodCallException('You cannot clear inverse collections.');
58
    }
59
60
    /**
61
     * {@inheritDoc}
62
     *
63
     * Overwritten to ensure the collection is loaded, since references aren't sent to inverse collections.
64
     */
65
    public function allWithoutLoad()
66
    {
67
        $this->loadFromStore();
68
        return parent::allWithoutLoad();
69
    }
70
71
    /**
72
     * {@inheritDoc}
73
     */
74
    public function getIdentifiers($onlyUnloaded = true)
75
    {
76
        if (true === $this->loaded) {
77
            return [];
78
        }
79
        return [$this->owner->getId()];
80
    }
81
82
    /**
83
     * Gets the model that owns this inverse collection.
84
     *
85
     * @return  Model
86
     */
87
    public function getOwner()
88
    {
89
        return $this->owner;
90
    }
91
92
    /**
93
     * {@inheritDoc}
94
     */
95
    public function getQueryField()
96
    {
97
        return $this->inverseField;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->inverseField; (string) is incompatible with the return type declared by the abstract method As3\Modlr\Models\Collect...llection::getQueryField 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...
98
    }
99
100
    /**
101
     * {@inheritDoc}
102
     *
103
     * Overwritten to always return false.
104
     *
105
     */
106
    public function isDirty()
107
    {
108
        return false;
109
    }
110
111
    /**
112
     * {@inheritdoc}
113
     *
114
     * Overwritten to prevent modification.
115
     *
116
     * @throws  \BadMethodCallException
117
     */
118
    public function push(AbstractModel $model)
119
    {
120
        throw new \BadMethodCallException('You cannot push to inverse collections.');
121
    }
122
123
    /**
124
     * {@inheritdoc}
125
     *
126
     * Overwritten to prevent modification.
127
     *
128
     * @throws  \BadMethodCallException
129
     */
130
    public function remove(AbstractModel $model)
131
    {
132
        throw new \BadMethodCallException('You cannot remove from an inverse collections.');
133
    }
134
}
135