PHP Silex routing localization - php

starting with Silex.
Say I want a localised site where all routes have to start with /{_locale} and don't fancy repeating myself as :
$app->match('/{_locale}/foo', function() use ($app) {
return $app['twig']->render('foo.twig');
})
->assert('_locale', implode('|', $app['languages.available']))
->value('_locale', $app['locale.default'])
->bind('foo');
$app->match('/{_locale}/bar', function() use ($app) {
return $app['twig']->render('bar.twig');
})
->assert('_locale', implode('|', $app['languages.available']))
->value('_locale', $app['locale.default'])
->bind('bar');
Ideally, I'd like to create a base route that would match the locale and subclass it in some way but couldn't figure out by myself how to trigger that in an elegant way.

I think you can delegate the local detection with mount function:
You mount a route for each local you want to support, but they redirect to the same controller:
$app->mount('/en/', new MyControllerProvider('en'));
$app->mount('/fr/', new MyControllerProvider('fr'));
$app->mount('/de/', new MyControllerProvider('de'));
And now the local can be an attribute of your controller:
class MyControllerProvider implements ControllerProviderInterface {
private $_locale;
public function __construct($_locale) {
$this->_locale = $_locale;
}
public function connect(Application $app) {
$controler = $app['controllers_factory'];
$controler->match('/foo', function() use ($app) {
return $app['twig']->render('foo.twig');
})
->bind('foo');
$controler->match('/bar', function() use ($app) {
return $app['twig']->render('bar.twig');
})
->bind('bar');
return $controler;
}
}

Related

How can you create wildcard routes on Lumen?

Let's say I have a controller called TeamsController. Controller has following method, that returns all teams user has access to.
public function findAll(Request $request): JsonResponse
{
//...
}
Then I have bunch of other controllers with the same method. I would like to create a single route, that would work for all controllers, so I would not need to add a line for each controller every time I create a new controller.
I am unable to catch the controller name from URI. This is what I have tried.
$router->group(['middleware' => 'jwt.auth'], function () use ($router) {
// This works
//$router->get('teams', 'TeamsController#findAll');
// This just returns TeamsController#findAll string as a response
$router->get('{resource}', function ($resource) {
return ucfirst($resource) . 'Controller#findAll';
});
});
You return a string instead of calling a controller action:
I believe Laravel loads the controllers this way (not tested)
$router->group(['middleware' => 'jwt.auth'], function () use ($router) {
$router->get('{resource}', function ($resource) {
$app = app();
$controller = $app->make('\App\Http\Controllers\'. ucfirst($resource) . 'Controller');
return $controller->callAction('findAll', $parameters = array());
});
});
But again, I don't really think it's a good idea.

How to swap Filesystem for GeneratorCommand

Within the Artisan Service provider:
$this->app->singleton('command.request.make', function ($app) {
return new RequestMakeCommand($app['files']);
});
Illuminate/Foundation/Providers/ArtisanServiceProvider.php
Is building up a class that extends: Illuminate/Console/GeneratorCommand.php
My question is, is there a way to replace the bindings $app['files'] for that command / all GeneratorCommands in a package service provider? But not replace Filesystem anywhere else? I want to extend it like:
<?php
namespace Package;
use Illuminate\Filesystem\Filesystem;
class Override extends Filesystem
{
public function put($path, $contents, $lock = false)
{
parent::put($path, $contents, $lock = false);
Event::dispatch('package.files: $path', $content);
}
}
I need a way to listen to File::put in generator classes
So also open to other approaches.. this is the best I came up with.
Not ideal but it works:
$files = $this->app['files'];
$this->app->beforeResolving('command.controller.make', function ($abstract, $parameters, $container) {
$container->bind('files', function() {
return new Override;
});
});
$this->app->afterResolving('command.controller.make', function ($command, $container) use($files) {
$container->bind('files', function() use($files) {
return $files;
});
});

calling another route for the return value

hello I am new to silex and what I try to do basically is
I have one controller that uses curl to fetch something from another server. Then I have a different route where I want to show something specific from that value(JSON) returned.
I thought of using something like
$app->get('books', function() use ($app) {
$content = $app->get('overview/books/');
$content = json_decode($content);
return ... ;
})
$app->get('overview/books', function() use ($app) {
// do the curl operation and return
})
but obviously that doesn't return what I want.. How can I solve this?
You should put your json-getting code in a service and use that in both controllers.
First, you should create a class that will contain all your relevant code:
class JsonFetcher
{
public function fetch()
{ /* your code here */ }
}
then register it as a service:
$app["json-fetcher"] = $app->share(function () {
return new JsonFetcher();
});
Then use it in your controller:
$app->get("books", function () use ($app) {
$fetcher = $app["json-fetcher"];
$json = $fetcher->fetch();
// your code here
});
Edit:
If your service would be a one-method class, and it has no dependencies, you may simply register a function as a service like this:
$app["json-fetcher"] = $app->share($app->protect(function () {
//fetch and return json
}));
You can read about share and protect in the Pimple docs.

How do I define multiple routes for one request in Silex?

Is there a way in Silex to define multiple routes for one request. I need to be able to define two routes for one page (both routes takes to the same page). Here's my current controller:
$app->get('/digital-agency', function() use ($app) {
return $app['twig']->render('digital_agency.html', $data);
});
It works when I duplicate the function like this:
$app->get('/digital-agency', function() use ($app) {
return $app['twig']->render('digital_agency.html', $data);
});
$app->get('/agencia-digital', function() use ($app) {
return $app['twig']->render('digital_agency.html', $data);
});
So, any idea of a more clean way to do it?
You can save the closure to a variable and pass that to both routes:
$digital_agency = function() use ($app) {
return $app['twig']->render('digital_agency.html', $data);
};
$app->get('/digital-agency', $digital_agency);
$app->get('/agencia-digital', $digital_agency);
You can also use the assert method to match certain expressions.
$app->get('/{section}', function() use ($app) {
return $app['twig']->render('digital_agency.html', $data);
})
->assert('section', 'digital-agency|agencia-digital');

Translate Silex routes

I'm trying to make urls translatable in my Silex app.
First, I tried overriding UrlGenerator and RedirectableUrlMatcher, but that didn't really work.
Then, I tried overriding:
$app['route_class'] = 'My\Translatable\Route';
with code like this:
class Route extends Silex\Route
{
public function setPattern($pattern)
{
return parent::setPattern(str_replace('admin', 'admin2', $pattern));
}
}
But I'm getting https://gist.github.com/6c60ef4b2d8d6584eaa7.
What is the right way to achieve this?
So the solution is to extend RedirectableUrlMatcher and overwrite match method instead of Route.
Matcher.php
class Matcher extends Silex\RedirectableUrlMatcher
{
public function match($pathInfo)
{
return parent::match(str_replace('/admin', '/', $pathInfo));
}
}
app.php
$app['url_matcher'] = $app->share(function () use ($app) {
return new Matcher($app['routes'], $app['request_context']);
});
Now when I'm accessing http://domain.com/admin silex returns content for http://domain.com/.
Hope this is what you need.

Categories