Completed
Push — master ( 213021...32ccac )
by Roberto
19s
created

Element::formater()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 5.024

Importance

Changes 0
Metric Value
dl 0
loc 18
ccs 6
cts 10
cp 0.6
rs 9.6666
c 0
b 0
f 0
cc 4
nc 4
nop 3
crap 5.024
1
<?php
2
3
namespace NFePHP\EFD\Common;
4
5
use \stdClass;
6
use NFePHP\Common\Strings;
7
use Exception;
8
use function Safe\json_decode;
9
use function Safe\json_encode;
10
use function Safe\preg_match;
11
12
abstract class Element
13
{
14
15
    public $std;
16
    public $values;
17
    protected $parameters;
18
    private $reg;
19
    
20
    /**
21
     * Constructor
22
     * @param string $reg
23
     */
24 9
    public function __construct($reg)
25
    {
26 9
        $this->reg = $reg;
27 9
        $this->values = new stdClass();
28 9
    }
29
30
    public function postValidation()
31
    {
32
        return true;
33
    }
34
    
35
    /**
36
     * Valida e ajusta os dados de entrada para os padões estabelecidos
37
     * @param \stdClass $std
38
     */
39 9
    protected function standarize(\stdClass $std)
40
    {
41 9
        if (empty($this->parameters)) {
42
            throw new Exception('Parametros não estabelecidos na classe');
43
        }
44 9
        $errors = [];
45
        //passa todos as variáveis do stdClass para minusculo
46 9
        $arr = array_change_key_case(get_object_vars($std), CASE_LOWER);
47 9
        $std = json_decode(json_encode($arr));
48
        //paga as chaves dos parametros e passa para minusculo
49 9
        $stdParam = json_decode(json_encode($this->parameters));
50 9
        $this->parameters = array_change_key_case(get_object_vars($stdParam), CASE_LOWER);
51 9
        $paramKeys = array_keys($this->parameters);
52
        //passa os paramatros com as chaves modificadas para um stdClass
53 9
        if (!$json = json_encode($this->parameters)) {
54
            throw new \RuntimeException("Falta definir os parametros ou existe erro no array");
55
        }
56 9
        $stdParam = json_decode($json);
57 9
        if ($stdParam === null) {
58
            throw new \RuntimeException("Houve uma falha na converção para stdClass");
59
        }
60
        //verifica se foram passados os dados obrigatórios
61 9
        foreach ($std as $key => $value) {
62 9
            if (!isset($stdParam->$key)) {
63
                //ignore non defined params
64
                continue;
65
            }
66 9
            if ($stdParam->$key->required && $std->$key === null) {
67 3
                $errors[] = "$key é requerido.";
68
            }
69
        }
70 9
        $newstd = new \stdClass();
71 9
        foreach ($paramKeys as $key) {
72 9
            if (!key_exists($key, $arr)) {
73
                $newstd->$key = null;
74
            } else {
75 9
                if ($std->$key === null) {
76
                    $newstd->$key = null;
77
                    continue;
78
                }
79
                //se o valor para o parametro foi passado, então validar
80 9
                $resp = $this->isFieldInError(
81 9
                    $std->$key,
82 9
                    $stdParam->$key,
83 9
                    strtoupper($key),
84 9
                    $this->reg
85
                );
86 9
                if ($resp) {
87 6
                    $errors[] = $resp;
88
                }
89
                //e formatar o dado passado
90 9
                $formated = $this->formater(
91 9
                    $std->$key,
92 9
                    $stdParam->$key->format,
93 9
                    strtoupper($key)
94
                );
95 9
                $newstd->$key = $formated;
96
            }
97
        }
98
        //se algum erro for detectado disparar um Exception
99 9
        if (!empty($errors)) {
100 6
            throw new \InvalidArgumentException(implode("\n", $errors));
101
        }
102 3
        return $newstd;
103
    }
104
105
    /**
106
     * Verifica os campos comrelação ao tipo e seu regex
107
     * @param string|integer|float $input
108
     * @param stdClass $param
109
     * @param string $fieldname
110
     * @return string|boolean
111
     */
112 9
    protected function isFieldInError($input, $param, $fieldname, $element)
113
    {
114 9
        $type = $param->type;
115 9
        $regex = $param->regex;
116 9
        if (empty($regex)) {
117
            return false;
118
        }
119 6
        switch ($type) {
120 9
            case 'integer':
121
                if (!is_integer($input)) {
122
                    return "[$this->reg] $element campo: $fieldname deve ser um valor numérico inteiro.";
123
                }
124
                break;
125 9
            case 'numeric':
126 9
                if (!is_numeric($input)) {
127 3
                    return "[$this->reg] $element campo: $fieldname deve ser um numero.";
128
                }
129 6
                break;
130
            case 'string':
131
                if (!is_string($input)) {
132
                    return "[$this->reg] $element campo: $fieldname deve ser uma string.";
133
                }
134
                break;
135
        }
136 6
        $input = (string) $input;
137 6
        if ($regex === 'email') {
138
            if (!filter_var($input, FILTER_VALIDATE_EMAIL)) {
139
                return "[$this->reg] $element campo: $fieldname Esse email [$input] está incorreto.";
140
            }
141
            return false;
142
        }
143 6
        if (!preg_match("/$regex/", $input)) {
144 3
            return "[$this->reg] $element campo: $fieldname valor incorreto [$input]. (validação: $regex)";
145
        }
146 3
        return false;
147
    }
148
149
    /**
150
     * Formata os campos float
151
     * @param string|integer|float|null $value
152
     * @param string $format
153
     * @param string $fieldname
154
     * @return int|string|float|null
155
     * @throws \InvalidArgumentException
156
     */
157 9
    protected function formater($value, $format = null, $fieldname = '')
158
    {
159 9
        if ($value === null) {
160
            return $value;
161
        }
162 9
        if (!is_numeric($value)) {
163
            //se não é numerico então permitir apenas ASCII
164 3
            return Strings::toASCII($value);
165
        }
166 6
        if (empty($format)) {
167 6
            return $value;
168
        }
169
        //gravar os valores numericos para possivel posterior validação complexa
170
        $name = strtolower($fieldname);
171
        $this->values->$name = (float) $value;
172
        
173
        return $this->numberFormat(floatval($value), $format, $fieldname);
174
    }
175
    
176
    /**
177
     * Format number
178
     * @param float $value
179
     * @param string $format
180
     * @return string
181
     * @throws \InvalidArgumentException
182
     */
183
    private function numberFormat($value, $format, $fieldname)
184
    {
185
        $n = explode('v', $format);
186
        $mdec = strpos($n[1], '-');
187
        $p = explode('.', "{$value}");
188
        $ndec = !empty($p[1]) ? strlen($p[1]) : 0; //decimal digits
189
        $nint = strlen($p[0]); //integer digits
190
        $intdig = (int) $n[0];
191
        if ($nint > $intdig) {
192
            throw new \InvalidArgumentException("[$this->reg] O [$fieldname] é maior "
193
            . "que o permitido [$format].");
194
        }
195
        if ($mdec !== false) {
196
            //is multi decimal
197
            $mm = explode('-', $n[1]);
198
            $decmin = (int) $mm[0];
199
            $decmax = (int) $mm[1];
200
            //verificar a quantidade de decimais informada
201
            //se maior ou igual ao minimo e menor ou igual ao maximo
202
            if ($ndec >= $decmin && $ndec <= $decmax) {
203
                //deixa como está
204
                return number_format($value, $ndec, ',', '');
205
            }
206
            //se menor que o minimo, formata para o minimo
207
            if ($ndec < $decmin) {
208
                return number_format($value, $decmin, ',', '');
209
            }
210
            //se maior que o maximo, formata para o maximo
211
            if ($ndec > $decmax) {
212
                return number_format($value, $decmax, ',', '');
213
            }
214
        }
215
        $decplaces = (int) $n[1];
216
        return number_format($value, $decplaces, ',', '');
217
    }
218
219
    /**
220
     * Construtor do elemento
221
     * @return string
222
     */
223 3
    protected function build()
224
    {
225 3
        $register = '';
226 3
        foreach ($this->parameters as $key => $params) {
227 3
            $register .= $this->std->$key . '|';
228
        }
229 3
        return $register;
230
    }
231
232
    /**
233
     * Retorna o elemento formatado em uma string
234
     * @return string
235
     */
236 3
    public function __toString()
237
    {
238 3
        return '|' . $this->reg . '|' . $this->build();
239
    }
240
}
241