Manually calling controller method with parameter and still have method injection - laravel

How can I call a controller method manually specifying some input parameters yet still have method injection work for the parameters not specified (example below).
routes.php
$myController->index($id);
controllers/MyControllerOne.php
class MyControllerOne
{
public function index($id, MyRequest $request)
{
}
}
extra information
The reason I need this is because I have special information in my routes that determines which controller should be executed such as /myroute/{data}/{id}. It's a bit unorthodox but it's a necessary evil given the scope of our system.
Once I resolve within my routes which controller needs to be called I then want to call the method on that controller. $controllerInstance->index($id).

If it's only for Request, I think you could manually pass this $this->app->make('Request'), like so
$controllerIntance->index($id, $this->app->make('Request'))
Note that you actually don't have to inject Request, since you might as well use App::make inside of your controller. But I'm not sure how good this decision is in case of testability and coupling.
For more info:
This function resolves 'Request' out of the container, that is instantiates or returns an existing instance (depending of the type of service provider).
Using make is described here http://laravel.com/docs/5.0/container (see "Resolving"). I also found this answer helpful, to understanding how the container works https://stackoverflow.com/a/25798288/1627227

Related

Laravel 5.1 index & create authorization

I'm using Laravel 5.1's authorization features, documented here. My controllers implement AuthorizesRequests and I have my policies set up connecting policies to their models to create an ACL of sorts. In my controllers, I'm checking for authorization in each method. For example, in an 'AgencyController' the 'update' method calls $this->authorize($agency), which then checks my AgencyPolicy's update method to know rather or not the current user is allowed to update the agency, just as described in the documentation. This works the way I want it to.
However, what I can't seem to figure out is how to use authorization for other methods like index() and create() where there isn't a specific model being used. Calling $this->authorize('index') seems to return false, even if I have an index($user) function in my policy class that only returns true.
I'm new to using Laravel's authorization helpers, so I might be going about this wrong or missing something obvious. Any help pointing me in the right direction would be gretaly appreciated!
You have to pass it the class name of the model you're checking:
$this->authorize('index', Agency::class);
With some help from someone in the Laravel slack group I was able to find the answer to this myself.
Without an instance of the model, the authorize() calls couldn't map to the correct policies. But by simply passing the class to them, it is able to and works.
For example, instead of calling $this->authorize('index') in my controller's index method, I'm now calling $this->authorize('index', Agency::class) to give it the correct model to use.

re-register service provider in laravel

I am not sure if I am going about this the right way but here is what I am attempting to do, if there is a better way please let me know.
I am using a service provider that pulls some data from a config file. the problem is that if I use Config::set to change one of the settings after calling a function that uses that service provider it will not update. I thought that because I am using app->bind instead of app->share that it would re instantiate the class every time. here is my code:
service provider:
public function Register() {
$app = $this->app;
$app->bind('\path\to\MyInterface', function() use($app) {
$server = $app['config']->get('myconfig.server');
$client = $app['config']->get('myconfig.client');
$key = $app['config']->get('myconfig.key');
$version = $app['config']->get('myconfig.version');
return new MyService(new Instance($server, $client, $key, $version));
});
$this->app->booting(function() {
$loader = \Illuminate\Foundation\AliasLoader::getInstance();
$loader->alias('MyServiceFacade', '\path\to\MyFacade');
});
}
Facade class:
class MyServiceFacade extends Facade {
protected static function getFacadeAccessor() { return '\path\to\MyInterface'; }
}
route for testing:
Route::get('test', function() {
$nodes = MyServiceFacade::allNodes();
\Config::set('myconfig.server', 'new server name');
$nodes2 = MyServiceFacade::allNodes();
var_dump($nodes->getContent());
var_dump($nodes2->getContent());
}
);
I am getting the same results from both. shouldn't this be using the update config since I am making a new instance of the controller?
Skip to update 2 below for a stab at the answer
Your question doesn't quite make sense. In your testing route you're saying
App::make('MyController');
This is you asking Laravel to make an instance of the MyController service and/or class. However, you never define a MyController service and/or class.
You bind a \pathto\Interface identifier here
$app->bind('\pathto\Interface', ...
and alias MyService to that identifier here
$loader->alias('MyService', '\pathto\Facade');
but there's no place you bind or alias a MyController identifier anywhere. There's nothing in your code samples that tie MyController to the service you have bound.
Because of that it's not 100% clear what you're asking.
Update: Your question still doesn't quite make sense, and I think this not-sense-masking is what's leading the the unexpected behavior. i.e., you're doing something that "works", as in PHP doesn't complain with an error, but what you think is happening behind the scenes is not happening.
You've refereed to MyService as a facade -- however, you haven't told us what the "facade accessor" string the MyService facade points to (via its getFacadeAccessor method). Also, you appear to be directly instantiating a class from that facade class (new MyService), which isn't how Laravel facades work.
Update 2: The code samples provided are still a little sketchy, and I suspect they don't accurately reflect the actual application. The context from the comments are that MyServiceFacade::allNodes is a call to a facade. However, the facade defined in the code samples is named MyFacade and there's no class MyServiceFacade. I'm going to take a stab based on something mentioned in a comment as to the problem, but based on what I've seen above the problem still might be an incorrect application of service providers, services, and facades.
Binding a service with bind ensures the application container will always return a new instance of the service. I bet if you tried something like the following
$app = app();
$object = $app['\path\to\MyInterface'];
You'd find your object is instantiated anew every time. Adding some basic var_dump debugging to the bound closure and/or service class constructor is a good way to confirm that.
However, Laravel facades are a little different. They're not, technically, a part of the application container system. Facades are a second system built on top of the application container.
In addition to providing a convenient alias for accessing a service class, the facade implementation also forces the service object into a single-instance/singleton irrespective of how you've bound it into the container. This happens in the base facade class here
#File: vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php
protected static function resolveFacadeInstance($name)
{
if (is_object($name)) return $name;
if (isset(static::$resolvedInstance[$name]))
{
return static::$resolvedInstance[$name];
}
return static::$resolvedInstance[$name] = static::$app[$name];
}
The base facade class keeps an instance cache in static::$resolvedInstance. The specifics of how Laravel gets here are a bit long for a StackExchange answer, but my Unraveling Laravel Facades article (part of a longer series) is a good place to start.
The problem here (again, based on the incomplete information provided) appears to be a misunderstanding of facades. The main takeaway is a facade always forces a service object to be a singleton.

Zend controller's predispatch method

I was reading this to understand zend's MVC Request Lifecycle.
But i can't think of any cases in zend where i would use a controller's predispatch method , isn't the init method enough for the code that i want executed before controller's actions .
What should exactly should be in a controller's predispatch and not init .
Can you give an example ?
See Zend_Controller_Action - Object Initialization and the following section Pre and Post Dispatch Hooks. They both go into some detail on the two, and the Action Controller itself.
init() is more for setting up the controller object and doing initialization that will be available to all of your actions. Since init() runs prior to preDispatch(), anything you set up in init() will be available for preDispatch() to use. While it is possible to forward or redirect from init(), it is best practice to do it from preDispatch() because it runs prior to dispatching the controller action.
From the manual:
Note: Usage of init() vs. preDispatch() What is the difference between them (init and preDispatch), and what actions would you take
in each?
The init() method is primarily intended for extending the
constructor. Typically, your constructor should simply set object
state, and not perform much logic. This might include initializing
resources used in the controller (such as models, configuration
objects, etc.), or assigning values retrieved from the front
controller, bootstrap, or a registry.
The preDispatch() method can also be used to set object or
environmental (e.g., view, action helper, etc.) state, but its primary
purpose is to make decisions about whether or not the requested action
should be dispatched. If not, you should then _forward() to
another action, or throw an exception.
Note: _forward() actually will not work correctly when executed from init(), which is a formalization of the intentions
of the two methods.
to extend drew010's answer here is an example of how I use preDispatch() and int():
public function preDispatch() {
$this->_helper->layout->setLayout('admin');
}
/**
*initiaize the flashmessenger and assign the _session property
*/
public function init() {
if ($this->_helper->FlashMessenger->hasMessages()) {
$this->view->messages = $this->_helper->FlashMessenger->getMessages();
}
//set the session namespace to property for easier access
$this->_session = new Zend_Session_Namespace('location');
}
I use preDispatch() to set the layout for every action as it not the default layout and in init() I initialize my flash messenger and setup the session namespace for this controller and initialize the session as a property.
Here's one popular gotcha where you can waste loads of resources using init() instead of preDispatch(): if you do access control using controller plugin's preDispatch() method then call sequence will be: YourController::init(), YourAccessPlugin::preDispatch(), YourController::preDispatch(), YourController::whateverAction. This means that if you do any heavy lifting in init() then unauthorized users can trigger it. Say for e.g. you start a new session namespace in init() then mindless search bots can cause your session database to be littered with empty sessions. So stick to very basic simple stuff in init, avoid touching or modifying any resources, avoid database access.

Issue with Openrasta's Get methods' precedence in resource handler

I am new to openRasta framework. I have a resource called Project.I have 2 different types of GET to be done on this resource as i need different info on these two GETs.My configuration is like this
ResourceSpace.Has.ResourcesOfType<IList<Project>>()
.AtUri("/projects")
.And.AtUri("/miniprojects")
.HandledBy<ProjectHandler>()
.AsJsonDataContract()
.And.AsXmlDataContract();
and my methods in Handler are as below
[HttpOperation(HttpMethod.GET, ForUriName = "/projects")]
public OperationResult GetProjectsList()
{
}
[HttpOperation(HttpMethod.GET, ForUriName = "/miniprojects")]
public OperationResult GetMiniProjectList()
{
}
Whenever i am doing some GET on this resource, whatever my URL is for example http://localhost/projects or http://localhost/miniprojects) the very first method with GetXXX name in handler class gets called every time. When I changed the sequence of the GetXXX methods in handler file the other method gets called.
So my question is, does sequence of methods in Handler determines which GetXXX method to be called? Moreover, I specified different "ForUriName" in the HttpOperation attribute for each GetXXX method as mentioned in the snippet, but still the sequence took the precedence.
Can any one help me in resolving this issue? Or let me know if I am missing anything.
Thanks in advance.
If threre is no way do make the distinction between two URIs then we don't guarantee any order at all.
If you really want to use URI routes in this way (as opposed to model different resources), then your uri needs to be registered with a name
.AtUri("/miniprojects").Named("miniprojects")
The Named bit needs to match the attribute
[HttpOperation(ForUriName="miniprojects")]

How to set a custom URL path for a controller without creating new routes?

I wonder if there is attribute (built-in or some open source) for me to tag my controllers with the specific URL segment I want it to use, as in:
[MagicUrlRoute("status")]
public class InternalNameNotToBeRevealed : Controller
{
public ActionResult Show()
{
...
}
}
This way, instead of "/InternalNameNotToBeRevealed/Show" being what the user sees, it will be "/status/Show". This might be nit-picking, but it bothers that I have to use the controller class name as the official URL path.
Now, I do understand I could create a custom-route on global.asax, but that will be a lot of work for hundreds of controllers.
I found this very handy library to do exactly that, but only for actions:
http://maproutes.codeplex.com/releases/view/39888
I appreciate any suggestions.
You could have a listing of the mappings and just call MapRoute in a loop to register all the custom mappings. The mappings could be a dictionary, or you could even scan all your controllers once on App_Start, collect a custom attribute value and then use those to build the mappings. However, I'm not sure how well that would perform for a large number of mappings.
If you wanted a higher-performance mechanism, you'd have to create your own Route. You should be able to do this by inheriting from System.Web.Routing.RouteBase and overloading GetRouteData and GetVirtualPath to do the mapping. When constructing RouteData, you can just provide the existing System.Web.Mvc.MvcRouteHandler as the route handler, and as long as your route data contains 'controller' and 'action' values, it should continue down the MVC pipeline. Then just use the Add method on RouteCollection to add your route. You can take a look at MapRoute in System.Web.Mvc.RouteCollectionExtensions for some insight on how MVC adds it's route.

Resources