AbstractMappableModel   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 250
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 7
Bugs 0 Features 0
Metric Value
wmc 22
c 7
b 0
f 0
lcom 1
cbo 8
dl 0
loc 250
rs 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 19 2
A __call() 0 6 2
A populate() 0 17 4
A populateFromId() 0 7 2
A populateFromWhere() 0 10 2
A save() 0 11 2
A select() 0 19 3
A insert() 0 6 1
A update() 0 6 1
A delete() 0 12 2
A getInstance() 0 6 1
1
<?php
2
3
namespace Silk\Model;
4
5
use Collections\ArrayList;
6
use PhpDocReader\Reader;
7
use Silk\Database\TableGateway;
8
use Silk\Exceptions\NoDataFoundException;
9
use Silk\Exceptions\NoPrimaryKeyException;
10
use Silk\Exchange\Extractor\Extractor;
11
use Silk\Exchange\Populator\Populator;
12
13
/**
14
 * Class AbstractMappableModel
15
 * @author  Lucas A. de Araújo <[email protected]>
16
 * @package Silk\Model
17
 */
18
abstract class AbstractMappableModel implements MappableModelInterface
19
{
20
    /**
21
     * @var TableGateway
22
     * @configure {"ignore":true}
23
     */
24
    private $tableGateway;
25
26
    /**
27
     * @var string
28
     * @configure {"ignore":true}
29
     */
30
    private $primaryKey = null;
31
32
    /**
33
     * @var mixed
34
     * @configure {"ignore":true}
35
     */
36
    private $where;
37
38
    /**
39
     * @var bool
40
     * @configure {"ignore":true}
41
     */
42
    private $lazy;
43
44
    /**
45
     * Verifica qual a estratégia de população adequada de
46
     * acordo com o parâmetro passado pelo usuário, e também
47
     * inicia as dependências da classe, bem como a definição
48
     * de seu TableGateway.
49
     *
50
     * @param null $param
51
     * @param bool $lazy
52
     * @throws NoDataFoundException
53
     * @throws NoPrimaryKeyException
54
     */
55
    public function __construct($param = null, $lazy = false)
56
    {
57
        // Define a chave primária do objeto
58
        $this->primaryKey = Reader::getConfig($this)['primary_key'];
59
60
        // Constrói o objeto de acesso aos dados.
61
        $this->tableGateway = new TableGateway($this);
62
63
        // Define o parâmetro de construção do objeto
64
        $this->where = $param;
65
66
        // Verifica se deve ser carregado apenas quando
67
        // for usado.
68
        $this->lazy = $lazy;
69
70
        // Se não for lazy load, carrega o objeto
71
        if(!$this->lazy)
72
            $this->populate($this->where);
73
    }
74
75
    /**
76
     * Esse método mágico será responsável por popular o objeto
77
     * caso a opção lazy load tenha sido definida como verdadeira.
78
     * Desse modo, os dados serão carregados só quando o objeto for
79
     * acessado pela primeira vez.
80
     *
81
     * @param $name
82
     * @param $arg
83
     */
84
    public function __call($name, $arg)
85
    {
86
        // Carrega o objeto se por lazy load
87
        if($this->lazy)
88
            $this->populate($this->where);
89
    }
90
91
    /**
92
     * Método responsável por escolher qual será a estratégia
93
     * de população do objeto. De modo a permitir três modos de
94
     * instanciação distintos: id, array, e select.
95
     *
96
     * @param $param
97
     * @throws NoDataFoundException
98
     * @throws NoPrimaryKeyException
99
     */
100
    private function populate($param)
101
    {
102
        // Se for numérico ou string, presume-se
103
        // que é uma chave primária.
104
        if(is_numeric($param) || is_string($param))
105
        {
106
            $this->populateFromId($param);
107
        }
108
109
        // Verifica se é um comando do tipo where
110
        // que pode ser usado diretamente como parâmetro
111
        // no TableGateway do Zend Framework 2.
112
        else if(!is_null($param))
113
        {
114
            $this->populateFromWhere($param);
115
        }
116
    }
117
118
    /**
119
     * Método responsável por construir o where responsável
120
     * por fazer a busca dos dados do objeto no banco através
121
     * de sua chave primária, previamente configurada na classe.
122
     *
123
     * @param $id
124
     * @throws NoDataFoundException
125
     * @throws NoPrimaryKeyException
126
     */
127
    private function populateFromId($id)
128
    {
129
        if(empty($this->primaryKey))
130
            throw new NoPrimaryKeyException();
131
132
        $this->populateFromWhere([$this->primaryKey => $id]);
133
    }
134
135
    /**
136
     * Popula o objeto a partir de um comando where. Ou
137
     * lança uma exception caso nenhum tipo de dado tenha
138
     * sido encontrado no banco de dados, a modo de corresponder
139
     * com a busca.
140
     *
141
     * @param $where
142
     * @throws NoDataFoundException
143
     */
144
    private function populateFromWhere($where)
145
    {
146
        $resultSet = $this->tableGateway->select($where);
147
148
        if($resultSet->count() == 0)
149
            throw new NoDataFoundException();
150
151
        $array = $resultSet->toArray()[0];
152
        Populator::populate($this, $array);
153
    }
154
155
    /**
156
     * Método responsável por salvar um objeto no banco de dados
157
     * verificando qual é a estratégia ideal. Se o objeto tiver
158
     * uma chave primária definida, ele será atualizado, caso não
159
     * houve nenhuma, será inserido um novo registro no banco.
160
     *
161
     * @return int
162
     */
163
    public function save()
164
    {
165
        if(empty($this->getId()))
166
        {
167
            return $this->insert();
168
        }
169
        else
170
        {
171
            return $this->update();
172
        }
173
    }
174
175
    /**
176
     * Seleciona uma coleção de objetos do tipo do objeto que fora
177
     * chamado. O método irá identificar qual a classe filho dessa
178
     * classe atual, e instanciar um objeto do tipo da classe filho
179
     * e em seguida popular ele e adicioná-lo na lista de dados.
180
     *
181
     * @param $where
182
     * @return ArrayList
183
     * @throws NoDataFoundException
184
     */
185
    public static function select($where)
186
    {
187
        $table = new TableGateway(self::getInstance());
188
        $resultSet = $table->select($where);
189
190
        if($resultSet->count() == 0)
191
            throw new NoDataFoundException();
192
193
        $list = new ArrayList();
194
195
        foreach($resultSet->toArray() as $array)
196
        {
197
            $obj = self::getInstance();
198
            Populator::populate($obj, $array);
199
            $list->add($obj);
200
        }
201
202
        return $list;
203
    }
204
205
    /**
206
     * Insere um registro no banco de dados usando o método insert
207
     * do TableGateway do Zend Framework 2. O processo de inserção
208
     * é executado apenas depois de os dados dos objeto serem adequadamente
209
     * extraídos levando em consideração as configurações disponíveis.
210
     *
211
     * @return int
212
     */
213
    private function insert()
214
    {
215
        $result = $this->tableGateway->insert(Extractor::extract($this));
216
        $this->setId($this->tableGateway->getLastInsertValue());
217
        return $result;
218
    }
219
220
    /**
221
     * Atualiza um registro no banco de dados usando o método update
222
     * do TableGateway do Zend Framework 2. O processo de atualização
223
     * é executado apenas depois de os dados dos objeto serem adequadamente
224
     * extraídos levando em consideração as configurações disponíveis.
225
     *
226
     * @return int
227
     */
228
    private function update()
229
    {
230
        return $this->tableGateway->update(Extractor::extract($this), [
231
            $this->primaryKey => $this->getId()
232
        ]);
233
    }
234
235
    /**
236
     * Remove um objeto do banco de dados através de sua chave primária.
237
     * Caso a sua chave primária não exista, o objeto do banco de dados
238
     * será excluído tendo como where, toda sua estrutura.
239
     *
240
     * @return int
241
     */
242
    public function delete()
243
    {
244
        if(!empty($this->primaryKey))
245
        {
246
            return $this->tableGateway->delete([$this->primaryKey => $this->getId()]);
247
        }
248
        else
249
        {
250
            return $this->tableGateway->delete(Extractor::extract($this));
251
        }
252
253
    }
254
255
    /**
256
     * Retorna uma instância da classe que chamou o método. Será usado
257
     * para auxiliar métodos estáticos como select, update e delete.
258
     *
259
     * @return MappableModelInterface
260
     */
261
    private static function getInstance()
262
    {
263
        $name = get_called_class();
264
        $object = new $name;
265
        return $object;
266
    }
267
}