I do need to change Zend_Controller_Front and use My_Controller_Front, but I can't figure it out... I have made this:
At My_Controller_Front
/**
* Set singleton instance
*/
public static function setInstance($instance = null) {
self::$_instance = $instance;
}
And at my bootstrap
protected function _replaceZendController() {
Busca_Controller_Front::setInstance(Busca_Controller_Front::getInstance());
return $this;
}
From looking at the code I don't think its possible to have Zend_Application use anything other than Zend_Controller_Front.
When you run a Zend_Application, the following things happen:
Zend_Application::bootstrap() runs
The bootstrap process creates Zend_Application_Bootstrap_Bootstrap which sets up the resource loader and then loads the FrontController resource
The Frontcontroller resource is hardcoded to load Zend_Controller_Front (see Zend/Application/Resource/Frontcontroller::getFrontController())
The only way you may be able to change this behavior would be to register your own resource loader which could intercept the loading of the FrontController resource which would load your Front Controller instead of the Zend Front Controller. Of course you would have to make sure your Front Controller supports every option the Zend Framework one does.
So the question is, why do you need to replace Zend_Controller_Front with your own? Can't you set the appropriate options or create plugins to accomplish your goal?
Related
I recently moved from Slim 2.X to Slim 3.X and I've found a problem that may be a little stupid but annoys me in some ways.
The newly Slim 3.X, as a difference between the older 2.X version, it implements a new container system using Dependency Injection Containers (DIC) build on Pimple.
As I've been reading, I find this a very great enhancement because it lets you manage your PHP app in a lot of different ways.
When I started playing around with the new things it has, I found something confusing that maybe is something I'm missing.
I use PHPStorm; one of the things that I like about this IDE is its code-completion and the facility for writing code and understanding classes (I'm actually a student, so this helps me a lot).
When I write a Slim route, if I want to access, for example, to my view object stored inside the container, I have to refer to it with the $this->view variable. The thing is that, normally, PHPStorm lists me the methods and properties inside an object when I mention it, but that didn't happen with the $this object.
I suppose that, inside a route, Slim stores all route functionalities and all the container objects into the $this assigner.
$container = $app->getContainer();
$container['view'] = new \Slim\Views\PhpRenderer('protected/views/');
$app->get('/products', function(Request $request, Response $response) {
$response = $this->view->render($response, 'products.php');
return $response;
})->setName('products');
When I access my /products route, it successfully renders my products template and shows what it's expected to show, so no problems with that.
The matter with it is that I want PHPStorm to know that $this variable inside a route it stores all the containers that are set previously before the route is called.
I thought about /* #var */ and /* #global */ or something like this but after searching for a while and trying different things, I haven't found anything that could work.
In conclusion, what I'm trying to say is if it's possible that PHPStorm could list me the properties and methods of the container objects like this:
but with the $this object inside a route:
Thanks!
The easiest way to do this is to have separate Action classes rather than use closures. This also has the benefit of being easier to test.
Firstly create your action, inject its dependencies into its constructor and write an `__invoke`` method that will be called by Slim:
class ProductsListAction {
protected $view;
public function __construct(\Slim\Views\PhpRenderer $view) {
$this->view = $view;
}
public function __invoke($request, $response, $args) {
$response = $this->view->render($response, 'products.php');
return $response;
}
}
For this to work, you now need a DIC factory for it:
$container['ProductsListAction'] = function ($c) {
return new ProductsListAction($c['view']);
};
You can now register your new action as a route callable:
$app->get('/products', 'ProductListAction');
Now, PhpStorm will correctly autocomplete within your ProductsListAction class.
I was trying to find something like this for Eclipse, and someone suggested you modify the properties with PHPDOCS of Slim\App. Since I didn't want to change the Slim files themself, I tried to make an empty class that extends Slim\App, and use PHPDOCS to add propeties to that:
/**
* OurApp
*
* Extends Slim\App with properties so we have code completion for a bunch of stuff!
*
* #property-read SomeClass $something
* #property-read SomeotherClass $someOtherThing
* #property-read string $someString
* #property-read \Slim\Views\PhpRenderer $renderer
*/
class OurApp extends \Slim\App {}
$app = new OurApp($settings);
And that works nicely. This way you can start typing $app-> and get the completion for whatever is in the standard Slim\App and get something, someOtherThing and someString, etc. For our project we changed to a bunch of values in the $container
items Dependency.php that we needed to access.
I'm building a PHP app using Laravel Framework. I need to read some session values on every request and use this values on my controller methods.
How can I achieve this? Where to put this code?
I would like something like the Zend Framework Bootstrap class.
So, you can create a file named, for instance, BaseController.php which extends Controller. Then put your logic in the __construct()
Then, all of your other controllers can extend BaseController and in their __construct() they can perform a parent::__construct(); to make that fire.
The best practice is to use the Laravel Request Lifecycle (https://laravel.com/docs/8.x/lifecycle)
Following the documentation, the best place to place "onLoad" or global code, is on the boot method of the appServiceProvider. For example, if I wan't to set an specific timezone for all my project:
//app/Providers/AppServiceProvider.php
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
date_default_timezone_set('America/Argentina/Jujuy');
}
I would like to extend Laravels Router class (Illuminate\Routing\Router) to add a method I need a lot in my application.
But sadly I can't get this to work. I already extended other classes successfully so I really have no idea where my wrong thinking comes from.
Anyway, right into the code:
<?php
namespace MyApp\Extensions;
use Illuminate\Routing\Router as IlluminateRouter;
class Router extends IlluminateRouter
{
public function test()
{
$route = $this->getCurrentRoute();
return $route->getParameter('test');
}
}
So as you see I want to get the parameter set by {test} in routes.php with a simple call like:
Router::test();
Not sure how to go on now. Tried to bind it to the IOC-Container within my ServiceProvider in register() and boot() but I got no luck.
Whatever I try I get either a constructor error or something else.
All solutions I found are too old and the API has changed since then.
Please help me!
edit:
I already tried binding my own Router within register() and boot() (as said above) but it doesn't work.
Here is my code:
<?php
namespace MyApp;
use Illuminate\Support\ServiceProvider;
use MyApp\Extensions\Router;
class MyAppServiceProvider extends ServiceProvider {
public function register()
{
$this->app['router'] = $this->app->share(function($app)
{
return new Router(new Illuminate\Events\Dispatcher);
}
// Other bindings ...
}
}
When I try to use my Router now I have the problem that it needs an Dispatcher.
So I have to do:
$router = new Router(new Illuminate\Events\Dispatcher); // Else I get an exception :(
Also it simply does nothing, if I call:
$router->test();
:(
And if I call
dd($router->test());
I get NULL
Look at: app/config/app.php and in the aliases array. You will see Route is an alias for the illuminate router via a facade class.
If you look at the facade class in Support/Facades/Route.php of illuminate source, you will see that it uses $app['router'].
Unlike a lot of service providers in laravel, the router is hard coded and cannot be swapped out without a lot of work rewiring laravel or editing the vendor source (both are not a good idea). You can see its hardcoded by going to Illuminate / Foundation / Application.php and searching for RoutingServiceProvider.
However, there's no reason i can think of that would stop you overriding the router class in a service provider. So if you create a service provider for your custom router, which binds to $app['router'], that should replace the default router with your own router.
I wouldn't expect any issues to arise from this method, as the providers should be loaded before any routing is done. So overriding the router, should happen before laravel starts to use the router class, but i've not this before, so be prepared for a bit of debugging if it doesn't work straight away.
So I was asking in the official Laravel IRC and it seems like you simply can't extend Router in 4.1 anymore. At least that's all I got as a response in a pretty long dialogue.
It worked in Laravel 4.0, but now it doesn't. Oh well, maybe it will work in 4.2 again.
Other packages suffer from this as well: https://github.com/jasonlewis/enhanced-router/issues/16
Anyway, personally I'll stick with my extended Request then. It's not that much of a difference, just that Router would've been more dynamic and better fitting.
I'm using Laravel 4.2, and the router is really hard coded into the Application, but I extended it this way:
Edit bootstrap/start.php, change Illuminate\Foundation\Application for YourNamespace\Application.
Create a class named YourNamespace\Application and extend \Illuminate\Foundation\Application.
class Application extends \Illuminate\Foundation\Application {
/**
* Register the routing service provider.
*
* #return void
*/
protected function registerRoutingProvider()
{
$this->register(new RoutingServiceProvider($this));
}
}
Create a class named YourNamespace\RoutingServiceProvider and extend \Illuminate\Routing\RoutingServiceProvider.
class RoutingServiceProvider extends \Illuminate\Routing\RoutingServiceProvider {
protected function registerRouter()
{
$this->app['router'] = $this->app->share(function($app)
{
$router = new Router($app['events'], $app);
// If the current application environment is "testing", we will disable the
// routing filters, since they can be tested independently of the routes
// and just get in the way of our typical controller testing concerns.
if ($app['env'] == 'testing')
{
$router->disableFilters();
}
return $router;
});
}
}
Finally, create YourNamespace\Router extending \Illuminate\Routing\Router and you're done.
NOTE: Although you're not changing the name of the class, like Router and RoutingServiceProvider, it will work because of the namespace resolution that will point it to YourNamespace\Router and so on.
I recently wrote a post about request forwarding in Silex, which used a blog example to explain sub requests in Silex.
I use a slightly modified version of this example for a domain controller.
The path to the domain endpoint = /product/domain
A domain can also have a webhosting package attached to it.
The url path for this endpoint would be /product/domain/(id)/webhosting/
You can fetch info about a webhosting package by using the url path.
The url path for this endpoint would be /product/domain/(id)/webhosting/(id)
To handle these sub requests, I have a method called forwardRequest, which has no parameters in it's method signature, but uses func_get_args to keep it dynamic.
Unfortunately this doesn't work as Silex uses the named parameters in your route to call your method. So if you have /product/domain/domain_id/webhosting/webhosting_id, your method should have a signature of method($domain_id, $webhosting_id), which is a PITA if you want to forward multiple endpoints through one method. If you have additional /product/domain/domain_id/emailhosting and /product/domain/domain_id/dns endpoints, you have to create a method for each in order to forward the request.
Does anyone have a solution in which I can use only 1 method to forward all these sub requests?
Note: I'm using PHP 5.3.
The part of silex that decides which arguments to pass to the controller is called the "controller resolver". The default controller resolver uses reflection. You can override the controller_resolver service with a custom implementation though.
Defining a custom controller resolver that wraps the existing one but replaces the arguments with a single one, the request:
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
class RequestArgumentControllerResolver implements ControllerResolverInterface
{
protected $resolver;
public function __construct(ControllerResolverInterface $resolver)
{
$this->resolver = $resolver;
}
public function getController(Request $request)
{
return $this->resolver->getController($request, $controller);
}
public function getArguments(Request $request, $controller)
{
return [$request];
}
}
Extend the existing controller resolver with the newly defined decorator:
$app['controller_resolver'] = $app->share($app->extend('controller_resolver', function ($resolver, $app) {
return new RequestArgumentControllerResolver($resolver);
}));
Note: This is just one way of doing it. You don't have to decorate, you can also replace the resolver completely if you like. And obviously this is just a very basic example of only passing a single arg to the controller, you can do something more sophisticated.
I try to follow this tutorial, but I can't get it to work:
http://weierophinney.net/matthew/archives/246-Using-Action-Helpers-To-Implement-Re-Usable-Widgets.html
I did everything as described, but I don't know how to make it available in my controllers. My filesystem looks like this:
- application
- controllers
- IndexController.php
- modules
- user
- configs
user.ini
- controllers
- forms
Login.php
- helpers
HandleLogin.php
- views
- scripts
login.phmtl
profile.phtml
Bootstrap.php
- views
How do I use the HandleLogin Helper in my IndexController? I really have no idea and I'm looking an trying for more then a day and I almost want to throw my PC out of the window ;). So any help would be appreciated!
Looks like the widget plugin is not called anywhere.
Few things to check:
Do you have a Bootstrap.php file for the module?
Does this bootstrap file has _initWidgets() method?
Does this method call:
$widget = new Module_Widget_Name; // is it callable?
Zend_Controller_Action_HelperBroker::addHelper($widget);
Have you registered widget resource?
public function _initResourceLoader()
{
$loader = $this->getResourceLoader();
$loader->addResourceType('helper', 'helpers', 'Helper');
$loader->addResourceType('widget', 'widgets', 'Widget');
return $loader;
}
Does application.ini contains resources.modules[] = line?
You dont. The point of the tutorial is to create a reusable widget that runs independent from any specific controllers. When the application receives a request, it will run through it's dispatch cycle and trigger the action helper on preDispatch automatically:
Now, let's look at the action helper itself. As a reminder, action helpers can define hooks for init() (invoked by the helper broker each time it is passed to a new controller), preDispatch() (invoked prior to executing the controller's preDispatch() hook and executing the action itself), and postDispatch() (executed after the action and the controller's postDispatch() routine).
The helper will fetch the current controller (whichever that may be for that request) to get the View instance and configure it with the form