Completed
Pull Request — master (#25)
by Luke
02:15
created

ObjectCollection::join()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 1
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * Nozavroni/Collections
5
 * Just another collections library for PHP5.6+.
6
 *
7
 * @copyright Copyright (c) 2016 Luke Visinoni <[email protected]>
8
 * @author    Luke Visinoni <[email protected]>
9
 * @license   https://github.com/nozavroni/collections/blob/master/LICENSE The MIT License (MIT)
10
 */
11
namespace Noz\Collection;
12
13
use BadMethodCallException;
14
use InvalidArgumentException;
15
16
use function Noz\is_traversable;
17
use SplObjectStorage;
18
19
/**
20
 * Class ObjectCollection.
21
 *
22
 * An object collection - stores objects.
23
 *
24
 * @package Noz\Collection
25
 */
26
class ObjectCollection extends AbstractCollection
27
{
28
    /**
29
     * The required object type.
30
     *
31
     * @var string
32
     */
33
    protected $type;
34
35
    /**
36
     * ObjectCollection constructor.
37
     *
38
     * @param array|SplObjectStorage $data An array of objects or SplObjectStorage object
0 ignored issues
show
Documentation introduced by
Should the type for parameter $data not be array|SplObjectStorage|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
39
     * @param string                 $type A class that all objects should be an instance of
0 ignored issues
show
Documentation introduced by
Should the type for parameter $type not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
40
     */
41
    public function __construct($data = null, $type = null)
42
    {
43
        if (is_null($data)) {
44
            $data = [];
45
        }
46
        $this->setRequiredType($type);
47
        parent::__construct($data);
48
    }
49
50
    /**
51
     * Set the required object type.
52
     *
53
     * If a required type is set, all objects added to this collection must be of this type.
54
     *
55
     * @param string $type The required object type
56
     *
57
     * @return $this
58
     */
59
    public function setRequiredType($type)
60
    {
61
        $this->type = $type;
62
63
        return $this;
64
    }
65
66
    /**
67
     * {@inheritdoc}
68
     */
69
    protected function prepareData($data)
70
    {
71
        if ($data instanceof SplObjectStorage) {
72
            $tmp = [];
73
            foreach ($data as $obj) {
74
                $tmp[spl_object_hash($obj)] = $obj;
75
            }
76
            // @todo Data is potentially still lost even though I copy all the objects from the SplObjectStorage object.
77
            // These objects store not only objects, but also data associated with that object. That data is lost here.
78
            $data = $tmp;
79
        }
80
        return $data;
81
    }
82
83
    /**
84
     * Is correct input data type?
85
     *
86
     * @param mixed $data The data to assert correct type of
87
     *
88
     * @return bool
89
     */
90
    protected function isConsistentDataStructure($data)
91
    {
92
        // this collection may only contain scalar or null values
93
        if (!is_traversable($data)) {
94
            return false;
95
        }
96
        foreach ($data as $key => $val) {
97
            try {
98
                $this->assertValidType($val);
99
            } catch (InvalidArgumentException $e) {
100
                return false;
101
            }
102
        }
103
104
        return true;
105
    }
106
107
    /**
108
     * Assert a value is of valid type.
109
     *
110
     * @param mixed $value The value to check type of
111
     * @throws InvalidArgumentException
112
     */
113
    protected function assertValidType($value)
114
    {
115
        if (is_object($value)) {
116
            if (is_null($this->type)) {
117
                return;
118
            }
119
            if ($value instanceof $this->type) {
120
                return;
121
            }
122
            throw new InvalidArgumentException(sprintf(
123
                'Invalid object type "%s", expecting "%s".',
124
                get_class($value),
125
                $this->type
126
            ));
127
        }
128
        throw new InvalidArgumentException('Invalid value type: "' . gettype($value) . '". Expecting an object.');
129
    }
130
131
    /**
132
     * {@inheritdoc}
133
     */
134
//    public function __toString()
0 ignored issues
show
Unused Code Comprehensibility introduced by
39% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
135
//    {
136
//        // @todo __toString is not supposed to throw an exception. I need to remove __toString
137
//        // from AbstractCollection and only use it on collections where it makes sense, such as
138
//        // CharCollection and the like...
139
//        throw new BadMethodCallException(sprintf(
140
//            'Objects of type, "%s" cannot be converted to a string.',
141
//            __CLASS__
142
//        ));
143
//    }
144
145
    /**
146
     * {@inheritdoc}
147
     */
148
    public function join($delimiter = '')
149
    {
150
        // @todo I need to remove join
151
        // from AbstractCollection and only use it on collections where it makes sense, such as
152
        // CharCollection and the like...
153
        throw new BadMethodCallException(sprintf(
154
            'Objects of type, "%s" cannot be converted to a string.',
155
            __CLASS__
156
        ));
157
    }
158
159
    /**
160
     * {@inheritdoc}
161
     */
162
    public function set($index, $val)
163
    {
164
        $this->assertValidType($val);
165
        return parent::set($index, $val);
166
    }
167
168
    /**
169
     * {@inheritdoc}
170
     */
171
    public function push(...$items)
172
    {
173
        foreach ($items as $item) {
174
            $this->assertValidType($item);
175
        }
176
        return parent::push(...$items);
177
    }
178
179
    /**
180
     * {@inheritdoc}
181
     */
182
    public function unshift(...$items)
183
    {
184
        foreach ($items as $item) {
185
            $this->assertValidType($item);
186
        }
187
        return parent::unshift(...$items);
188
    }
189
190
    /**
191
     * Pad this collection to a certain size.
192
     *
193
     * Returns a new collection, padded to the given size, with clones of the given object.
194
     *
195
     * @param int    $size The number of items that should be in the collection
196
     * @param object $with The value to pad the collection with
0 ignored issues
show
Documentation introduced by
Should the type for parameter $with not be object|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
197
     *
198
     * @return ObjectCollection
199
     */
200
    public function pad($size, $with = null)
201
    {
202
        $this->assertValidType($with);
203
        $data = $this->data;
204
        if (($count = count($data)) < $size) {
205
            while($count < $size) {
206
                $with = clone $with;
207
                $count = array_push($data, $with);
208
            }
209
        }
210
        return new self($data);
211
    }
212
}
213