Skip to content

Instantly share code, notes, and snippets.

@casperwilkes
Last active June 8, 2018 05:04
Show Gist options
  • Save casperwilkes/0c867043bedfaa73925986de6cbe5846 to your computer and use it in GitHub Desktop.
Save casperwilkes/0c867043bedfaa73925986de6cbe5846 to your computer and use it in GitHub Desktop.
An alias function for the SlimPHP framework. Also serves as an in-depth guide to setting it up.

Purpose

SlimPHP v2 did not offer an elegant way (or any way actually) to alias application urls. I created a function that will allow a user to alias their urls in such a way that they can use optional and conditional parameters as well.

This will also help maintain an application when routes change. Instead of having to navigate through .htaccess rewrite rules, you could potentially enforce all of your route re-writes through this method.

There are several steps that you will need to take to successfully set this up. Once it's set up, you will only need to modify 1 file (or section) going forward.

Function

The following function will allow you to alias your Slimphp2 routes.

<?php
/**
 * Alias's a url within Slim Application instance
 * @param \Slim\Slim $app Slim Environment
 * @param string $url Original url to alias (without optional parameters)
 * @param string $alias The alias for the url (with optional parameters)
 * @param array $conditions Associative array of conditions to apply to url parameters mimicking slim routes
 * @example alias_url($app, 'users/admin/edit/:id', 'users/edit/:id', array('id' => '\d+'))
 * @example alias_url($app, 'users/admin/edit/:id', 'users/edit(/:id)', array('id' => '\d+'))
 */
function alias_url(\Slim\Slim $app, $url, $alias, array $conditions = array()) {
    // Get app environment //
    $env = $app->environment();

    // Trim inputs in case user put in '/' //
    $url = trim($url, '/');
    $alias = trim($alias, '/');
    $path = trim($env['PATH_INFO'], '/');

    // Uri parameter extractions //
    $params = array();
    $paramNames = array();
    $paramNamesPath = array();

    // Create named parameters //
    $patternAsRegex = preg_replace_callback(
        '#:([\w]+)\+?#',
        function ($m) use (&$paramNames, &$paramNamesPath, $conditions) {
            // Setup the paramNames array //
            $paramNames[] = $m[1];
            // Check if conditions are set //
            if (isset($conditions[$m[1]])) {
                // Insert the conditions //
                return '(?P<' . $m[1] . '>' . $conditions[$m[1]] . ')';
            }

            // check if multiple //
            if (substr($m[0], -1) === '+') {
                $paramNamesPath[$m[1]] = 1;

                return '(?P<' . $m[1] . '>.+)';
            }

            // Return whatever is after //
            return '(?P<' . $m[1] . '>[^/]+)';
        },
        str_replace(')', ')?', (string) $alias)
    );

    // Regex pattern from current url //
    $search = '#^' . $patternAsRegex . '$#i';

    // Check for match of alias and env path //
    if (preg_match($search, $path, $paramValues)) {
        // Params to unset //
        $unsetParams = array();
        // Loop through parameters //
        foreach ($paramNames as $name) {
            // Check if we have parameters //
            if (isset($paramValues[$name])) {
                // Check if arrays (from :id+)
                if (isset($paramNamesPath[$name])) {
                    $params[':' . $name] = explode('/', urldecode($paramValues[$name]));
                } else {
                    $params[':' . $name] = urldecode($paramValues[$name]);
                }
            } else {
                // unset parameters //
                $unsetParams[] = '/:' . $name;
            }
        }

        // Replace parameters in correct url scheme //
        $replace_path = str_replace(array_keys($params), array_values($params), $url);

        // Apply any removals //
        $env['PATH_INFO'] = '/' . str_replace($unsetParams, '', $replace_path);
    }
}
?>

How it works

$app: You will need to pass the slim app instance to the method. We'll use this to over-write the current path info.

$url: This is the path that you want to have aliased. You can literally copy that from your original route. When you do this, make sure that if you have any optional route parameters to remove the option but leave the parameters. You'll see in the Aliasing Example section

$alias: This is the actual path you want the user to use - the alias. If there are conditions in the true route ($url), this is where you'll want to put those.

$conditions: This parameter is completely optional. If you want to enforce any parameter conditionals here, you can, but you can also have them declared at the route level instead, or as well. When we alias the url, we'll over-write the url path, and from there slim will take over. These are useful if you want a hard enforcement here before the request hits the route.

Inclusion

There are several ways to use this method. The most effective is to include it in a global functions file. If, for whatever reason, you are not using a global functions file, include it in it's own file called something like alias_url.php.

(For the rest of this gist, i will refer to single inclusion as alias_url.php).

You will absolutely need to have this function loading before your routes are run, so it needs to be included right at the beginning of runtime/setup.

If you already have a global functions file, it's probably already autoloaded. If you decide to include it by itself there are a couple of options you can use.

Inclusion Examples

Preferably, include it in your composer.json:

{
    "require": {
        "slim/slim": "2.*"
    },
    "autoload": {
        "files": [
            "app/includes/Bootstrap.php",
            "app/includes/Functions.php",
            "app/includes/alias_url.php"
        ]
    }
}

Secondly, you could include it in your index.php:

<?php
/**
 * Application Entry
 */

// Require the site autoloader //
require '../vendor/autoload.php';
// Require alias url function //
require '../path/to/alias_url.php';

// Init App //
$app = new Slim\Slim();

Aliasing

After you've included your alias_url() method, you will want to include your aliases. There are a couple of ways to do this as well. I prefer to have a single file containing my aliases. Others may wish to include them in their route files, or even their index. I subscribe to separation of concerns.

In this example, we'll be putting the alias urls in their own file called alias.php.

Aliasing Example

In our alias.php file:

<?php
/**
 * Alias routes
 */

// Login/Logout //
alias_url($app, 'users/login', 'login');
alias_url($app, 'users/logout', 'logout');

// Password reset //
alias_url($app, 'users/passwordReset/:stage/:confirm', 'passwordReset(/:stage(/:confirm))');

// Profile //
alias_url($app, 'users/profile', 'profile');
alias_url($app, 'users/profile/password', 'profile/password');

// Post links //
alias_url($app, 'post/view/page/:id/:name', 'posts(/:id(/:name))', array('id' => '\d', 'name' => '\w+'));

Application

The final step in setting up your aliasing is to include your alias file within a Slim Hook.

Including the file here will allow us to effectively overwrite the PATH_INFO before the route is dispatched. This will allow slim to run as normal and won't even notice that we've modified the path.

This hook should either be in your index.php or included within a separate hooks file that is included in your entry-point.

Hook example

In our Hook file, or section:

<?php
$app->hook('slim.before', function () {
    // URL Alias' //
    require '../app/includes/Alias.php';
});

Closing

If you found this useful, or have any suggestions, leave a comment. I'd love to hear what you have to say. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment