Partes de un enlace Web

Un enlace Web está compuesto de diferentes partes. Por ejemplo:

    
        https://wwww.chenhanhan.com:443/blog/articulo/busqueda?tema=magento&idioma=es#primer_parrafo
    
  • schema o protocol: https://
  • subdomain: www
  • domain o hostname: chenhanhan.com
  • Port: 443
  • path: blog/articulo/busqueda
  • query string separator: ?
  • query string parameter: tema=magento&idioma=es
  • fragment o hash: #primer_parrafo

Agrupando elementos:

  • host: chenhanhan:443
  • origen: https://www.chenhanhan.com:443
  • href: toda la url

Podemos usar el javascript para ver un ejemplo real, ejecutando console.table(location).

propiedad Valor
href https://www.chenhanhan.com/magento2/menu_desaparece.php#mala_configuracion_del_sistema_cache
origin https://www.chenhanhan.com
protocol https:
host www.chenhanhan.com
hostname www.chenhanhan.com
pathname /magento2/menu_desaparece.ph
hash #mala_configuracion_del_sistema_cache

Routers de Magento 2

Magento dispone de varios tipos de routers para el frontend: robots, urlrewrite, standard, cms y default. Todas las clases de routers implementan el interface \Magento\Framework\App\RouterInterface, que tiene un método obligatorio, match(). Sirve para procesar el action de la petición de la aplicación, que tiene esta estructura <front-name>/<controller-name>/<action-name>.

Tipo Clase Orden
robots \Magento\Robots\Controller\Router 10
urlrewrite \Magento\UrlRewrite\Controller\Router 20
standard \Magento\Framework\App\Router\Base 30
cms \Magento\Cms\Controller\Router 60
default \Magento\Framework\App\Router\DefaultRouter 100
routers de Magento
Diagrama de Routers de Magento - Se crea un interface con un método. Las clases que lo implementan estarán obligadas a definir el método. Lo que consigue el interface es que tengan algo en común, por ejemplo, algún método. Se generan instancias de todas las clases que hayan implementado el interface y se guardan estas instancias en una variable, que es iterada para invocar el método común.

Los Routers son almacenados en un arreglo llamado routerList del constructor de la clase \Magento\Framework\App\RouterList. Estas clases son pasadas por los ficheros xml di.xml. Por ejemplo: di.xml del Router CMS y del Router de UrlRewrite.

    
        # Ruta: app/code/Magento/Cms/etc/frontend/di.xml

        <type name="Magento\Framework\App\RouterList">
            <arguments>
                <argument name="routerList" xsi:type="array">
                    <item name="cms" xsi:type="array">
                        <item name="class" xsi:type="string">Magento\Cms\Controller\Router</item>
                        <item name="disable" xsi:type="boolean">false</item>
                        <item name="sortOrder" xsi:type="string">60</item>
                    </item>
                </argument>
            </arguments>
        </type>
        
        # Ruta: app/code/Magento/UrlRewrite/etc/frontend/di.xml
        
        <type name="Magento\Framework\App\RouterList">
            <arguments>
                <argument name="routerList" xsi:type="array">
                    <item name="urlrewrite" xsi:type="array">
                        <item name="class" xsi:type="string">Magento\UrlRewrite\Controller\Router</item>
                        <item name="disable" xsi:type="boolean">false</item>
                        <item name="sortOrder" xsi:type="string">20</item>
                    </item>
                </argument>
            </arguments>
        </type>
    

Las clases Routers de los ficheros xml serán recogidas e instanciadas.

    
        # Constructor: \Magento\Framework\App\RouterList::__construct

        public function __construct(\Magento\Framework\ObjectManagerInterface $objectManager, array $routerList)
        {
            $this->objectManager = $objectManager;
            $this->routerList = array_filter(
                $routerList,
                function ($item) {
                    return (!isset($item['disable']) || !$item['disable']) && $item['class'];
                }
            );
            uasort($this->routerList, [$this, 'compareRoutersSortOrder']);
        }

        # Método para crear objeto de los routers recogidos desde los ficheros xml.
        # \Magento\Framework\App\RouterList::getRouterInstance

        /**
         * Retrieve router instance by id
         *
         * @param string $routerId
         * @return RouterInterface
         */
        protected function getRouterInstance($routerId)
        {
            if (!isset($this->routerList[$routerId]['object'])) {
                $this->routerList[$routerId]['object'] = $this->objectManager->create(
                    $this->routerList[$routerId]['class']
                );
            }
            return $this->routerList[$routerId]['object'];
        }
    

Robots

Hace el match con las peticiones relacionadas con el fichero robots.txt, que sirve para evitar motores de búsqueda como Google o Bing indexen las páginas Webs no deseadas.

Urlrewrite

Hace el match con las rutas de urlrewrite. Son mapeos de enlaces en la base de datos, en la tabla url_rewrite.

    
        +------------------+----------------------+------+-----+---------+----------------+
        | Field            | Type                 | Null | Key | Default | Extra          |
        +------------------+----------------------+------+-----+---------+----------------+
        | url_rewrite_id   | int(10) unsigned     | NO   | PRI | NULL    | auto_increment |
        | entity_type      | varchar(32)          | NO   |     | NULL    |                |
        | entity_id        | int(10) unsigned     | NO   | MUL | NULL    |                |
        | request_path     | varchar(255)         | YES  | MUL | NULL    |                |
        | target_path      | varchar(255)         | YES  | MUL | NULL    |                |
        | redirect_type    | smallint(5) unsigned | NO   |     | 0       |                |
        | store_id         | smallint(5) unsigned | NO   | MUL | NULL    |                |
        | description      | varchar(255)         | YES  |     | NULL    |                |
        | is_autogenerated | smallint(5) unsigned | NO   | MUL | 0       |                |
        | metadata         | varchar(255)         | YES  |     | NULL    |                |
        +------------------+----------------------+------+-----+---------+----------------+
    

