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:
Complex classes like Sii 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 Sii, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
31 | class Sii |
||
32 | { |
||
33 | |||
34 | private static $config = [ |
||
35 | 'wsdl' => [ |
||
36 | '*' => 'https://{servidor}.sii.cl/DTEWS/{servicio}.jws?WSDL', |
||
37 | 'QueryEstDteAv' => 'https://{servidor}.sii.cl/DTEWS/services/{servicio}?WSDL', |
||
38 | 'wsDTECorreo' => 'https://{servidor}.sii.cl/DTEWS/services/{servicio}?WSDL', |
||
39 | ], |
||
40 | 'servidor' => ['palena', 'maullin'], ///< servidores 0: producción, 1: certificación |
||
41 | 'certs' => [300, 100], ///< certificados 0: producción, 1: certificación |
||
42 | ]; |
||
43 | |||
44 | const PRODUCCION = 0; ///< Constante para indicar ambiente de producción |
||
45 | const CERTIFICACION = 1; ///< Constante para indicar ambiente de desarrollo |
||
46 | |||
47 | const IVA = 19; ///< Tasa de IVA |
||
48 | |||
49 | private static $retry = 10; ///< Veces que se reintentará conectar a SII al usar el servicio web |
||
50 | private static $verificar_ssl = true; ///< Indica si se deberá verificar o no el certificado SSL del SII |
||
51 | private static $ambiente = self::PRODUCCION; ///< Ambiente que se utilizará |
||
52 | |||
53 | private static $direcciones_regionales = [ |
||
54 | 'CHILLÁN VIEJO' => 'CHILLÁN', |
||
55 | 'HUECHURABA' => 'SANTIAGO NORTE', |
||
56 | 'LA CISTERNA' => 'SANTIAGO SUR', |
||
57 | 'LAS CONDES' => 'SANTIAGO ORIENTE', |
||
58 | 'LO ESPEJO' => 'SANTIAGO SUR', |
||
59 | 'PEÑALOLÉN' => 'ÑUÑOA', |
||
60 | 'PUDAHUEL' => 'SANTIAGO PONIENTE', |
||
61 | 'RECOLETA' => 'SANTIAGO NORTE', |
||
62 | 'SANTIAGO' => 'SANTIAGO CENTRO', |
||
63 | 'SAN MIGUEL' => 'SANTIAGO SUR', |
||
64 | 'SAN VICENTE' => 'SAN VICENTE TAGUA TAGUA', |
||
65 | 'TALTAL' => 'ANTOFAGASTA', |
||
66 | 'VITACURA' => 'SANTIAGO ORIENTE', |
||
67 | 'VICHUQUÉN' => 'CURICÓ', |
||
68 | ]; /// Direcciones regionales del SII según la comuna |
||
69 | |||
70 | /** |
||
71 | * Método que permite asignar el nombre del servidor del SII que se |
||
72 | * usará para las consultas al SII |
||
73 | * @param servidor Servidor que se usará, si es https://maullin2.sii.cl, entonces se debe pasar como valor maullin2 |
||
74 | * @param certificacion Permite definir si se está cambiando el servidor de certificación o el de producción |
||
75 | * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) |
||
76 | * @version 2015-09-14 |
||
77 | */ |
||
78 | public static function setServidor($servidor = 'maullin', $certificacion = Sii::CERTIFICACION) |
||
82 | |||
83 | /** |
||
84 | * Método que entrega el nombre del servidor a usar según el ambiente |
||
85 | * @param ambiente Ambiente que se desea obtener el servidor, si es null se autodetectará |
||
86 | * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) |
||
87 | * @version 2016-08-01 |
||
88 | */ |
||
89 | public static function getServidor($ambiente = null) |
||
93 | |||
94 | /** |
||
95 | * Método que entrega la URL de un recurso en el SII según el ambiente que se esté usando |
||
96 | * @param recurso Recurso del sitio del SII que se desea obtener la URL |
||
97 | * @param ambiente Ambiente que se desea obtener el servidor, si es null se autodetectará |
||
98 | * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) |
||
99 | * @version 2017-09-11 |
||
100 | */ |
||
101 | public static function getURL($recurso, $ambiente = null) |
||
102 | { |
||
103 | return 'https://'.self::getServidor($ambiente).'.sii.cl'.$recurso; |
||
104 | } |
||
105 | |||
106 | /** |
||
107 | * Método para obtener el WSDL |
||
108 | * |
||
109 | * \code{.php} |
||
110 | * $wsdl = \sasco\LibreDTE\Sii::wsdl('CrSeed'); // WSDL para pedir semilla |
||
111 | * \endcode |
||
112 | * |
||
113 | * Para forzar el uso del WSDL de certificación hay dos maneras, una es |
||
114 | * pasando un segundo parámetro al método get con valor Sii::CERTIFICACION: |
||
115 | * |
||
116 | * \code{.php} |
||
117 | * $wsdl = \sasco\LibreDTE\Sii::wsdl('CrSeed', \sasco\LibreDTE\Sii::CERTIFICACION); |
||
118 | * \endcode |
||
119 | * |
||
120 | * La otra manera, para evitar este segundo parámetro, es asignar el valor a |
||
121 | * través de la configuración: |
||
122 | * |
||
123 | * \code{.php} |
||
124 | * \sasco\LibreDTE\Sii::setAmbiente(\sasco\LibreDTE\Sii::CERTIFICACION); |
||
125 | * \endcode |
||
126 | * |
||
127 | * @param servicio Servicio por el cual se está solicitando su WSDL |
||
128 | * @param ambiente Ambiente a usar: Sii::PRODUCCION o Sii::CERTIFICACION o null (para detección automática) |
||
129 | * @return URL del WSDL del servicio según ambiente solicitado |
||
130 | * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) |
||
131 | * @version 2016-06-11 |
||
132 | */ |
||
133 | public static function wsdl($servicio, $ambiente = null) |
||
153 | |||
154 | /** |
||
155 | * Método para realizar una solicitud al servicio web del SII |
||
156 | * @param wsdl Nombre del WSDL que se usará |
||
157 | * @param request Nombre de la función que se ejecutará en el servicio web |
||
158 | * @param args Argumentos que se pasarán al servicio web |
||
159 | * @param retry Intentos que se realizarán como máximo para obtener respuesta |
||
160 | * @return Objeto SimpleXMLElement con la espuesta del servicio web consultado |
||
161 | * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) |
||
162 | * @version 2016-08-28 |
||
163 | */ |
||
164 | public static function request($wsdl, $request, $args = null, $retry = null) |
||
222 | |||
223 | /** |
||
224 | * Método que permite indicar si se debe o no verificar el certificado SSL |
||
225 | * del SII |
||
226 | * @param verificar =true si se quiere verificar certificado, =false en caso que no (por defecto se verifica) |
||
227 | * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) |
||
228 | * @version 2015-09-16 |
||
229 | */ |
||
230 | public static function setVerificarSSL($verificar = true) |
||
234 | |||
235 | /** |
||
236 | * Método que indica si se está o no verificando el SSL en las conexiones al SII |
||
237 | * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) |
||
238 | * @version 2017-05-11 |
||
239 | */ |
||
240 | public static function getVerificarSSL() |
||
244 | |||
245 | /** |
||
246 | * Método que realiza el envío de un DTE al SII |
||
247 | * Referencia: http://www.sii.cl/factura_electronica/factura_mercado/envio.pdf |
||
248 | * @param usuario RUN del usuario que envía el DTE |
||
249 | * @param empresa RUT de la empresa emisora del DTE |
||
250 | * @param dte Documento XML con el DTE que se desea enviar a SII |
||
251 | * @param token Token de autenticación automática ante el SII |
||
252 | * @param retry Intentos que se realizarán como máximo para obtener respuesta |
||
253 | * @return Respuesta XML desde SII o bien null si no se pudo obtener respuesta |
||
254 | * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) |
||
255 | * @version 2016-08-06 |
||
256 | */ |
||
257 | public static function enviar($usuario, $empresa, $dte, $token, $retry = null) |
||
338 | |||
339 | /** |
||
340 | * Método para obtener la clave pública (certificado X.509) del SII |
||
341 | * |
||
342 | * \code{.php} |
||
343 | * $pub_key = \sasco\LibreDTE\Sii::cert(100); // Certificado IDK 100 (certificación) |
||
344 | * \endcode |
||
345 | * |
||
346 | * @param idk IDK de la clave pública del SII. Si no se indica se tratará de determinar con el ambiente que se esté usando |
||
347 | * @return Contenido del certificado |
||
348 | * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) |
||
349 | * @version 2015-09-16 |
||
350 | */ |
||
351 | public static function cert($idk = null) |
||
368 | |||
369 | /** |
||
370 | * Método que asigna el ambiente que se usará por defecto (si no está |
||
371 | * asignado con la constante _LibreDTE_CERTIFICACION_) |
||
372 | * @param ambiente Ambiente a usar: Sii::PRODUCCION o Sii::CERTIFICACION |
||
373 | * @warning No se está verificando SSL en ambiente de certificación |
||
374 | * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) |
||
375 | * @version 2016-08-28 |
||
376 | */ |
||
377 | public static function setAmbiente($ambiente = self::PRODUCCION) |
||
385 | |||
386 | /** |
||
387 | * Método que determina el ambiente que se debe utilizar: producción o |
||
388 | * certificación |
||
389 | * @param ambiente Ambiente a usar: Sii::PRODUCCION o Sii::CERTIFICACION o null (para detección automática) |
||
390 | * @return Ambiente que se debe utilizar |
||
391 | * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) |
||
392 | * @version 2015-09-07 |
||
393 | */ |
||
394 | public static function getAmbiente($ambiente = null) |
||
404 | |||
405 | /** |
||
406 | * Método que entrega la tasa de IVA vigente |
||
407 | * @return Tasa de IVA vigente |
||
408 | * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) |
||
409 | * @version 2015-09-03 |
||
410 | */ |
||
411 | public static function getIVA() |
||
415 | |||
416 | /** |
||
417 | * Método que entrega un arreglo con todos los datos de los contribuyentes |
||
418 | * que operan con factura electrónica descargados desde el SII |
||
419 | * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) |
||
420 | * @version 2017-07-07 |
||
421 | */ |
||
422 | public static function getContribuyentes(\sasco\LibreDTE\FirmaElectronica $Firma, $ambiente = null, $dia = null) |
||
479 | |||
480 | |||
481 | /** |
||
482 | * Método que entrega un arreglo con todas los documentos tributarios electrónicos |
||
483 | * recepcionados en el SII |
||
484 | * @param Firma digital del certificado |
||
485 | * @param Ambiente de prueba |
||
486 | * @param Rut empresa a consultar |
||
487 | * @param Desde fecha a consultar. Formato d-m-Y |
||
488 | * @param Hasta fecha a consultar. Formato d-m-Y |
||
489 | * @return Dirección regional del SII |
||
490 | * [0] Lin. |
||
491 | * [1] Rut del Emisor |
||
492 | * [2] Razón Social Emisor |
||
493 | * [3] Tipo Dte |
||
494 | * [4] Folio Dte |
||
495 | * [5] Fecha Emisión |
||
496 | * [6] Monto Total |
||
497 | * [7] Fecha Recepción |
||
498 | * [8] Número Envío |
||
499 | * @author Adonias Vasquez (adonias.vasquez[at]epys.cl) |
||
500 | * @version 2017-09-30 |
||
501 | */ |
||
502 | public static function getDTERecibidos(\sasco\LibreDTE\FirmaElectronica $Firma, $ambiente = null, $rut = null, $desde = null, $hasta = null) |
||
579 | /** |
||
580 | * Método que entrega la dirección regional según la comuna que se esté |
||
581 | * consultando |
||
582 | * @param comuna de la sucursal del emior o bien código de la sucursal del SII |
||
583 | * @return Dirección regional del SII |
||
584 | * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) |
||
585 | * @version 2016-06-03 |
||
586 | */ |
||
587 | public static function getDireccionRegional($comuna) |
||
595 | |||
596 | } |
||
597 |
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.