Completed
Pull Request — 2.0 (#62)
by
unknown
05:20
created

FlexibleContainer::fields()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 24
rs 8.5125
cc 5
eloc 14
nc 4
nop 1
1
<?php
2
/*
3
 * This file is part of the PommProject/ModelManager package.
4
 *
5
 * (c) 2014 - 2015 Grégoire HUBERT <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace PommProject\ModelManager\Model\FlexibleEntity;
11
12
use PommProject\Foundation\Inflector;
13
use PommProject\ModelManager\Exception\ModelException;
14
15
/**
16
 * FlexibleContainerTrait
17
 *
18
 * Trait for being a flexible data container.
19
 *
20
 * @package   ModelManager
21
 * @copyright 2014 - 2015 Grégoire HUBERT
22
 * @author    Grégoire HUBERT
23
 * @license   X11 {@link http://opensource.org/licenses/mit-license.php}
24
 */
25
abstract class FlexibleContainer implements FlexibleEntityInterface, \IteratorAggregate
26
{
27
    use StatefulEntityTrait;
28
29
    protected $container = [];
30
31
    /**
32
     * hydrate
33
     *
34
     * @see FlexibleEntityInterface
35
     */
36
    public function hydrate(array $values)
37
    {
38
        $this->container = array_merge($this->container, $values);
39
40
        return $this;
41
    }
42
43
    /**
44
     * fields
45
     *
46
     * Return the fields array. If a given field does not exist, an exception
47
     * is thrown.
48
     *
49
     * @throws  \InvalidArgumentException
50
     * @see     FlexibleEntityInterface
51
     */
52
    public function fields(array $fields = null)
53
    {
54
        if ($fields === null) {
55
            return $this->container;
56
        }
57
58
        $output = [];
59
60
        foreach ($fields as $name) {
61
            if (isset($this->container[$name]) || array_key_exists($name, $this->container)) {
62
                $output[$name] = $this->container[$name];
63
            } else {
64
                throw new \InvalidArgumentException(
65
                    sprintf(
66
                        "No such field '%s'. Existing fields are {%s}",
67
                        $name,
68
                        join(', ', array_keys($this->container))
69
                    )
70
                );
71
            }
72
        }
73
74
        return $output;
75
    }
76
77
78
    /**
79
     * extract
80
     *
81
     * @see FlexibleEntityInterface
82
     */
83
    public function extract()
84
    {
85
        return $this->fields();
86
    }
87
88
    /**
89
     * getIterator
90
     *
91
     * @see FlexibleEntityInterface
92
     */
93
    public function getIterator()
94
    {
95
        return new \ArrayIterator($this->extract());
96
    }
97
98
    /**
99
     * __call
100
     *
101
     * Allows dynamic methods getXxx, setXxx, hasXxx or clearXxx.
102
     *
103
     * @access public
104
     * @throws ModelException if method does not exist.
105
     * @param  mixed $method
106
     * @param  mixed $arguments
107
     * @return mixed
108
     */
109
    public function __call($method, $arguments)
110
    {
111
        list($operation, $attribute) = $this->extractMethodName($method);
112
113
        switch ($operation) {
114
        case 'set':
115
            $this->container[$attribute] = $arguments[0];
116
117
            return $this;
118
        case 'get':
119
            return $this
120
                ->checkAttribute($attribute)
121
                ->container[$attribute]
122
                ;
123
        case 'has':
124
            return isset($this->container[$attribute]) || array_key_exists($attribute, $this->container);
125
        case 'clear':
126
            unset($this->checkAttribute($attribute)->container[$attribute]);
127
128
            return $this;
129
        default:
130
            throw new ModelException(sprintf('No such method "%s:%s()"', get_class($this), $method));
131
        }
132
    }
133
134
    /**
135
     * checkAttribute
136
     *
137
     * Check if the attribute exist. Throw an exception if not.
138
     *
139
     * @access protected
140
     * @param  string $attribute
141
     * @return FlexibleContainer    $this
142
     * @throws ModelException
143
     */
144
    protected function checkAttribute($attribute)
145
    {
146
        if (!(isset($this->container[$attribute]) || array_key_exists($attribute, $this->container))) {
147
            throw new ModelException(
148
                sprintf(
149
                    "No such attribute '%s'. Available attributes are {%s}",
150
                    $attribute,
151
                    join(", ", array_keys($this->fields()))
152
                )
153
            );
154
        }
155
156
        return $this;
157
    }
158
159
    /**
160
     * extractMethodName
161
     *
162
     * Get container field name from method name.
163
     * It returns an array with the operation (get, set, etc.) as first member
164
     * and the name of the attribute as second member.
165
     *
166
     * @access protected
167
     * @param  string   $argument
168
     * @return array
169
     * @throws ModelException
170
     */
171
    protected function extractMethodName($argument)
172
    {
173
        $split = preg_split('/(?=[A-Z])/', $argument, 2);
174
175
        if (count($split) !== 2) {
176
            throw new ModelException(sprintf('No such argument "%s:%s()"', get_class($this), $argument));
177
        }
178
179
        return [$split[0], Inflector::underscore($split[1])];
180
    }
181
}
182