Complex classes like AbstractMapper often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use AbstractMapper, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
18 | class AbstractMapper implements |
||
19 | DbAdapterAwareInterface, |
||
20 | ServiceLocatorAwareInterface, |
||
21 | ProvidesTableMetadataInterface |
||
22 | { |
||
23 | use ServiceLocatorAwareTrait; |
||
24 | use ProvidesTableMetadataTrait; |
||
25 | |||
26 | protected $hydrator; |
||
27 | protected $dbAdapter; |
||
28 | protected $model; |
||
29 | protected $tableFields; |
||
30 | protected $tableName; |
||
31 | protected $tableKeyFields; |
||
32 | protected $sql; |
||
33 | protected $usePaginator; |
||
34 | protected $paginatorOptions; |
||
35 | protected $enabledOnly = false; |
||
36 | |||
37 | 34 | public function getSelect($tableName = null) |
|
41 | |||
42 | 2 | public function getAll() |
|
43 | { |
||
44 | 2 | $select = $this->getSelect(); |
|
45 | 2 | return $this->selectManyModels($select); |
|
46 | } |
||
47 | |||
48 | 10 | public function find(array $data) |
|
49 | { |
||
50 | 10 | $select = $this->getSelect() |
|
51 | 10 | ->where($data); |
|
52 | 10 | return $this->selectOneModel($select); |
|
53 | } |
||
54 | |||
55 | public function findMany(array $data) |
||
56 | { |
||
57 | $select = $this->getSelect() |
||
58 | ->where($data); |
||
59 | return $this->selectManyModels($select); |
||
60 | } |
||
61 | |||
62 | 2 | public function findRow(array $data) |
|
63 | { |
||
64 | 2 | $select = $this->getSelect() |
|
65 | 2 | ->where($data); |
|
66 | 2 | return $this->selectOne($select); |
|
67 | 1 | } |
|
68 | |||
69 | public function findRows(array $data) |
||
70 | { |
||
71 | $select = $this->getSelect() |
||
72 | ->where($data); |
||
73 | return $this->select($select); |
||
74 | } |
||
75 | |||
76 | //return array or null |
||
|
|||
77 | 35 | public function select(Select $select, ResultSet\ResultSetInterface $resultSet = null) |
|
78 | { |
||
79 | 35 | $stmt = $this->getSql()->prepareStatementForSqlObject($select); |
|
80 | |||
81 | 35 | $resultSet = $resultSet ?: new ResultSet\ResultSet(ResultSet\ResultSet::TYPE_ARRAY); |
|
82 | 35 | $resultSet->initialize($stmt->execute()); |
|
83 | |||
84 | 34 | return $resultSet; |
|
85 | } |
||
86 | |||
87 | //return deleted nuber of rows |
||
88 | 1 | public function delete(array $where, $tableName = null) |
|
89 | { |
||
90 | 1 | $tableName = $tableName ?: $this->getTableName(); |
|
91 | 1 | $sql = $this->getSql(); |
|
92 | 1 | $delete = $sql->delete($tableName); |
|
93 | |||
94 | 1 | $delete->where($where); |
|
95 | |||
96 | 1 | $statement = $sql->prepareStatementForSqlObject($delete); |
|
97 | |||
98 | 1 | return $statement->execute(); |
|
99 | } |
||
100 | |||
101 | //returns lastInsertId or null |
||
102 | 10 | public function insert($dataOrModel, $tableName = null, HydratorInterface $hydrator = null) |
|
103 | { |
||
104 | 10 | $tableName = $tableName ?: $this->getTableName(); |
|
105 | 9 | $data = $this->extract($dataOrModel, $hydrator); |
|
106 | |||
107 | 9 | if ($tableName === $this->getTableName()) { |
|
108 | 4 | $data = $this->cleanData($data); |
|
109 | 4 | } |
|
110 | |||
111 | 9 | if ($tableName === $this->getTableName() && $this->findRow($this->dataToKeyData($data))) { |
|
112 | throw new \RuntimeException('row already exists'); |
||
113 | } |
||
114 | |||
115 | 8 | $sql = $this->getSql(); |
|
116 | 7 | $insert = $sql->insert($tableName); |
|
117 | |||
118 | 7 | $insert->values($data); |
|
119 | |||
120 | 7 | $statement = $sql->prepareStatementForSqlObject($insert); |
|
121 | 7 | $result = $statement->execute(); |
|
122 | |||
123 | 5 | return $result->getGeneratedValue(); |
|
124 | } |
||
125 | |||
126 | 4 | public function dataToKeyData($data) |
|
127 | { |
||
128 | 4 | if (!is_array($this->getTableKeyFields())) { |
|
129 | throw new \RuntimeException('no key fields for:' . $this->getTableName()); |
||
130 | } |
||
131 | 4 | foreach ($this->getTableKeyFields() as $field) { |
|
132 | 4 | $return[$field] = $data[$field]; |
|
133 | 2 | } |
|
134 | 2 | return $return; |
|
135 | } |
||
136 | |||
137 | //returns affected number of rows |
||
138 | 4 | public function update($dataOrModel, array $where, $tableName = null, HydratorInterface $hydrator = null) |
|
139 | { |
||
140 | 4 | $tableName = $tableName ?: $this->getTableName(); |
|
141 | 4 | $data = $this->extract($dataOrModel, $hydrator); |
|
142 | 4 | if ($tableName === $this->getTableName()) { |
|
143 | 2 | $data = $this->cleanData($data); |
|
144 | 2 | } |
|
145 | |||
146 | 4 | $sql = $this->getSql(); |
|
147 | 4 | $update = $sql->update($tableName); |
|
148 | |||
149 | 4 | $update->set($data) |
|
150 | 4 | ->where($where); |
|
151 | |||
152 | 4 | $statement = $sql->prepareStatementForSqlObject($update); |
|
153 | |||
154 | 4 | return $statement->execute(); |
|
155 | } |
||
156 | |||
157 | //returns row or null |
||
158 | 21 | public function selectOne(Select $select, ResultSet\ResultSetInterface $resultSet = null) |
|
159 | { |
||
160 | 21 | $select->limit(1); |
|
161 | //var_dump($select->getSqlString()); die(); |
||
162 | 21 | return $this->select($select, $resultSet)->current(); |
|
163 | } |
||
164 | |||
165 | //returns array of rows |
||
166 | 15 | public function selectMany(Select $select, ResultSet\ResultSetInterface $resultSet = null) |
|
167 | { |
||
168 | 15 | if ($this->usePaginator) { |
|
169 | 1 | $this->usePaginator = false; |
|
170 | 1 | $rows = $this->initPaginator($select, $resultSet); |
|
171 | 1 | } else { |
|
172 | 14 | $result = $this->select($select, $resultSet); |
|
173 | 13 | $rows = array(); |
|
174 | 13 | foreach ($result as $row) { |
|
175 | 13 | $rows[] = $row; |
|
176 | 13 | } |
|
177 | } |
||
178 | 14 | return $rows; |
|
179 | } |
||
180 | |||
181 | //returns model or null |
||
182 | 11 | public function selectOneModel(Select $select, HydratorInterface $hydrator = null, AbstractModel $model = null) |
|
183 | { |
||
184 | 11 | $resultSet = new ResultSet\HydratingResultSet($this->getHydrator(), $this->getModel()); |
|
185 | 11 | return $this->selectOne($select, $resultSet); |
|
186 | } |
||
187 | |||
188 | //returns array of models |
||
189 | 14 | public function selectManyModels(Select $select, HydratorInterface $hydrator = null, AbstractModel $model = null) |
|
190 | { |
||
191 | 14 | $resultSet = new ResultSet\HydratingResultSet($this->getHydrator(), $this->getModel()); |
|
192 | 14 | return $this->selectMany($select, $resultSet); |
|
193 | } |
||
194 | |||
195 | 13 | public function extract($dataOrModel, HydratorInterface $hydrator = null) |
|
196 | { |
||
197 | 13 | if (is_array($dataOrModel)) { |
|
198 | 10 | return $dataOrModel; |
|
199 | } |
||
200 | 3 | if (!$dataOrModel instanceof AbstractModel) { |
|
201 | throw new \InvalidArgumentException('need nstance of AbstractModel got: ' . getType($dataOrModel)); |
||
202 | } |
||
203 | 3 | $hydrator = $hydrator ?: $this->getHydrator(); |
|
204 | 3 | return $hydrator->extract($dataOrModel); |
|
205 | } |
||
206 | |||
207 | 6 | public function cleanData($data) |
|
208 | { |
||
209 | 6 | if (!is_array($this->getTableFields()) || !count($this->getTableFields())) { |
|
210 | return $data; |
||
211 | } |
||
212 | 6 | foreach ($data as $key => $val) { |
|
213 | 6 | if (!in_array($key, $this->getTableFields())) { |
|
214 | unset($data[$key]); |
||
215 | } |
||
216 | 6 | } |
|
217 | 6 | return $data; |
|
218 | } |
||
219 | |||
220 | public function hydrate(array $data, AbstractModel $model = null, HydratorInterface $hydrator = null) |
||
221 | { |
||
222 | $hydrator = $hydrator ?: $this->getHydrator(); |
||
223 | $model = $model ?: $this->getModel(); |
||
224 | |||
225 | return $hydrator->hydrate($data, $model); |
||
226 | } |
||
227 | |||
228 | 1 | public function initPaginator($select, ResultSet\ResultSetInterface $resultSet = null) |
|
229 | { |
||
230 | 1 | $paginator = new Paginator(new PaginatorDbSelect($select, $this->getDbAdapter(), $resultSet)); |
|
231 | |||
232 | 1 | $options = $this->getPaginatorOptions(); |
|
233 | 1 | if (isset($options['n'])) { |
|
234 | 1 | $paginator->setItemCountPerPage($options['n']); |
|
235 | 1 | } |
|
236 | 1 | if (isset($options['p'])) { |
|
237 | 1 | $paginator->setCurrentPageNumber($options['p']); |
|
238 | 1 | } |
|
239 | |||
240 | 1 | return $paginator; |
|
241 | } |
||
242 | |||
243 | /** |
||
244 | * @return hydrator |
||
245 | */ |
||
246 | 28 | public function getHydrator() |
|
247 | { |
||
248 | 28 | if (is_string($this->hydrator) && class_exists($this->hydrator)) { |
|
249 | return new $this->hydrator(); |
||
250 | } else { |
||
251 | 28 | return new ClassMethods(); |
|
252 | } |
||
253 | } |
||
254 | |||
255 | /** |
||
256 | * @param $hydrator |
||
257 | * @return self |
||
258 | */ |
||
259 | public function setHydrator(HydratorInterface $hydrator) |
||
260 | { |
||
261 | $this->hydrator = $hydrator; |
||
262 | return $this; |
||
263 | } |
||
264 | |||
265 | /** |
||
266 | * @return model |
||
267 | */ |
||
268 | 25 | public function getModel(array $data = null) |
|
269 | { |
||
270 | 25 | if (is_string($this->model) && class_exists($this->model)) { |
|
271 | 25 | if ($data) { |
|
272 | $hydrator = $this->getHydrator(); |
||
273 | return $hydrator->hydrate($data, new $this->model); |
||
274 | } |
||
275 | 25 | return new $this->model; |
|
276 | } else { |
||
277 | throw new \RuntimeException('could not instantiate model - ' . $this->model); |
||
278 | } |
||
279 | } |
||
280 | |||
281 | /** |
||
282 | * @param $model |
||
283 | * @return self |
||
284 | */ |
||
285 | public function setModel(AbstractModel $model) |
||
286 | { |
||
287 | $this->model = $model; |
||
288 | return $this; |
||
289 | } |
||
290 | |||
291 | /** |
||
292 | * @return Sql |
||
293 | */ |
||
294 | 38 | protected function getSql() |
|
295 | { |
||
296 | 38 | if (!$this->sql instanceof Sql) { |
|
297 | 23 | $this->sql = new Sql($this->getDbAdapter()); |
|
298 | 23 | } |
|
299 | |||
300 | 38 | return $this->sql; |
|
301 | } |
||
302 | |||
303 | /** |
||
304 | * @param Sql |
||
305 | * @return AbstractDbMapper |
||
306 | */ |
||
307 | protected function setSql(Sql $sql) |
||
308 | { |
||
309 | $this->sql = $sql; |
||
310 | return $this; |
||
311 | } |
||
312 | |||
313 | 1 | public function usePaginator(array $paginatorOptions = array()) |
|
314 | { |
||
315 | 1 | $this->usePaginator = true; |
|
316 | 1 | $this->paginatorOptions = $paginatorOptions; |
|
317 | 1 | return $this; |
|
318 | } |
||
319 | |||
320 | /** |
||
321 | * @return paginatorOptions |
||
322 | */ |
||
323 | 2 | public function getPaginatorOptions() |
|
327 | |||
328 | /** |
||
329 | * @param $paginatorOptions |
||
330 | * @return self |
||
331 | */ |
||
332 | 1 | public function setPaginatorOptions($paginatorOptions) |
|
333 | { |
||
334 | 1 | $this->paginatorOptions = $paginatorOptions; |
|
335 | 1 | return $this; |
|
336 | } |
||
337 | |||
338 | /** |
||
339 | * @return dbAdapter |
||
340 | */ |
||
341 | 23 | public function getDbAdapter() |
|
345 | |||
346 | /** |
||
347 | * @param $dbAdapter |
||
348 | * @return self |
||
349 | */ |
||
350 | 28 | public function setDbAdapter(Adapter $dbAdapter) |
|
351 | { |
||
352 | 28 | $this->dbAdapter = $dbAdapter; |
|
353 | 28 | return $this; |
|
354 | } |
||
355 | |||
356 | /** |
||
357 | * @return tableName |
||
358 | */ |
||
359 | 40 | public function getTableName() |
|
363 | |||
364 | /** |
||
365 | * @param $tableName |
||
366 | * @return self |
||
367 | */ |
||
368 | 1 | public function setTableName($tableName) |
|
369 | { |
||
370 | 1 | $this->tableName = $tableName; |
|
371 | 1 | return $this; |
|
372 | } |
||
373 | |||
374 | /** |
||
375 | * @return tableFields |
||
376 | */ |
||
377 | 6 | public function getTableFields() |
|
381 | |||
382 | /** |
||
383 | * @param $tableFields |
||
384 | * @return self |
||
385 | */ |
||
386 | public function setTableFields($tableFields) |
||
387 | { |
||
388 | $this->tableFields = $tableFields; |
||
389 | return $this; |
||
390 | } |
||
391 | |||
392 | /** |
||
393 | * @return tableKeyFields |
||
394 | */ |
||
395 | 4 | public function getTableKeyFields() |
|
399 | |||
400 | /** |
||
401 | * @param $tableKeyFields |
||
402 | * @return self |
||
403 | */ |
||
404 | public function setTableKeyFields($tableKeyFields) |
||
405 | { |
||
406 | $this->tableKeyFields = $tableKeyFields; |
||
407 | return $this; |
||
408 | } |
||
409 | |||
410 | 4 | public function enabledOnly() |
|
414 | |||
415 | public function setEnabledOnly($bool) |
||
416 | { |
||
417 | $this->enabledOnly = $bool; |
||
418 | return $this; |
||
419 | } |
||
420 | } |
||
421 |
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.