Hay distintos tipos de entity type: cms_page, category, product y custom.

    
        SELECT DISTINCT(entity_type) DISTINTAS_ENTIDADES_EN_URL_REWRITE FROM url_rewrite;

        +------------------------------------+
        | DISTINTAS_ENTIDADES_EN_URL_REWRITE |
        +------------------------------------+
        | cms-page                           |
        | category                           |
        | product                            |
        | custom                             |
        +------------------------------------+
    

Las redirecciones con destino a página del producto tienen el entity_type product. Las con destino a página de categorías, category. Las con destino a página cms page, cms-page. Lo demás son del tipo custom.

Standard

Hace el match con las rutas de standard. Procesa Urls que tengan este formato <front-name>/<controller-name>/<action-name>.

Cms

Hace el match con las rutas de cms.
    
        # Ruta: app/code/Magento/Cms/Controller/Router.php Implemeta de \Magento\Framework\App\RouterInterface

        public function match(\Magento\Framework\App\RequestInterface $request)
        {
            .......

            /** @var \Magento\Cms\Model\Page $page */
            $page = $this->_pageFactory->create();
            $pageId = $page->checkIdentifier($identifier, $this->_storeManager->getStore()->getId());
            if (!$pageId) {
                return null;
            }

            $request->setModuleName('cms')->setControllerName('page')->setActionName('view')->setParam('page_id', $pageId);
            $request->setAlias(\Magento\Framework\Url::REWRITE_REQUEST_PATH_ALIAS, $identifier);

            return $this->actionFactory->create(\Magento\Framework\App\Action\Forward::class);
        }

    

Default

Hace el match con las rutas de default. Procesa las Urls inválidas, las no encontradas devolviendo \Magento\Framework\App\Router\NoRouteHandler.

Partes de un enlace web frontend de Magento

Un enlace Web de Magento 2 tiene esta estructura:

    
        <store-url>/<store-code>/<front-name>/<controller-name>/<action-name>/<parameter1>/<value del parameter1>/<parameter-n>/<value del parameter-n>

        # Ejemplo
        https://ejemplo.com/hogar/agenda-2022-medida-media-21cm-x-15cm

        # El enlace real es el siguiente.
        https://ejemplo.com/hogar/catalog/product/view/id/12/category/22
    

El enlace del ejemplo es de una página de producto, el que se ve por el usuario final. Está mapeado por el router url_rewrite, mapeado en la tabla url_rewrite de la base de datos. Luego pasa por el router standard.

  • store-url: https://ejemplo.com
  • store-code: hogar
  • front-name: catalog
  • controller-name: product
  • action-name: view
  • parametro id: 12
  • parametro category: 22

El frontname catalog está definido en la ruta app/code/Magento/Catalog/etc/frontend/routes.xml.

    
        <?xml version="1.0"?>
        <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
            <router id="standard">
                <route id="catalog" frontName="catalog">
                    <module name="Magento_Catalog" />
                </route>
            </router>
        </config>
    

El controller-name es el nombre de la carpeta Product dentro de la carpeta Controller y el action-name es el nombre del fichero View.php. Todos están en el módulo Catalog de Magento.

    
    Catalog
        └─Controller
            └─Product
                │  Compare.php
                │  Gallery.php
                │  View.php
    

En el fichero View.php, hay una función llamada execute(), que será llamada cuando se accede a la página del producto.

    
        /**
         * Product view action
         *
         * @return Forward|Redirect
         */
        public function execute()
        {
            // Get initial data from request
            $categoryId = (int) $this->getRequest()->getParam('category', false);
            $productId = (int) $this->getRequest()->getParam('id');
            $specifyOptions = $this->getRequest()->getParam('options');

            if ($this->getRequest()->isPost() && $this->getRequest()->getParam(self::PARAM_NAME_URL_ENCODED)) {
                $product = $this->_initProduct();

                if (!$product) {
                    return $this->noProductRedirect();
        .....
    

Un controlador puede estar asociado a un template phtml, donde se muestra el contenido html al usuario. Esta asociación se hace a través de un fichero xml llamado layout, que relaciona el controlador y el fichero phtml. Para ello se tiene que crear un fichero en la carpeta view/frontend/layout con el nombre catalog_product_view.xml.

    

        # Nombre del fichero layout asociado al controlador.
        [identificador_del_router][controller][actioname]

        # Por ejemplo para el enlace https://ejemplo.com/hogar/catalog/product/view/id/12/category/22
        # El fichero layout tiene este nombre y está en app/code/Magento/Catalog/view/frontend/layout

        catalog_product_view.xml
    
  • catalog: es el id de la etiqueta route del fichero routes.xml
  • product: es la carpeta llamada Product en la carpeta Controller del módulo Catalog
  • view: es el fichero llamado View.php en la carpeta Catalog/Controller/Product

Partes de un enlace web admin de Magento

Referencias