1

Is there a nice and supported way to define routes like this:

$app->get('/', function (Request $request, Response $response) {
});
$app->get('/hello/{name}', function (Request $request, Response $response) {
});

... and get them work as expected no matter the location of the index.php routing file?

E.g. if DOCUMENT_ROOT is C:\Projects\Playground (http://playground.example.com) and my router file is located at C:\Projects\Playground\PHP\Slim\foo\bar\index.php (http://playground.example.com/PHP/Slim/foo/bar) I'd like http://playground.example.com/PHP/Slim/foo/bar/hello/world! to match '/hello/{name}'.

(Every other file belonging to Slim would be somewhere else, let's say C:\Libraries\Slim, and should be irrelevant to this question.)

With nice and supported I mean not this:

$uri_prefix = complex_function_to_calculate_it($_SERVER['DOCUMENT_ROOT'], __DIR__);
$app->get($uri_prefix . '/hello/{name}', function (Request $request, Response $response) {
});

Slim 3 uses nikic/fast-route but I couldn't find any hint.

Álvaro González
  • 142,137
  • 41
  • 261
  • 360
  • This seems like a strange folder structure. Are you using Composer? See e.g. http://stackoverflow.com/a/24145717/283078 – cmbuckley Mar 30 '16 at 10:28
  • @cmbuckley This particular layout is a playground site I use for quick testing (though I'm interested in generic solutions I could use in real life cases). I use Composer and I'm not interested in MVC right now (a PSR-7 microframework is better suited for my current needs). – Álvaro González Mar 30 '16 at 10:38
  • In that case, the `public` directory should be your `DOCUMENT_ROOT`. – cmbuckley Mar 30 '16 at 11:36
  • @cmbuckley That would dump the rest of the site in a black hole. – Álvaro González Mar 30 '16 at 11:46
  • Your source files should not be public facing code, so you should probably sit all your current public-facing content in `C:\Projects\Test\public` and update the `DOCUMENT_ROOT` accordingly. You can then use URL rewriting or symbolic linking to send all URLs beginning with your desired subdirectory to the Slim application (e.g. http://stackoverflow.com/questions/22421302/how-to-mod-rewrite-php-slim-url-to-sub-directory) – cmbuckley Mar 30 '16 at 12:47
  • @cmbuckley Yes, I know how to install a Slim project as standalone site. This question is about sharing the same virtual host (using Apache terminology). – Álvaro González Mar 30 '16 at 16:41
  • As I say - a URL rewrite might be the best way to go here, but you're making some initial errors up front (such as putting non-public code in a public-facing directory) that you should address first before continuing. – cmbuckley Mar 30 '16 at 22:04
  • @cmbuckley I've edited my question and rewritten path names, I hope it's clear now what it's all about. – Álvaro González Apr 05 '16 at 10:38

3 Answers3

1

Besides creating .htaccess file in the subdirectory:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [QSA,L]

you need to either configure web server or slim:

Solution 1 (configure apache):

On debian 9 open the following file:

/etc/apache2/apache2.conf

Once opened, modify

<Directory /var/www/>
    Options Indexes FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>

into

<Directory /var/www/>
    Options Indexes FollowSymLinks
    AllowOverride All
    Require all granted
</Directory>

and then restart the apache to apply the changes:

systemctl restart apache2

Solution 2 (configure slim):

Attach this:

// Activating routes in a subfolder
$container['environment'] = function () {
    $scriptName = $_SERVER['SCRIPT_NAME'];
    $_SERVER['SCRIPT_NAME'] = dirname(dirname($scriptName)) . '/' . basename($scriptName);
    return new Slim\Http\Environment($_SERVER);
};

Note that you'll need to use subdir name in the routes, e.g. /subdir/ for home, or some specific route: /subdir/auth/signup

Boy
  • 1,182
  • 2
  • 11
  • 28
0

Oh well... If it isn't supported out of the box, I guess it's better to just not complicate it too much and make it a parameter:

define('ROUTE_PREFIX', '/PHP/Slim/foo/bar');
$app->get(ROUTE_PREFIX . '/hello/{name}', function (Request $request, Response $response) {
});

After all, writing generic code that calculates it dynamically under all circumstances is too much of a burden, esp. when you can have endless factors like symlinks or Apache aliases.

The parameter should of course be defined with the rest of your site settings (either src/settings.php if you use Slim Skeleton, .env if you use phpdotenv... whatever).

Álvaro González
  • 142,137
  • 41
  • 261
  • 360
0

You could nest all of your routes inside of a wrapper group in Slim, for which the path pattern is determined based on the $_SERVER variable:

$app = Slim\Factory\AppFactory::create();
$app->group(dirname($_SERVER['SCRIPT_NAME']), function($subdirectory) {
    $subdirectory->group('/api/v1', $function($api) {
        // define routes as usual, e.g...
        $api->get('/foo/{foo:[0-9]+}', function($req, $res) {
            // ...
        });
    });
});

A little pre-processing of the $_SERVER['SCRIPT_NAME'] variable lets you do other things -- detect that your API is nested inside a directory named API and don't append another API to the route pattern, for example.

Seth Battis
  • 106
  • 8