ZF2 Event Trigger - zend-framework2

I'm having an issue getting an event to trigger. Here is my code...
controller.php
function get($id)
{
$this->getEventManager()->trigger('hmac.check');
}
When this trigger is ran it will not run the hmac.check event even though it is attached.
module.php
class Module
{
/**
* Init the methods
*
* #param ModuleManager $moduleManager
*/
public function init(ModuleManager $mm)
{
$mm->getEventManager()
->attach(
'hmac.check',
function(MvcEvent $evt)
{
echo "The trigger has worked";
$key = $evt->getParams()->fromHeader('key');
$ts = $evt->getParams()->fromHeader('when');
$uri = $evt->getParams()->fromHeader('uri');
$hmac = new \Scc\Hmac\Hmac(new HmacConfig, new HmacStorage);
}
);
}
}
If i echo out a message before or after the $mm->getEventManager->attach(); it displays the test fine so i know it is executing the init method.
any help with this would be great.
Thanks in advance
EDIT:
This is a restful controller if that makes any difference (i don't think it does).

The problem is that you're attaching listeners to the ModuleManagers EventManager instance, and not the main Application EventManager.
There's no way to attach to the Application EventManager directly from module init(), the module manager doesn't have access to it, so you need to instead get the SharedManager from the ModuleManager's EventManager and attach your event listeners to that.
Here's an example of doing that by listening to the hmac.check event when triggered by any controller that extends Zend\Mvc\Controller\AbstractRestfulController, but you could listen to a specific controller by replacing that with your controllers FQCN instead.
class Module
{
/**
* Init the methods
*
* #param ModuleManager $moduleManager
*/
public function init(ModuleManager $mm)
{
$mm->getEventManager()->getSharedManager()
->attach(
'Zend\Mvc\Controller\AbstractRestfulController', 'hmac.check',
function(MvcEvent $evt)
{
echo "The trigger has worked";
$key = $evt->getParams()->fromHeader('key');
$ts = $evt->getParams()->fromHeader('when');
$uri = $evt->getParams()->fromHeader('uri');
$hmac = new \Scc\Hmac\Hmac(new HmacConfig, new HmacStorage);
}
);
}
}

Related

Problem in creating a service in a contair to inject a dependency into a class

I am trying to inject a dependency into a class in Slim framework. I created a service in a container to do it but I got this error.
PHP Catchable fatal error: Argument 2 passed to Api\Controllers\StudentWorkPriceController::__construct() must be an instance of Api\Models\StudentWorkPrice, none given, called in /studentwork/vendor/slim/slim/Slim/CallableResolver.php on line 93 and defined in /studentwork/src/api/Controllers/StudentWorkPriceController.php on line 29
My code is as below:
dependencies.php
$container = $app->getContainer();
$container['\Api\Controllers\StudentWorkPriceController']=function ($c){
$studentWorkPrice = new \Api\Models\StudentWorkPrice();
return new \Api\Controllers\StudentWorkPriceController($c,$studentWorkPrice);
};
index.php
use Api\Controllers\StudentWorkPriceController;
require __DIR__ . '/src/dependencies.php';
$app->get('/stuworkprice[/{params:.*}]',StudentWorkPriceController::class . ':select')->setName('StudentWorkPrice.select');
StudentWorkPriceController.php
use Api\Models\StudentWorkPrice as StudentWorkPrice;
class StudentWorkPriceController
{
// protected $logger;
// protected $pdo;
protected $stuWorkPrice;
/**
* StudentWorkPriceController constructor.
* #param ContainerInterface $container
*/
public function __construct(ContainerInterface $container, StudentWorkPrice $stuWorkPrice)
{
// $this->logger = $container->get('logger');
// $this->pdo = $container->get('pdo');
$this->stuWorkPrice = $stuWorkPrice;
}
public function select(){
}
}
It seems that the service I defined in container doesn't run! Could anybody please help me to figure out what's happening here!
Thanks a lot

ZF3 - EventManager and dispatch event

in an older ZF2 application I change the layout in a dispatch listener, if the matched route starts with admin. Now I started a new project and want to use ZF3 components, but the event manager does have some changes and I get the following exception:
Uncaught TypeError: Argument 2 passed to Zend\EventManager\EventManager::attach() must be callable, none given
I don't know really how to handle this in ZF3. Here are my relevant source codes to change the layout in my ZF2 application:
Module.php
namespace Admin;
use Zend\EventManager\EventInterface;
use Zend\ModuleManager\Feature\BootstrapListenerInterface;
class Module implements BootstrapListenerInterface {
public function onBootstrap(EventInterface $event) {
$application = $event->getApplication();
$eventManager = $application->getEventManager();
$serviceManager = $application->getServiceManager();
$eventManager->attach($serviceManager->get('Admin\Listener\Dispatch'));
}
}
DispatchListener.php
namespace Admin\Listener;
use Zend\EventManager\AbstractListenerAggregate;
use Zend\EventManager\EventInterface;
use Zend\EventManager\EventManagerInterface;
use Zend\Mvc\MvcEvent;
class DispatchListener extends AbstractListenerAggregate {
public function attach(EventManagerInterface $eventManager) {
$this->listeners[] = $eventManager->attach(
MvcEvent::EVENT_DISPATCH, array($this, 'onDispatch'), 100
);
}
public function onDispatch(EventInterface $event) {
$matchedRouteName = $event->getRouteMatch()->getMatchedRouteName();
if (strpos($matchedRouteName, 'admin') === 0) {
$event->getViewModel()->setTemplate('layout/admin');
}
}
}
zf3 is more focused on decoupling components, it seems aggregates has been removed to attach event see the api document
event manager
for short the attach message says
attach($eventName, callable $listener, $priority = 1) : callable
I hope since you are not specifying the eventName you are getting the error message
update:
see the link to migration guide from v2 to v3 for event manager
Removed functions
In ZF3 you can change your layout for your controller this easy way:
<?php
namespace YourCompanyModule;
use Zend\ModuleManager\ModuleManager;
use Zend\Mvc\MvcEvent;
class Module
{
// The "init" method is called on application start-up and
// allows to register an event listener.
public function init(ModuleManager $manager)
{
// Get event manager.
$eventManager = $manager->getEventManager();
$sharedEventManager = $eventManager->getSharedManager();
// Register the event listener method.
$sharedEventManager->attach(__NAMESPACE__, 'dispatch',
[$this, 'onDispatch'], 100);
}
// Event listener method.
public function onDispatch(MvcEvent $event)
{
// Get controller to which the HTTP request was dispatched.
$controller = $event->getTarget();
// Get fully qualified class name of the controller.
$controllerClass = get_class($controller);
// Get module name of the controller.
$moduleNamespace = substr($controllerClass, 0, strpos($controllerClass, '\\'));
// Switch layout only for controllers belonging to our module.
if ($moduleNamespace == __NAMESPACE__) {
$viewModel = $event->getViewModel();
$viewModel->setTemplate('layout/layout2');
}
}
// ...
}

Call to a member function get()

I created a sort base module in my ZF2 vendor library. So far everything is working the way I want it to work. I do have a problem. While I am able to extend the base module's controllers, I am unable to access the base service. I am using Doctrine 2 as my database layer.
After implementing the ServiceLocator, I am getting Fatal error: Call to a member function get() on a non-object in my base service file. My BaseService file is shown as below:
namespace MyResource\Service;
use Doctrine\ORM\Mapping as ORM;
use Zend\ServiceManager\ServiceManager;
use Zend\ServiceManager\ServiceManagerAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class BaseService implements ServiceLocatorAwareInterface
{
/**
* Entity manager instance
*
* #var Doctrine\ORM\EntityManager
*/
protected $_em;
protected $_serviceLocator;
public function __construct()
{
$this->getEntityManager();
}
/**
* Returns an instance of the Doctrine entity manager loaded from the service
* locator
*
* #return Doctrine\ORM\EntityManager
*/
public function getEntityManager()
{
if (null === $this->_em) {
$this->_em = $this->getServiceLocator()
->get('doctrine.entitymanager.orm_default');
}
return $this->_em;
}
/**
* Set serviceManager instance
*
* #param ServiceLocatorInterface $serviceLocator
* #return void
*/
public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
{
$this->serviceLocator = $serviceLocator;
}
/**
* Retrieve serviceManager instance
*
* #return ServiceLocatorInterface
*/
public function getServiceLocator()
{
return $this->serviceLocator;
}
}
Can anyone help?
Thanks
1):
Your property is called
protected $_serviceLocator;
but you are assigning your values to
protected $serviceLocator;
2)
Are you creating your Service via DI or the service manager? If you do then the ServiceLocator should be automatically injected for you, if you are creating it manually using the "new" keyword then it will not have the ServiceLocatior attached.
There seems to be a glitch in ZF2 .If you try setting the properties
as below the problem will be fixed. Try like this
foreach ($resultSet as $row) {
$entity = new Countrypages();
$entity->setId($row->id);
$entity->setName($row->name);
$entity->setSnippet($row->snippet);
$entity->setSortorder($row->sortorder);
$entity->setActive($row->active);
$entity->setCreated($row->created);
$entity->setModified($row->modified);
$entity->setFirstname($row->firstname);
$entity->setCreatedby($row->createdby);
$entities[] = $entity;
}
ignore this
foreach ($resultSet as $row) {
$entity = new Countrypages();
$entity->setId($row->id);
->setName($row->name);
->setSnippet($row->snippet);
->setSortorder($row->sortorder);
->setActive($row->active);
->setCreated($row->created);
->setModified($row->modified);
->setFirstname($row->firstname);
->setCreatedby($row->createdby);
$entities[] = $entity;
}
I hope this help you save your time.
You're using use use Zend\ServiceManager\ServiceManagerAwareInterface but you're implementing ServiceLocatorAwareInterface (and there's no "use" statement for that one).

How to pass a variable value from one MXML to another MXML?

I am doing a project in Flash Builder using ActionScript.
I have two MXML files: login.mxml and welcome.mxml.
login.mxml:
var username:String="sample";
var password:String="sample";
welcome.mxml:
trace("welcome"+username); // o/p-welcome sample
I have to pass the username value from login.mxml to welcome.xml.
Is it possible to pass a variable value from one MXML to another MXML file? How?
Yes, it is possible. The best way though would be bind the views to an objects values.
Your views don't seem to be to be associated in terms of "one aggregates the other" but their parent (the container view) knows both. So the parent would pass an object reference to both views and when this instance is updated, the views will be notified and and updated via data binding.
If the views are completely independent from each other, it would be the most straight forward way to dispatch events through the application via the application. You should introduce a new event type (i.e. SystemEvent) which is dispatched by the Application. To keep you application clean from too many references to specific global variables used in the views, i'd suggest a delegate if you're to firm with MVC yet:
package de.guj.vila.delegates {
import flash.events.Event;
import flash.events.IEventDispatcher;
import mx.core.FlexGlobals;
import mx.core.IMXMLObject;
import mx.core.UIComponent;
public class ViewDelegate implements IEventDispatcher, IMXMLObject {
//---------------------------------------------------------------------
//
// Properties
//
//---------------------------------------------------------------------
private var _bus:IEventDispatcher;
private var _uiComponent:UIComponent;
/**
* The view which uses the delegate.
*/
public function set uiComponent(value:UIComponent):void {
_uiComponent = value;
}
//---------------------------------------------------------------------
//
// Constructor
//
//---------------------------------------------------------------------
public function ViewDelegate() {
_bus = FlexGlobals.topLevelApplication as IEventDispatcher;
}
//---------------------------------------------------------------------
//
// Implemented Methods
//
//---------------------------------------------------------------------
/**
* #inheritDoc
*
* #see flash.events.IEventDispatcher
*/
public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void {
_bus.addEventListener(type, listener, useCapture, priority, useWeakReference);
}
/**
* #inheritDoc
* #see flash.events.IEventDispatcher
*/
public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void {
_bus.removeEventListener(type, listener, useCapture);
}
/**
* #inheritDoc
* #see flash.events.IEventDispatcher
*/
public function dispatchEvent(event:Event):Boolean {
return _bus.dispatchEvent(event);
}
/**
* #inheritDoc
*
* #see flash.events.IEventDispatcher
*/
public function hasEventListener(type:String):Boolean {
return _bus.hasEventListener(type);
}
/**
* #inheritDoc
*
* #see mx.core.IMXMLObject
*/
public function initialized(document:Object, id:String):void {
uiComponent = document as UIComponent;
}
/**
* #inheritDoc
*
* #see flash.events.IEventDispatcher
*/
public function willTrigger(type:String):Boolean {
return _bus.willTrigger(type);
}
}
}
You can just stuff the in the fx:Declarations block, give it an id and dispatch events from view to view. You just have to set up the listeners. This way you can easily implement quite a clean structure, since you just have to refactor the delegate. Utilizing the delegate as a base class, you can event handle any events in the delegate, so you views stay clean and, most importantly, it's easy to port to a different MVC approach, because you already isolated view behaviour from the applications behaviour.
In the end you'll want to use an MVC framework (RobotLegs for example) to be able to scale your application easily.

ZF2: How to attach listener on the event in the Module class?

I want to set a basePath to be the same for every component of my Mvc for a given request. I mean when I call these methods I want to get the same result, lets say '/spam/ham/':
echo $this->headLink()->prependStylesheet($this->basePath() . '/styles.css') // $this->basePath() has to be '/spam/ham/'
$this->getServiceLocator()
->get('viewhelpermanager')
->get('headLink')
->rependStylesheet($this->getRequest()->getBasePath() . '/styles.css') // $this->setRequest()->getBasePath() has to be /spam/ham/
How to set the basePath for the first case I have found already, here's my question. By the way, the original manual doesn't have any info I received from the answer.
And now the second one - the basePath has to be set in the Request:
$this->getRequest()->getBasePath()
Here I found some answer that in fact doesn't work at all http://zend-framework-community.634137.n4.nabble.com/Setting-the-base-url-in-ZF2-MVC-td3946284.html. As said here StaticEventManager is deprecated so I changed it with SharedEventManager :
// In my Application\Module.php
namespace Application;
use Zend\EventManager\SharedEventManager
class Module {
public function init() {
$events = new SharedEventManager();
$events->attach('bootstrap', 'bootstrap', array($this, 'registerBasePath'));
}
public function registerBasePath($e) {
$modules = $e->getParam('modules');
$config = $modules->getMergedConfig();
$app = $e->getParam('application');
$request = $app->getRequest();
$request->setBasePath($config->base_path);
}
}
}
And in my modules/Application/configs/module.config.php I add:
'base_path' => '/spam/ham/'
But it desn't work. The problems are:
1) The run never comes to the registerBasePath function. But it has to. I've attached an event with the listener in the init function.
2) When I change SharedEventManager for just EventManager it happens to come to the registerBasePath function but an exeption is thrown:
Fatal error: Call to undefined method Zend\EventManager\EventManager::getParam()
What do I do wrong? Why the run of the program doesn't come to the registerBasePath function? If this is the only way to set the basePath globally then how to do it right?
I know the documentation is lacking of these kinds of things. But you are right in the way to approach this:
Be early (so at bootstrap)
Grab the request from the application
Set the base path in the request
The docs are lacking this information and the post you refer to is quite old. The fastest and easiest way to do this is using the onBootstrap() method:
namespace MyModule;
class Module
{
public function onBootstrap($e)
{
$app = $e->getApplication();
$app->getRequest()->setBasePath('/foo/bar');
}
}
If you want to grab the base path from your config, you can load the service manager there:
namespace MyModule;
class Module
{
public function onBootstrap($e)
{
$app = $e->getApplication();
$sm = $app->getServiceManager();
$config = $sm->get('config');
$path = $config->base_path;
$app->getRequest()->setBasePath($path);
}
}

Resources