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.
Related
Consider the following class:
<?php
namespace App\Game\Battle\Services;
use App\Flare\Models\Character;
use App\Game\Battle\Values\LevelUpValue;
class CharacterService {
private $character;
public __construct(Character $character) {
$this->character = $character;
}
public function levelUpCharacter() {
$this->character->update(resolve(LevelUpValue::class)->getLevelAttributes());
}
}
I would like to register this in a provider and then when I resolve it, then pass in the Character param.
Now I know how to register classes, but I dont know how to register them such that when I resolve them I can pass in my own params.
I normally register my classes as singleton (except in some cases where I just use bind), but heres an example:
$this->app->singleton(BaseStatValue::class, function ($app) {
return new BaseStatValue();
});
So I know I can do:
$this->app->singleton(CharacterService::class, function ($app) {
return new CharacterService();
});
But how do I now resolve it with me physically passing it, the dependencies? I do not want a bunch of new CharacterService($character) in my code, I want to retrieve Character from the container.
You can not resolve Dependencies later but You can build Character in CharacterService signleton closure:
$this->app->singleton(CharacterService::class, function ($app) {
return new CharacterService($app->make(Character::class));
});
BTW. Try to avoid signleton becouse they are hard to test
I'm using silex and I'm trying to use controllers as services. This conception works fine but I can't figure out how to pass arguments to controller method. Here is what I mean
IndexController.php
class IndexController
{
public function pagesAction($page)
{
return $page;
}
}
//app.php
$app['index.controller'] = $app->share(function() use ($app) {
return new Controllers\IndexController();
});
$app->get('/pages/{num}', "index.controller:pagesAction");
When I access pages/3 I get
Controller "SD\Controllers\IndexController::pagesAction()" requires that you provide a value for the "$page" argument (because there is no default value or because there is a non optional argument after this one).
I also tried
$app->get('/pages/{num}', "index.controller:pagesAction:num");
Any ideas?
Change this
class IndexController
{
public function pagesAction($page) //what is $page? Is not into route
{
return $page;
}
}
to
class IndexController
{
public function pagesAction($num)
{
return $page;
}
}
This is because silex (and is also Symfony2 logic, of course) expects arguments name to be exactly the same from route to controller
OR
you should change your route to be parametrized for $page variable
I'm working on a ServiceProvider build for the Silex framework and i have some questions about how i should organise my code (design pattern ect).
This is what i have so far:
/Package
/Package/Classes
/Package/Controller
/Package/Model
/Package/Provider
/Package/Package.php
Now come's the part where i question about my code:
In the Package.php i have a class thats creating the other needed classes:
It's some kind of package builder i think..
public function __construct()
{
$this->content = new ContentClass($this);
$this->language = new LanguageClass($this);
}
public function content()
{
return $this->content->getContent();
}
public function language()
{
return $this->language->getLanguage();
}
In my ServiceProvider i can now do things like this:
public function register(Application $app)
{
$app['package'] = $app->share(function($app)
{
return new Package();
});
$app['package.content'] = $app['package']->content();
$app['package.language'] = $app['package']->language();
}
I don't think this is the correct way to do this.
I'm searching for a design pattern or something like that to organize my code the correct way. I hope some one could help me out with this, thank you!
I am not sure what else the Package.php class does, but you also could let the Provider build all necessary parts.
The benefit here would be that you can pass a config array to the provider to build a specific configuration.
You can use one of the many configProvider like https://github.com/igorw/ConfigServiceProvider to manage configuration in f.e. yaml.
F.e.:
package:
content:
config1: foo
config2: bar
language: de
and use the provider as builder:
public function register(Application $app)
{
$app['package.content'] = $app->share(function($app)
{
return new ContentClass($app['package']['content']['config1'], $app['package']['content']['config2']);
});
$app['package.language'] = $app->share(function($app)
{
return new LanguageClass($app['package']['language']);
});
}
I want to use this code in my application:
class ControllerExtension extends Symfony\Bundle\FrameworkBundle\Controller\Controller
{
public function render($view, array $parameters = array(), Response $response = null)
{
//etc.
}
}
But where do I put it and how do i activate it? I'm guessing it's something to do with the services.yml file. I've used Event Listeners, but this is obviously different.
From your code snippet (http://justpaste.it/2caz), it seems that you missed the "return" keyword in your call to parent.
class ControllerExtension extends Symfony\Bundle\FrameworkBundle\Controller\Controller
{
public function render($view, array $parameters = array(), Response $response = null)
{
if($this->getRequest()->getRequestFormat() == 'json') {
return new Response(json_encode($parameters));
} else {
// Missing 'return' in your snippet
return parent::render($view, $parameters, $response);
}
}
}
class MyController extends ControllerExtension
{
public function indexAction()
{
// This should now work
return $this->render(...);
}
}
You can put it in your bundle's Controller directory i.e src/YourNamespace/YourBundleName/Controller/ControllerExtension.php.
Make sure you provide the appropriate namespace in that file:
namespace YourNamespace\YourBundleName\Controller;
class ControllerExtension extends Symfony\Bundle\FrameworkBundle\Controller\Controller
{
...
To use it, either create a route for it in src/YourNamespace/YourBundlename/Resources/config/routing.yml
or
extend it:
namespace YourNamespace\YourBundleName\Controller;
class OtherController extends ControllerExtension
{
...
If what you are actually looking to do is override another bundle's controller, see the cookbook which describes overriding controllers.
Edit:
As far as I know, there's no way to automatically make this controller somehow take effect. You can have each of your controllers extend it as I've indicated above.
You might be able to create an event listener and use the response event to somehow change the response if the format is json. But, I'm not sure how you would access the view data from the event listener.
I use Cakephp 2.1 and I need to call a component method which resides in a plugin, from a view helper:
The component is here:
/app/Plugin/Abc/Controller/Component/AbcComponent.php
The helper is here:
/app/View/Helper/SimpleHelper.php
I tried inside helper:
App::import('Component', 'Abc.Abc');
$this->Abc = new Abc(); or $this->Abc = new AbcComponent;
or
$this->Abc = $this->Components->load('Abc.Abc');
inside the controllers this component works with no problem.
I know this isn't recommended (MVC design etc.) but if I don't use it this way I need to duplicate a lot of code. I need to make something like:
MyHelper extends Helper{
$simpleVar = Component->get_data();
}
I use CakePHP 2.4
This is how I successfully call Component from a Helper:
App::uses('AclComponent', 'Controller/Component');
class MyHelper extends AppHelper {
public function myFunction() {
$collection = new ComponentCollection();
$acl = new AclComponent($collection);
// From here you can use AclComponent in $acl
if ($acl->check($aro, $aco) {
// ...
}
}
}
Passing data from CakePHP component to a helper
This seems to be a very nice way to handle this.
I tried working the way you are before, and, although it seems to be a nice immediate solution, in the long run, it is better to just work with the component and helper as 2 separate entities in your controller.
lee
You can put logic in trait and use this from component and helper, if your porpouse is to use the same business logic in different places, to avoid duplication code.
By example
the trait (file app/Lib/NameOfTrait.php or app/PluginName/Lib/NameOfTrait.php)
trait NameOfTrait {
public function theTraitFunc($a, $b) {
// Code here
}
}
The Component:
App::uses('Component', 'Controller');
App::uses('NameOfTrait', 'PluginName.Lib');
class NameOfComponent extends Component {
use NameOfTrait;
private $member;
private $controller;
public function __construct(ComponentCollection $collection, $settings = array()) {
parent::__construct($collection, $settings);
$this->member = $settings['memberName'];
}
function startup(Controller $controller) {
$this->controller = $controller;
}
/**
* Wrap function call of trait function,
* I think the function doesn't have the same name,
* I don't try this but I think is obvious,
* to avoid the function to call itself
*/
public function theTraitFuncWrap($a) {
return $this->theTraitFunc($a, $this->member);
}
}
Do The same for the Helper.
I hope this help someone, bye :)