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:
1 | <?php |
||
12 | trait DynamicActionTrait |
||
13 | { |
||
14 | /** |
||
15 | * @var ArrayCollection |
||
16 | */ |
||
17 | protected $attributes; |
||
18 | |||
19 | /** |
||
20 | * @var PropertyAccessorInterface |
||
21 | */ |
||
22 | private $propertyAccessor; |
||
23 | |||
24 | /** |
||
25 | * Magic call implementation which forward to dynamic getter / setter |
||
26 | */ |
||
27 | public function __call($method, $arguments) |
||
28 | { |
||
29 | switch (true) { |
||
30 | |||
31 | // accessor ? |
||
32 | View Code Duplication | case strpos($method, 'get') === 0 : |
|
33 | return $this->_get(lcfirst(preg_filter( |
||
34 | '/^get(.+)/', '$1', $method |
||
35 | ))); |
||
36 | |||
37 | // mutator ? |
||
38 | View Code Duplication | case strpos($method, 'set') === 0 : |
|
39 | return $this->_set( |
||
40 | lcfirst(preg_filter('/^set(.+)/', '$1', $method)), |
||
41 | $arguments[0] |
||
42 | ); |
||
43 | |||
44 | default: |
||
45 | throw new \BadMethodCallException(sprintf('Method %s::%s() doesnt exists.', |
||
46 | get_class($this), |
||
47 | $method |
||
48 | )); |
||
49 | } |
||
50 | } |
||
51 | |||
52 | /** |
||
53 | * Return attribute map |
||
54 | * |
||
55 | * @return ArrayCollection |
||
56 | */ |
||
57 | private function getAttributes() |
||
58 | { |
||
59 | $this->attributes = $this->attributes ?: new ArrayCollection(); |
||
60 | |||
61 | return $this->attributes; |
||
62 | } |
||
63 | |||
64 | /** |
||
65 | * Return internal property accessor |
||
66 | * |
||
67 | * @return PropertyAccessorInterface |
||
68 | */ |
||
69 | private function getPropertyAccessor() |
||
70 | { |
||
71 | $this->propertyAccessor = $this->propertyAccessor ?: |
||
72 | PropertyAccess::createPropertyAccessor() |
||
73 | ; |
||
74 | |||
75 | return $this->propertyAccessor; |
||
76 | } |
||
77 | |||
78 | /** |
||
79 | * Returns data under given key, null if undefined |
||
80 | * |
||
81 | * @param string $key |
||
82 | * |
||
83 | * @return mixed |
||
84 | */ |
||
85 | protected function _get($key) |
||
86 | { |
||
87 | return $this->getAttributes()->get($key); |
||
88 | } |
||
89 | |||
90 | /** |
||
91 | * Tests if given key exists |
||
92 | * |
||
93 | * @param string $key |
||
94 | * |
||
95 | * @return boolean |
||
96 | */ |
||
97 | protected function _has($key) |
||
98 | { |
||
99 | return $this->getAttributes()->containsKey($key); |
||
100 | } |
||
101 | |||
102 | /** |
||
103 | * Stores given key as given value |
||
104 | * |
||
105 | * @param string $key |
||
106 | * @param mixed $value |
||
107 | * |
||
108 | * @return self |
||
109 | */ |
||
110 | protected function _set($key, $value) |
||
111 | { |
||
112 | $this->getAttributes()->set($key, $value); |
||
113 | |||
114 | return $this; |
||
115 | } |
||
116 | |||
117 | /** |
||
118 | * Define given field on given object, if accessible |
||
119 | * |
||
120 | * @param mixed $object |
||
121 | * @param string $field |
||
122 | * |
||
123 | * @return mixed|null |
||
124 | */ |
||
125 | protected function setIfDefined($object, $field) |
||
126 | { |
||
127 | $propertyAccessor = $this->getPropertyAccessor(); |
||
128 | if (!$this->_has($field)) { |
||
129 | return $propertyAccessor->isReadable($object, $field) ? |
||
130 | $propertyAccessor->getValue($object, $field) : |
||
131 | null |
||
132 | ; |
||
133 | } |
||
134 | |||
135 | $propertyAccessor->setValue( |
||
136 | $object, |
||
137 | $field, |
||
138 | $value = $this->_get($field) |
||
139 | ); |
||
140 | |||
141 | return $value; |
||
142 | } |
||
143 | |||
144 | /** |
||
145 | * @see NormalizableInterface::getScopes() |
||
146 | */ |
||
147 | public static function getScopes() |
||
148 | { |
||
149 | return array(); |
||
150 | } |
||
151 | |||
152 | /** |
||
153 | * @see NormalizableInterface::normalize() |
||
154 | */ |
||
155 | public function normalize($scope = 'default') |
||
156 | { |
||
157 | $data = $this->getAttributes()->toArray(); |
||
158 | |||
159 | $scopes = $this->getScopes(); |
||
160 | if(empty($scopes[$scope])) { |
||
161 | return $data; |
||
162 | } |
||
163 | |||
164 | $normalizedData = array(); |
||
165 | $propertyAccessor = PropertyAccess::createPropertyAccessor(); |
||
166 | foreach ($scopes[$scope] as $field) { |
||
167 | $normalizedData[$field] = $propertyAccessor->isReadable( |
||
168 | $data, |
||
169 | $propertyPath = strpos($field, '[') === 0 ? |
||
170 | $field : |
||
171 | sprintf('[%s]', $field) |
||
172 | ) ? |
||
173 | $propertyAccessor->getValue($data, $propertyPath) : |
||
174 | null |
||
175 | ; |
||
176 | } |
||
177 | |||
178 | return $normalizedData; |
||
179 | } |
||
180 | |||
181 | /** |
||
182 | * @see NormalizableInterface::denormalize() |
||
183 | */ |
||
184 | public function denormalize(array $objectData) |
||
192 | |||
193 | /** |
||
194 | * @see SerializableInterface::serialize() |
||
195 | */ |
||
196 | public function serialize($scope = 'default', PropertyAccessorInterface $propertyAccessor = null) |
||
197 | { |
||
198 | @trigger_error(sprintf('The method %s() is deprecated and will be removed in 2.0. Use normalize() instead.', __METHOD__), E_USER_DEPRECATED); |
||
199 | |||
200 | return $this->normalize($scope); |
||
201 | } |
||
202 | |||
203 | /** |
||
204 | * @see SerializableInterface::deserialize() |
||
205 | */ |
||
206 | public function deserialize(array $data, PropertyAccessorInterface $propertyAccessor = null) |
||
212 | } |
||
213 |
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.