Completed
Push — master ( 0ba58c...dd341e )
by Gabriel
07:12
created

Collection::getIndexKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Nip\Records\Collections;
4
5
use Nip\Collection as AbstractCollection;
6
use Nip\HelperBroker;
7
use Nip\Records\AbstractModels\Record as Record;
8
use Nip\Records\AbstractModels\RecordManager as Records;
9
10
/**
11
 * Class Collection
12
 * @package Nip\Records\Collections
13
 */
14
class Collection extends AbstractCollection
0 ignored issues
show
Deprecated Code introduced by
The class Nip\Collection has been deprecated with message: Use new Collection class from Nip/Collection repo

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
15
{
16
    protected $_indexKey = false;
17
18
    /**
19
     * @var Records
20
     */
21
    protected $_manager = null;
22
23
24
    /**
25
     * @param $relations
26
     */
27
    public function loadRelations($relations)
28
    {
29
        if (is_string($relations)) {
30
            $relations = func_get_args();
31
        }
32
33
        foreach ($relations as $relation) {
34
            $this->loadRelation($relation);
35
        }
36
    }
37
38
    /**
39
     * @param $name
40
     * @return Collection
41
     */
42
    public function loadRelation($name)
43
    {
44
        $relation = $this->getRelation($name);
45
        $results = $relation->getEagerResults($this);
46
        $relation->match($this, $results);
47
        return $results;
48
    }
49
50
    /**
51
     * @param $name
52
     * @return \Nip\Records\Relations\Relation|null
53
     */
54
    public function getRelation($name)
55
    {
56
        return $this->getManager()->getRelation($name);
0 ignored issues
show
Documentation Bug introduced by
The method getRelation does not exist on object<Nip\Records\AbstractModels\RecordManager>? 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...
57
    }
58
59
    /**
60
     * @return Records
61
     */
62 2
    public function getManager()
63
    {
64 2
        if ($this->_manager == null) {
65 1
            $this->initManager();
66
        }
67
68 2
        return $this->_manager;
69
    }
70
71
    /**
72
     * @param Records $manager
73
     * @return $this
74
     */
75 2
    public function setManager(Records $manager)
76
    {
77 2
        $this->_manager = $manager;
78
79 2
        return $this;
80
    }
81
82 1
    public function initManager()
83
    {
84 1
        $manager = $this->rewind()->getManager();
85 1
        $this->setManager($manager);
86 1
    }
87
88
    /**
89
     * @return string
90
     */
91
    public function toJSON()
92
    {
93
        $return = [];
94
        foreach ($this as $item) {
95
            $return = $item->toArray();
96
        }
97
98
        return json_encode($return);
99
    }
100
101
    public function save()
102
    {
103
        if (count($this) > 0) {
104
            foreach ($this as $item) {
105
                $item->save();
106
            }
107
        }
108
    }
109
110
    /**
111
     * @param Record $record
112
     * @param string $index
113
     */
114 3
    public function add($record, $index = null)
115
    {
116 3
        $index = $this->getRecordKey($record, $index);
117 3
        parent::add($record, $index);
118 3
    }
119
120
    /**
121
     * @param Record $record
122
     * @param null $index
123
     * @return bool|mixed|null
124
     */
125 3
    public function getRecordKey(Record $record, $index = null)
126
    {
127 3
        if ($index) {
128
            $index = $record->{$index};
129
        } else {
130 3
            $index = $this->getIndexKey();
131 3
            $index = $index ? $record->{$index} : $record->getPrimaryKey();
132 3
            if (!$index) {
133 2
                $index = null;
134
            }
135
        }
136 3
        return $index;
137
    }
138
139
    /**
140
     * @return bool
141
     */
142 3
    public function getIndexKey()
143
    {
144 3
        return $this->_indexKey;
145
    }
146
147
    /**
148
     * @param $key
149
     * @return mixed
150
     */
151
    public function setIndexKey($key)
152
    {
153
        return $this->_indexKey = $key;
154
    }
155
156
    /**
157
     * @param Record $record
158
     * @return bool
159
     */
160
    public function has($record)
161
    {
162
        if ($record instanceof Record) {
163
            return $this->hasRecord($record);
164
        }
165
166
        return parent::has($record);
167
    }
168
169
    /**
170
     * @param Record $record
171
     * @return bool
172
     */
173
    public function hasRecord(Record $record)
174
    {
175
        $index = $this->getRecordKey($record);
176
177
        return parent::has($index) && $this->get($index) == $record;
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (has() instead of hasRecord()). Are you sure this is correct? If so, you might want to change this to $this->has().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
178
    }
179
180
    /**
181
     * @param $record
182
     */
183
    public function remove($record)
184
    {
185
        foreach ($this as $key => $item) {
186
            if ($item == $record) {
187
                unset($this[$key]);
188
            }
189
        }
190
    }
191
192
    /**
193
     * When $each is true, each record gets it's delete() method called.
194
     * Otherwise, a delete query is built for the entire collection
195
     *
196
     * @param bool $each
197
     * @return $this
198
     */
199
    public function delete($each = false)
200
    {
201
        if (count($this) > 0) {
202
            if ($each) {
203
                foreach ($this as $item) {
204
                    $item->delete();
205
                }
206
            } else {
207
                $pk = $this->getManager()->getPrimaryKey();
208
                $pk_list = HelperBroker::get('Arrays')->pluck($this, $pk);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Nip\Helpers\AbstractHelper as the method pluck() does only exist in the following sub-classes of Nip\Helpers\AbstractHelper: Nip_Helper_Arrays. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

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

class MyUser extends 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 sub-classes 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 parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
209
210
                $query = $this->getManager()->newQuery("delete");
211
                $query->where("$pk IN ?", $pk_list);
212
                $query->execute();
213
            }
214
215
            $this->clear();
216
        }
217
218
        return $this;
219
    }
220
}
221