1

I try to build super simple framework. I don't want to use constrollers... basicly everything works good and this is great start for simple websites but I want one more feature that I have problems with.

I try to achieve as simple as possible solution to add in routes pages with 301 redirect. For example I want /facebook with 301 to http://facebook.com/example.

Here is my code... index.php below:

<?php

require_once __DIR__.'/../vendor/autoload.php';

$dotenv = new Dotenv\Dotenv(__DIR__.'/../');
$dotenv->load();

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing;

$request = Request::createFromGlobals();
$routes = include __DIR__.'/../routes/web.php';

$context = new Routing\RequestContext();
$context->fromRequest($request);
$matcher = new Routing\Matcher\UrlMatcher($routes, $context);

try {
    extract($matcher->match($request->getPathInfo()), EXTR_SKIP);
    ob_start();
    include sprintf(__DIR__.'/../resources/views/%s.php', $_route);

    $response = new Response(ob_get_clean());
} catch (Routing\Exception\ResourceNotFoundException $e) {
    $response = new Response();
    $response->setStatusCode(404);
    include __DIR__.'/../resources/views/errors/404.php';
} catch (Exception $e) {
    $response = new Response();
    $response->setStatusCode(500);
    include __DIR__.'/../resources/views/errors/500.php';
}

$response->send();

And my routes.php code:

<?php

use Symfony\Component\Routing;

$routes = new Routing\RouteCollection();

// 200

$routes->add('index', new Routing\Route('/'));
$routes->add('index', new Routing\Route('/about'));
$routes->add('index', new Routing\Route('/contact'));

// 301

// redirect from /facebook to -> http://facebook.com/example
// redirect from /twitter to -> http://twitter.com/example

return $routes;

Now I can make specific file for that route just like for the others and inside that file I can add header php redirect... but this is tedious approach. What can I do to define that redirect inside routes directly?

yceruto
  • 9,230
  • 5
  • 38
  • 65
Krystus
  • 285
  • 3
  • 4
  • 14

1 Answers1

3

In your case you can do the following:

//routes.php

use Symfony\Component\HttpFoundation\RedirectResponse;

$permanentRedirect = function ($url) {
    return new RedirectResponse($url, 301);
};

//...

$routes->add('facebook', new Routing\Route('/facebook', array(
    '_controller' => $permanentRedirect,
    'url' => 'http://facebook.com/example',
)));

//...

return $routes;

Next, in your index.php:

//...

try {
    extract($matcher->match($request->getPathInfo()), EXTR_SKIP);

    if (isset($_controller) && isset($url)) {
        $response = call_user_func($_controller, $url);
    } else {
        ob_start();
        include sprintf(__DIR__.'/../resources/views/%s.php', $_route);

        $response = new Response(ob_get_clean());
    }        
} catch (Routing\Exception\ResourceNotFoundException $e) {
    //...
} catch (Exception $e) {
    //...
}
yceruto
  • 9,230
  • 5
  • 38
  • 65
  • symfony/framework-bundle it's a big package. I have only symfony/http-foundation and symfony/routing one more will be ok but all of that from symfony/framework-bundle is not a good idea. Btw. will it work with my try method in index.php? I don't think so. – Krystus Sep 05 '16 at 20:26
  • Yes, this works basically with any callable function. – yceruto Sep 05 '16 at 20:35
  • Warning: include(/home/vagrant/Web/example.com/public/../resources/views/twitter.php): failed to open stream: No such file or directory in /home/vagrant/Web/example.com/public/index.php on line 22 – Krystus Sep 05 '16 at 20:42
  • I have already implemented your code (exactly class::method). But I get that error from my previous comment. – Krystus Sep 05 '16 at 20:50
  • @Yonel is it the `path` defaults not working without Symfony framework? I'm asking because on router component there is a link to "how to redirect..". – malcolm Sep 05 '16 at 20:59
  • The `class::method` pattern need a `namespace` defined. The `path` is the first param of the Route `/facebook`, then `_controller`, `url` or anyelse are defaults attributes related to the request, thus can be passed to the controller method. – yceruto Sep 05 '16 at 21:02
  • @Yonel after your last edit... old error come back. Something missing in try function I think. Warning: include(/home/vagrant/Web/example.com/public/../resources/views/facebook.php): failed to open stream: No such file or directory in /home/vagrant/Web/example.com/public/index.php on line 22 – Krystus Sep 05 '16 at 21:11
  • @Krystus take debugger and debug why *your code* tries to load a view. – zerkms Sep 05 '16 at 21:16
  • You error is related to request/response process, you need check this logic here http://symfony.com/doc/current/create_framework/index.html – yceruto Sep 05 '16 at 21:17
  • In my code I don't use controllers. So I've followed instructions up to http://symfony.com/doc/current/create_framework/routing.html and I do not implemented templating and httpkernel. Can't we achieve our goal with that code? – Krystus Sep 05 '16 at 21:23
  • @zerkms without controllers my code allowed me to include website partials by include sprintf(__DIR__.'/../resources/views/%s.php', $_route); specyfic by route. I think is a very simple approach. For example /blog is related with blog.php and in that file I have require to header.php and footer.php. – Krystus Sep 05 '16 at 21:28
  • @Krystus my point was - if something does not work as you expect, take a debugger and debug :-) It always work. – zerkms Sep 05 '16 at 21:32
  • I updated my answer again to resolve you issue with request/response process. – yceruto Sep 05 '16 at 21:36
  • @Yonel works like a dream! I appreciate your help. Now that code is perfect for my simple websites purpose. – Krystus Sep 05 '16 at 21:48