Is it possible in Yii to invoke an event handler so that it executes on each controller action call.
Basically I have a RESTful application. On each request, currently, it explicitly calls an authentication function. What I want is the authentication function calls when any request is made.
What I did
class MyController extends RestController{
public function actionDosomething(){
$this->authenticate();// I don't want this line to be put in every controller action.
}
}
Your answer is the beforeAction callback. Place this in your main Controller file.
public function beforeAction($action) {
if(in_array($action, array( /* you list of actions */ )))
{
//do your thing
}
}
Another option (in my opinion the more Yii-like approach) is to write a filter and then apply it as desired using the filters method.
It will give you even more flexibility in the future:
http://www.yiiframework.com/doc/guide/1.1/en/basics.controller#filter
Related
I come from python and I have been looking for a way to write yests in go. I have come across a few things on SO but they all seem very cumbersome and verbose for something that shpuld be needed all the time.
I am typing on mobile now, will add code later if needed...but for example...
say i have a function that calls smtp.Send somewhere in the middle. how can I easily test this function?
Say i have another one that hits some outside api (needs mocking) and then takes the response and calls something like ioutil.Readall()...how could i make my way through this test function and mock the call to the api and then pass some fake response data when Readall is called?
You can do it by using an interface. For example let's say you have an interface called Mailer:
type Mailer interface {
Send() error
}
Now you can embed a Mailer object into the function that calls the Send method.
type Processor struct {
Mailer
}
func (p *Processor) Process() {
_ = p.Mailer.Send()
}
Now in your test you can create a mock Mailer.
type mockMailer struct{}
//implement the Send on the mockMailer as you wish
p := &Processor{
Mailer: mockMailer,
}
p.Process()
when p.Process reaches the Send method it calls your mocked Send method.
I'm trying out operation hooks http://docs.strongloop.com/display/public/LB/Operation+hooks
Here is what I did in app code:
mymodel.observe('before save', doSomething);
//after some time elapses or based on an event we want to change the behaviour
mymodel.observe('before save', doSomethingElse);
var doSomething = function (ctx, next) {
//do something
next();
};
var doSomethingElse = function (ctx, next) {
//do something else
next();
};
When I test this code I find that always doSomething is executed which makes me wonder if the observer function can be registered only once per model or is it a bug?
If it is as per design, could you please tell the reason behind it?
Disclaimer: I am a core developer of LoopBack and the author of Operation hooks.
after some time elapses or based on an event we want to change the behaviour
The Operation hooks do not support unregistering of handler functions yet. Each call of observe() adds the handler to the list of methods invoked when a hook is triggered.
When I test this code I find that always doSomething is executed which makes me wonder if the observer function can be registered only once per model or is it a bug?
You can register multiple observers. Once you have registered doSomething, it will be always called. When you register doSomethingElse, it will be called too, after doSomething returns via next().
You can now unregister all observers with the clearObservers method and remove a single observer with the removeObserver method. See the ObserverMixin documentation.
According to the changelog, this feature was added in version 2.23.0 of the datasource juggler.
I am trying to call a second controller method from an action method.
I am able to call second controller method using
this.controller.get('controllers.secondController').method();
How can i call method of another controller from action method?
There is work around i know of like call the controller of the current action method which in turn calls the second controller method.
this.callFirstControllerMethod();
and then use
this.controller.get('controllers.secondController').method();
But is there a way to call the second controller method directly?
Generally this kind of logic should not be on the controller, a controller should really only have actions that relate to the UI or the display of your model.
I would suggest to add an action in the route, that can access the controllers and invoke any methods you need.
// route.js
actions: {
doSomething: function() {
var controllerA = this.controllerFor('firstController');
var controllerB = this.controllerFor('secondController');
controllerA.doSomething();
controllerB.doSomethingElse();
}
}
I have a situation where as soon as app starts i have to call a web service to post unsaved data back to the server while i keep on accessing the app. I should be able to navigate to different views, perform UI tasks.
I can use Task
Task CallWebService()
{
return Task.Factory.StartNew(() => {
// make your service call.
});
}
CallWebService().ContinueWith(task => {
if(task.isFaulted)
throw new AggregateException(task.Exception.InnerException.Message);
// Runs when the task is finished
InvokeOnMainThread(() => {
// Hide your activity indicator here.
StopActivityIndicator();
});
});
I dont know where to call InvokeOnMainThread as user could be on any view. How do we handle that.
I would create the downloader as a static class with event handlers (or use dependency resolver). In your view controllers override ViewDidAppear and ViewDidDisappear where you will subscribe and unsubscribe to the events.
In your AppDelegate.cs, You can add your "Task" to the FinishedLaunching override and the OnActivated override, assuming you have a way to determine if there is any "unsaved" data, that needs to be sent to the server.
public override void OnActivated (UIApplication application)
{
}
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
}
I'm trying to unit test a controller that stuffs data into a ViewData. All our views require similar data (Customer info which is derived from the url). So instead of putting the call into every single controller method, the original developers chose to put this ViewData stuffing into the OnActionExecuting event.
Of course, when you invoke the controller's action from a unit test, OnActionExecuting doesn't fire. (Thanks MVC Team!)
So I tried creating a custom view engine and having it stuff the customer data into the controllerContext when the view is requested. This works fine in a browser, but my viewEngine is ignored when I run this test. No amount of ViewEngines.Add(new funkyViewEngine) has any effect.
[TestMethod()]
public void LoginTest()
{
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new FunkyViewEngine());
UserController target = new UserController();
target.SetStructureMap(); <--sets us to use the test repo
target.ControllerContext.HttpContext = MVCHelpers.FakeHttpContext("https://customersubdomain.ourdomain.com"); <--moq magic
var actual = target.Login();
Assert.IsTrue(actual.GetType().IsAssignableFrom(typeof(System.Web.Mvc.ViewResult)));
var vr = actual as ViewResult;
Assert.IsTrue(vr.ViewData.Community() != null); <--"Community" should be set by viewengine
Assert.IsTrue(vr.ViewData.Community().Subdomain == "customersubdomain.ourdomain");
Assert.IsTrue(vr.ViewData.Community().CanRegister);
}
Is there any hope here? How do I either 1) create a method that gets called on controller execution BOTH in the browser and the unit framework or 2) get the unit framework to invoke my view engine.
Sorry for your frustration. The reason why you are seeing OnActionExecuting not being called when you directly call your action method from the unit test is because that's not how things work in MVC.
The request gets executed via a "pipeline", which as far as this area is concerned consists of the ControllerActionInvoker. This class is responsible for:
Finding the action method
Invoking action filters' OnActionExecuting method (note: your controller class is also an action filter)
Calling the action method itself
Invoking the action filters' OnActionExecuted method
Handling the result (e.g. finding the view and rendering it)
In your unit test you are directly invoking step 3. and skipping all the other steps. In a unit test, it is your responsibility to call any setup code required for your action to work.
However, this does not mean you should now write unit tests that use the ControllerActionInvoker to execute the entire pipeline. We (the MVC team) have already verified that all the pieces work together.
Instead, you should test your specific application code. In this case, you might consider having the following unit tests:
A test that verifies that given some Url calling OnActionExecuting on your controller puts the right Customer object into ViewData
A test that verifies that given some Customer object present in ViewData your action method returns the appropriate result
My last point is that you should keep the functionality in OnActionExecuting. A custom view engine is definetely the wrong place for it.
Not an answer you're probably looking for, but I'm using a custom MvcHandler to achieve the same goal (getting customer from URL in multi-tenant app). ViewEngine doesn't sound like a good place for this kind of logic to me...
My custom handler looks more or less like this:
public class AccountMvcHandler : MvcHandler
{
public Account Account { get; private set; }
protected override IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state)
{
return base.BeginProcessRequest(httpContext, callback, state);
}
protected override IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state)
{
string accountName = this.RequestContext.RouteData.GetRequiredString("account");
Account = ServiceFactory.GetService<ISecurityService>().GetAccount(accountName);
return base.BeginProcessRequest(httpContext, callback, state);
}
}