KumbiaPHP/KumbiaPHP

View on GitHub
core/kumbia/router.php

Summary

Maintainability
A
1 hr
Test Coverage
<?php
/**
 * KumbiaPHP web & app Framework
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.
 *
 * @category   Kumbia
 * @package    Router
 *
 * @copyright  Copyright (c) 2005 - 2023 KumbiaPHP Team (http://www.kumbiaphp.com)
 * @license    https://github.com/KumbiaPHP/KumbiaPHP/blob/master/LICENSE   New BSD License
 */

/**
 * Clase que Actua como router del Front-Controller
 *
 * Manejo de redirecciones de peticiones
 * Contiene información referente a la url de
 * la petición ( modudo, controlador, acción, parametros, etc )
 *
 * @category   Kumbia
 * @package    Router
 */
class Router
{

    /**
     * Array estático con las variables del router
     *
     * @var array
     */
    protected static $vars = [
        // 'method'          => '', //Método usado GET, POST, ...
        // 'route'           => '', //Ruta pasada URL
        // 'module'          => '', //Nombre del módulo actual
        // 'controller'      => 'index', //Nombre del controlador actual
        // 'action'          => 'index', //Nombre de la acción actual, por defecto index
        // 'parameters'      => [], //Lista los parámetros adicionales de la URL
        // 'controller_path' => 'index'
    ];

    /**
     * Array estático con las variables del router por defecto
     * TODO: Convertir a constante
     * 
     * @var array
     */
    protected static $default = [
        'module'          => '', //Nombre del módulo actual
        'controller'      => 'index', //Nombre del controlador actual, por defecto index
        'action'          => 'index', //Nombre de la acción actual, por defecto index
        'parameters'      => [], //Lista los parámetros adicionales de la URL
        'controller_path' => 'index'
    ];

    /**
     * This is the name of router class
     * @var string
     */
    protected static $router = 'KumbiaRouter';
    //Es el router por defecto

    /**
     * Indica si esta pendiente la ejecución de una ruta por parte del dispatcher
     *
     * @var boolean
     */
    protected static $routed = false;

    /**
     * Procesamiento basico del router
     * @param string $url
     * 
     * @throws KumbiaException
     * @return void
     */
    public static function init($url)
    {
        // Se miran los parámetros por seguridad
        if (stripos($url, '/../') !== false) {
            throw new KumbiaException("Posible intento de hack en URL: '$url'");
        }
        // Si hay intento de hack TODO: añadir la ip y referer en el log
        self::$default['route'] = $url;
        //Método usado
        self::$default['method'] = $_SERVER['REQUEST_METHOD'];
    }

    /**
     * Ejecuta una url
     *
     * @param string $url
     * 
     * @throws KumbiaException
     * @return Controller
     */
    public static function execute($url)
    {
        self::init($url);
        //alias
        $router = self::$router;
        $conf   = Config::get('config.application.routes');
        //Si config.ini tiene routes activados, mira si esta routed
        if ($conf) {
            /*Esta activado el router*/
            /* This if for back compatibility*/
            if ($conf === '1') {
                $url = $router::ifRouted($url);
            } else {
                /*Es otra clase de router*/
                $router = self::$router = $conf;
            }
        }

        // Descompone la url
        self::$vars = $router::rewrite($url) + self::$default;

        // Despacha la ruta actual
        return static::dispatch($router::getController(self::$vars));
    }

    /**
     * Realiza el dispatch de la ruta actual
     * 
     * @param Controller $cont  Controlador a usar
     *
     * @throws KumbiaException
     * @return Controller
     */
    protected static function dispatch($cont)
    {
        // Se ejecutan los filtros initialize y before
        if ($cont->k_callback(true) === false) {
            return $cont;
        }

        if (method_exists($cont, $cont->action_name)) {
            if (strcasecmp($cont->action_name, 'k_callback') === 0 ) {
                throw new KumbiaException('Esta intentando ejecutar un método reservado de KumbiaPHP');
            }

            if ($cont->limit_params) { // with variadic php5.6 delete it
                $reflectionMethod = new ReflectionMethod($cont, $cont->action_name);
                $num_params = count($cont->parameters);
                
                if ($num_params < $reflectionMethod->getNumberOfRequiredParameters() ||
                    $num_params > $reflectionMethod->getNumberOfParameters()) {
                        
                    throw new KumbiaException('', 'num_params');   
                }
                        
            }
        }
        
        call_user_func_array([$cont, $cont->action_name], $cont->parameters);

        //Corre los filtros after y finalize
        $cont->k_callback();

        //Si esta routed internamente volver a ejecutar
        self::isRouted();

        return $cont;
    }

    /**
     * Redirecciona la ejecución internamente
     * 
     * @throws KumbiaException
     * @return void
     */
    protected static function isRouted()
    {
        if (self::$routed) {
            self::$routed = false;
            $router = self::$router;
            // Despacha la ruta actual
            self::dispatch($router::getController(self::$vars));
        }
    }

    /**
     * Envia el valor de un atributo o el array con todos los atributos y sus valores del router
     * Mirar el atributo vars del router
     * ej.
     * <code>Router::get()</code>
     *
     * ej.
     * <code>Router::get('controller')</code>
     *
     * @param string $var (opcional) un atributo: route, module, controller, action, parameters o routed
     * 
     * @return array|string con el valor del atributo
     */
    public static function get($var = '')
    {
        return ($var) ? static::$vars[$var] : static::$vars;
    }

    /**
     * Redirecciona la ejecución internamente o externamente con un routes propio
     *
     * @param array $params array de $vars (móddulo, controller, action, params, ...)
     * @param boolean $intern si la redirección es interna
     * 
     * @return void
     */
    public static function to(array $params, $intern = false)
    {
        if ($intern) {
            self::$routed = true;
        }
        static::$vars = $params + self::$default;
    }
}