We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Create or define custom routing placeholders

Hi all,

I wonder if is possible to create or define custom routing placeholders for my app, as described by default in routing documentation. https://docs.phalcon.io/en/latest/reference/routing.html#defining-routes

Is it possible to define a custom placeholder with a regular expression and use it as default placeholders (ex: /:params, /;int) in my app, without repeat in each route definition?

Thank you for your attention.



98.9k

Could you please post the approximate code you are expecting?



1.5k

Route declaration traditional way:

//Define a route (traditional way)
$router->add(
    '/faq/{country:[a-z]{2}}',
    array(          
        'controller' => 'main',
        'action' => 'faq'
    )
);

Is posible create a custom placeholder called country to use as well?:

//Define a route using country custom placeholder
router->add('/faq/:country',
    array(          
        'controller' => 'main',
        'action' => 'faq'
    )
);

Thank you so much for your attention and sorry for the inconvenience.



98.9k

You can define a route without the regular expression:

$router->add(
    '/faq/{country}',
    array(          
        'controller' => 'main',
        'action' => 'faq'
    )
);


1.5k
Accepted
answer
edited Jul '14

First of all thanks for your attention and quick response.

Sorry, I think I have not explained well, my question is if there is any way to create a placeholder to which you attach a regular expression for later use in the definition of the routes, being well defined regular expression in a single point of the code.

After review cphalcon extension source code, I found the function where default routing placeholders are defined (ext/mvc/router/route.c):

/**
 * Replaces placeholders from pattern returning a valid PCRE regular expression
 *
 * @param string $pattern
 * @return string
 */
PHP_METHOD(Phalcon_Mvc_Router_Route, compilePattern){

    zval *pattern, *compiled_pattern = NULL, *id_pattern;
    zval wildcard, *pattern_copy = NULL, *params_pattern;
    zval *int_pattern;

    PHALCON_MM_GROW();

    phalcon_fetch_params(1, 1, 0, &pattern);

    PHALCON_CPY_WRT(compiled_pattern, pattern);

    /** 
     * If a pattern contains ':', maybe there are placeholders to replace
     */
    if (phalcon_memnstr_str(pattern, SL(":"))) {

        /** 
         * This is a pattern for valid identifiers
         */
        PHALCON_INIT_VAR(id_pattern);
        ZVAL_STRING(id_pattern, "/([a-zA-Z0-9_-]++)", 1);

        /** 
         * Replace the module part
         */
        if (phalcon_memnstr_str(pattern, SL("/:module"))) {
            INIT_ZVAL(wildcard);
            ZVAL_STRING(&wildcard, "/:module", 0);
            PHALCON_CPY_WRT(pattern_copy, compiled_pattern);

            PHALCON_INIT_NVAR(compiled_pattern);
            phalcon_fast_str_replace(compiled_pattern, &wildcard, id_pattern, pattern_copy);
        }

        /** 
         * Replace the controller placeholder
         */
        if (phalcon_memnstr_str(pattern, SL("/:controller"))) {
            INIT_ZVAL(wildcard);
            ZVAL_STRING(&wildcard, "/:controller", 0);
            PHALCON_CPY_WRT(pattern_copy, compiled_pattern);

            PHALCON_INIT_NVAR(compiled_pattern);
            phalcon_fast_str_replace(compiled_pattern, &wildcard, id_pattern, pattern_copy);
        }

        /** 
         * Replace the namespace placeholder
         */
        if (phalcon_memnstr_str(pattern, SL("/:namespace"))) {
            INIT_ZVAL(wildcard)
            ZVAL_STRING(&wildcard, "/:namespace", 0);
            PHALCON_CPY_WRT(pattern_copy, compiled_pattern);

            PHALCON_INIT_NVAR(compiled_pattern);
            phalcon_fast_str_replace(compiled_pattern, &wildcard, id_pattern, pattern_copy);
        }

        /** 
         * Replace the action placeholder
         */
        if (phalcon_memnstr_str(pattern, SL("/:action"))) {
            INIT_ZVAL(wildcard);
            ZVAL_STRING(&wildcard, "/:action", 0);
            PHALCON_CPY_WRT(pattern_copy, compiled_pattern);

            PHALCON_INIT_NVAR(compiled_pattern);
            phalcon_fast_str_replace(compiled_pattern, &wildcard, id_pattern, pattern_copy);
        }

        /** 
         * Replace the params placeholder
         */
        if (phalcon_memnstr_str(pattern, SL("/:params"))) {
            INIT_ZVAL(wildcard);
            ZVAL_STRING(&wildcard, "/:params", 0);

            PHALCON_INIT_VAR(params_pattern);
            ZVAL_STRING(params_pattern, "(/.*+)?+", 1);
            PHALCON_CPY_WRT(pattern_copy, compiled_pattern);

            PHALCON_INIT_NVAR(compiled_pattern);
            phalcon_fast_str_replace(compiled_pattern, &wildcard, params_pattern, pattern_copy);
        }

        /** 
         * Replace the int placeholder
         */
        if (phalcon_memnstr_str(pattern, SL("/:int"))) {
            INIT_ZVAL(wildcard);
            ZVAL_STRING(&wildcard, "/:int", 0);

            PHALCON_INIT_VAR(int_pattern);
            ZVAL_STRING(int_pattern, "/([0-9]++)", 1);
            PHALCON_CPY_WRT(pattern_copy, compiled_pattern);

            PHALCON_INIT_NVAR(compiled_pattern);
            phalcon_fast_str_replace(compiled_pattern, &wildcard, int_pattern, pattern_copy);
        }
    }

    /** 
     * Check if the pattern has parantheses in order to add the regex delimiters
     */
    if (phalcon_memnstr_str(compiled_pattern, SL("("))) {
        PHALCON_CONCAT_SVS(return_value, "#^", compiled_pattern, "$#");
        RETURN_MM();
    }

    /** 
     * Square brackets are also checked
     */
    if (phalcon_memnstr_str(compiled_pattern, SL("["))) {
        PHALCON_CONCAT_SVS(return_value, "#^", compiled_pattern, "$#");
        RETURN_MM();
    }

    RETURN_CCTOR(compiled_pattern);
}

After review this code I think that creating a class CustomRoute that inherits from \Phalcon\Mvc\Router\Route class, overriding the method compilePattern to replace custom placeholders for its associated regular expressions, and using this class for routing, could answer my question:


class CustomRoute extends \Phalcon\Mvc\Router\Route
{

    /**
     * Replaces placeholders from pattern returning a valid PCRE regular expression
     *
     * @param string $pattern
     * @return string
     */
    public function compilePattern($pattern) 
    {
        // Compile default placeholders
        $result = parent::compilePattern($pattern);

        // Compile custom placeholders          
        $result = str_replace('/:country', '{country:[a-z]{2}}', $result);          
        $result = str_replace('/:year', '{year:[0-9]{4}}', $result);            

        return $result;
    }

}   

Again, thanks for all and sorry for the inconvenience.

Regards.