Complex classes like DAO 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 DAO, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
11 | abstract class DAO implements DAOInterface { |
||
12 | |||
13 | /** @var \PDO */ |
||
14 | protected $pdo; |
||
15 | |||
16 | /** @var string[] */ |
||
17 | protected $selectCollumns = ['*']; |
||
18 | protected $join = ''; |
||
19 | protected $primaryKey = null; |
||
20 | protected $fixedFilter = []; |
||
21 | |||
22 | /** @var boolean */ |
||
23 | public static $debug = false; |
||
24 | |||
25 | /** |
||
26 | * Valida os campos retornando string de Erro ou Null |
||
27 | * @return string|null |
||
28 | */ |
||
29 | abstract protected function validate(); |
||
30 | |||
31 | /** Inicia o DAO */ |
||
32 | public function __construct() { |
||
35 | |||
36 | /** |
||
37 | * Define uma conexão manualmente |
||
38 | * @param \PDO $pdo |
||
39 | */ |
||
40 | public function setPDO($pdo) { |
||
43 | |||
44 | /** |
||
45 | * Define quais colunas serão consultadas no SELECT |
||
46 | * @param string[] $collumns |
||
47 | */ |
||
48 | public function setSelectCollumns(array $collumns) { |
||
51 | |||
52 | /** |
||
53 | * Adiciona nova coluna no SELECT |
||
54 | * @param string $collumn |
||
55 | */ |
||
56 | public function addSelectCollumn($collumn) { |
||
61 | |||
62 | /** |
||
63 | * Salva o registro |
||
64 | * @param object $obj |
||
65 | * @return string|null |
||
66 | */ |
||
67 | public function save($obj) { |
||
91 | |||
92 | /** |
||
93 | * Executa SQL via PDO |
||
94 | * @param string $sql |
||
95 | * @param mixed[] $values |
||
96 | * @return \PDOStatement |
||
97 | */ |
||
98 | protected function execSql($sql, $values) { |
||
106 | |||
107 | /** Insere o registro */ |
||
108 | protected function insert() { |
||
117 | |||
118 | /** Atualiza o registro */ |
||
119 | protected function update() { |
||
134 | |||
135 | /** |
||
136 | * @param $stmt \PDOStatement |
||
137 | * @return string erro |
||
138 | */ |
||
139 | protected function error(\PDOStatement $stmt) { |
||
149 | |||
150 | /** |
||
151 | * Exclui o registro |
||
152 | * @param object $obj |
||
153 | */ |
||
154 | public function delete($obj) { |
||
161 | |||
162 | /** |
||
163 | * Exclui o registro por id |
||
164 | * @param int $id |
||
165 | */ |
||
166 | public function deleteById($id) { |
||
169 | |||
170 | /** |
||
171 | * Exclui o registro por id |
||
172 | * @param string $name |
||
173 | * * @param mixed $value |
||
174 | */ |
||
175 | public function deleteByField($name, $value) { |
||
178 | |||
179 | /** |
||
180 | * Exclui todos os registros |
||
181 | * @param mixed[] $filters |
||
182 | */ |
||
183 | public function deleteAll($filters = []) { |
||
194 | |||
195 | /** |
||
196 | * Busca o objeto pelo id |
||
197 | * @param int $id |
||
198 | */ |
||
199 | public function fetchById($id) { |
||
202 | |||
203 | /** |
||
204 | * Busca o objeto por um campo/atributo específico |
||
205 | * @param string $name Nome do atributo |
||
206 | * @param mixed $value Valor do atributo |
||
207 | */ |
||
208 | public function fetchByField($name, $value) { |
||
211 | |||
212 | /** |
||
213 | * Busca o objeto |
||
214 | * @param string[] $filters Array de filtros |
||
215 | * @param string $option [Order by, Limit, etc] |
||
216 | */ |
||
217 | public function fetch($filters, $option = 'ORDER BY 1 DESC') { |
||
229 | |||
230 | /** |
||
231 | * Retorna todos os registros |
||
232 | * |
||
233 | * <code> |
||
234 | * $dao->fetchAll( ['id = ?' => 10]); |
||
235 | * </code> |
||
236 | * @param string[] $filters Array de filtros |
||
237 | * @param string $option [Order by, Limit, etc] |
||
238 | */ |
||
239 | public function fetchAll($filters = [], $option = 'ORDER BY 1 DESC') { |
||
257 | |||
258 | /** |
||
259 | * Retorna comando SELECT |
||
260 | * @param string $selectCollumns |
||
261 | * @return string |
||
262 | * @example "SELECT * FROM user" |
||
263 | */ |
||
264 | protected function selectSQL($selectCollumns = ['*']) { |
||
267 | |||
268 | /** |
||
269 | * Retorna comando WHERE |
||
270 | * @param string[] $filters |
||
271 | * @return string |
||
272 | */ |
||
273 | protected function whereSQL(&$filters) { |
||
277 | |||
278 | /** |
||
279 | * Retorna o total de registros |
||
280 | * @param string[] $filters Array de filtros |
||
281 | * @param string $option |
||
282 | * @return int |
||
283 | */ |
||
284 | public function numRows($filters = [], $option = 'ORDER BY 1 DESC') { |
||
299 | |||
300 | /** |
||
301 | * Retorna True se objeto existir |
||
302 | * @return boolean |
||
303 | */ |
||
304 | protected function objExists($obj) { |
||
307 | |||
308 | /** Define como Página 404 se o objeto não existir */ |
||
309 | public function checkFoundRegistry($obj) { |
||
315 | |||
316 | /** |
||
317 | * Exibe comando SQL, se debug está habilitado |
||
318 | * @param string $sql |
||
319 | * @param mixed[] $values |
||
320 | */ |
||
321 | protected function debug($sql, $values = []) { |
||
333 | |||
334 | private function getFilterValues($filters) { |
||
337 | |||
338 | protected function beforeSave() { |
||
341 | |||
342 | protected function afterSave() { |
||
345 | |||
346 | protected function onDelete() { |
||
349 | |||
350 | /** @return string Retorna o nome da PK */ |
||
351 | private function getPrimaryKey() { |
||
357 | |||
358 | } |
||
359 |
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: