I'm trying to create a method where I can trigger an event from a controller action (sending parameters with it), and have multiple components (in the same, or in another module) to listen that trigger and execute some random code (maybe some sanitised string or something)..
Is there a way to create such system with Yii Events? Or i'll need to work around something else?
Thanks
Sure,
Yii has a nice event system using CEvent. Have a look at Events explained tutorial.
You can combine it with yii Behaviors, here's another good tutorial if you are interested in Behaviors & Events.
Behaviors are a way of adding methods to a Class without php limitations of class extending since you can attach several behaviors to a same class.
Related
I'm learning Symfony and I'm trying to figure out where to put custom actions over an Entity...
For example, if I have an entity Order, where to put $order->complete()? Or $order->sendToProduction(), $order->queueForDelivery()?
Those are just examples, I have complex entities and I must perform on them many actions.
In the Controller?
No, because the same action may be called from different controllers
In the Entity?
That would be the more appropriate way in a MVC model, but here I can't find an easy way to perform custom mysql query (doctrine/em is not available) from inside the Entity class, which I find strange since db operations should be perfomed at the Entity level, I believe...
In the EntityController?
It doesn't seem appropriate, and it's not easy to call repository methods from a listener, for example, and call them directly on the object...
What else? Do I have to create services? Utility classes?
If the work can be done inside a signle entity (and it's relations of course) then it should be placed there. I mean, if the operation is about changing entity's internal state.
Otherwise, if this job need to use other parts of application like database, or is performed on multiple not related entites, then I would suggest using services.
That's what where are for. Service is basically a class that can do anything. Using Service container, you can pass any dependencies to it so it's very flexible and easy to use.
For example $order->queueForDelivery(). That may mean a few different things:
changing internal state like change status to queued_for_delivery - then it should be in Order entity class
$order should be put in the Queue that is other entity class, then it should be in Queue class like $queue->addOrder($order)
this queue is an external service like RabbitMQ or anything else. Then you should use a service class.
I am searching for a proper way of handling creation of a controller via factory (to avoid strict dependencies to services in controller itself to allow unit testing).
I have a controller with 2 actions:
search form submission in which I only use Zend Form with validators
to determine if a valid query was send to it and, if it was,
redirect to show results action
show results - I use https://github.com/ripaclub/sphinxsearch to
talk to Sphinx Search
Now, my factory for creation of controller looks like that:
$ctrl = new Album\Controller\SearchController();
$ctrl->setSearchForm(new Album\Form\SearchForm());
$ctrl->setSearchEntity(new Album\Model\Search());
$sphinxqlAdapter = $serviceLocator->getServiceLocator()->get('SphinxSearch\Db\Adapter\Adapter');
$ctrl->setSphinxqlAdapter($sphinxqlAdapter);
$ctrl->setSphinxqlMatch($serviceLocator->getServiceLocator()->get('sphinxqlMatch'));
$ctrl->setSphinxqlSearch($serviceLocator->getServiceLocator()->get('SphinxQlSearchFactory'));
return $ctrl;
The thing is, that even my first action (which is simple form validation + redirect) gets all classes for Sphinx injected and ready to use... but they are useless there. I tried to use Lazy Services as stated here http://framework.zend.com/manual/2.2/en/modules/zend.service-manager.lazy-services.html and it works for my 'sphinxqlMatch' service - this class does not get instantiated when calling form action. The problem is with SphinxSearch\Db\Adapter\Adapter because it uses a factory to create a database adapter for running SphinxQL services. While I get no exceptions, I checked that adapter gets instantiated immediately so no proxy'ing occurs.
Anybody has experience with lazy services and how to make it work with factories? Or maybe some other pattern is better here - please provide hints/solutions.
I know I could alternatively divide those two actions into separate controllers as the final resort, but for me it makes sense that search form submission routines and displaying search results logically fits together :)
I'm developing a project management tool in Symfony, right now I'm creating a module to recording the logs i.e, to capture every event like New project create, task create, task status changes, deletion of projects and task, etc.
I have a log table where I have planned to insert new rows whenever any of the above event occurs. But for doing this, I need to go into each controller and call the log model to execute the insert query. Its almost like I'm going to work on all the actions in the controller again for appending this code. is there any other way to call the model only once using some event dispatcher like class in Symfony.
Glad your are using Propel, there is a bunch of plugins and/or behavior for tracking what happend to your object. I will give you a list of what I've found:
pmPropelObjectLogBehaviorPlugin: Maintains a class changelog (the changes of each instance).
AuditableBehavior: Add ability to log activity for propel objects
propel-listener-behavior: Makes you attach listeners to propel generated objects that inform you about updates on those.
ncPropelChangeLogBehaviorPlugin: a Behavior for Propel objects that allows you to track any changes made to them.
JMSAOPBundle does exactly that.
If I may suggest, I think it's better to add custom events for each action, with this way you can extend your app with more listener without losing control. If you use doctrine you can also work with doctrine event system
I do understand the concept of the Observer Pubsub and MVC pattern. I use it in jQuery for instance. Symfony documentation also seems decent, so the usage of the component isn't really an issue but the concept is kinda confusing for me. Could you point some real-life examples (dummy code would be awesome) of using this pattern in Symfony? Can I use it in several different controllers or controller's methods only?
I think Form.php is a good example. If you look at bind method (which is called during bindRequest method call) it dispatches various events. For info about those events take a look at this answer. Also check this cookbook entry for adding event listener.
Edit: It seems there is a cookbook section on event dispatcher. Check here.
I think you should go through
https://github.com/beberlei/AcmePizzaBundle
it shows you how to build forms using form builder and interact with the database.
Let us say I have a controller that takes care of login/registration/password recovery and such in my app. I want to share this across different modules and controllers. What's the best way?
Should I make an action helper, Or use inheritance? Of course I don't mean logic of those action, those are implemented by models (different for every module), I just want to share common parameters, interpretation and passing results to views.
I'm targeting to do some kind of a generic library for those things in my project. So I would have some abstract user model from which all other models that want to use login/registration function will inherit, but I'm wondering what about the controller stuff.
Any idea?
Basically I think what you are trying to create are widgets . Here is an great article how to create them using action helper by ZF team lead http://weierophinney.net/matthew/archives/246-Using-Action-Helpers-To-Implement-Re-Usable-Widgets.html .
Creating a re-usable authentication service is what you want to do. Creating it as a service allows you to test it in isolation. Inject the service into a front-controller plug-in so it is run during each request. The actual checking can be encapsulated into a custom validator so you can simply call ->isValid(). If not valid, re-route to the login page.