ZendFramework 2 - how to call zfcUser from the Model class - zend-framework2

I am trying to call ZFCUser from a class within my model but i keep getting this message:
Call to undefined method Members\Model\MemberTable::zfcUserAuthentication()
this is how i tried to call it:
public function getUserEntity()
{
if($this->zfcUserAuthentication()->getAuthService()->hasIdentity())
{
if (!$this->user_entity)
{
$this->setUserEntity($this->zfcUserAuthentication()->getAuthService()->getIdentity());
}
return $this->user_entity;
}
}
i suspect that i need to implement/extend a class inorder for ZFcuser to be recoginised.
i would really appriciate some quick advice on this.
thank you
by the way
the ZFCUser works when i call it from my controller so, the use Zend\Mvc\Controller\AbstractActionController obviouly enables this to be recoginised.
but what is the equivalent of the AbstractActionController for other classes in your framework.

zfcUserAuthentication() is a controller plugin, so that's why it can be called from controllers. You can't (or shouldn't) try and access this from non-controllers. If you need the user entity within another class, you should pass it in as a dependency for that class.
Edit: Update your member table factory so it sets the user entity:
'Members\Model\MemberTable' => function($sm) {
$tableGateway = $sm->get('MemberTableGateway');
$table = new MemberTable($tableGateway);
$authService = $serviceLocator->get('zfcuser_auth_service');
$userEntity = $authService->getIdentity();
$table->setUserEntity($userEntity);
return $table;
}
add a property to your MemberTable class for it:
protected $userEntity;
and getters/setter for it:
public function setUserEntity($userEntity)
{
$this->userEntity = $userEntity;
}
public function getUserEntity()
{
return $this->userEntity;
}
then just call $this->getUserEntity() when you need it.

There are various ways to do that -
One of the way is - do the following in "MemberTable.php" file.
Maybe most of the below lines of code is already available in our project.
a. Add the below lines after 'namespace' statement -
use Zend\ServiceManager\ServiceLocatorAwareInterface; //Added Line
use Zend\ServiceManager\ServiceLocatorInterface; //Added Line
b. Change the class statement as -
class MemberTable implements ServiceLocatorAwareInterface { //Modified Line
....
.....
}
c. Add the below line at the top of the class statement -
class MemberTable implements ServiceLocatorAwareInterface {
protected $serviceLocator; //Added line
....
.....
}
d. Add the following functions -
public function setServiceLocator(ServiceLocatorInterface $serviceLocator) {
$this->serviceLocator = $serviceLocator;
}
public function getServiceLocator() {
return $this->serviceLocator;
}
e. In Members/Module.php, make the changes,
'Members\Model\MemberTable' => function($sm) {
$tableGateway = $sm->get('MemberTableGateway');
$table = new MemberTable($tableGateway);
$table->setServiceLocator($sm); //This is the important line.
return $table;
}
Now you have the 'ServiceLocator' available in the MemberTable class.
For accessing the zfcUserAuthentication() or any ControllerPlugin, you can do the following -
public function getUserEntity()
{
$zfcUserAuth = $this->getServiceLocator()->get('controllerPluginManager')->get('zfcUserAuthentication');
if($zfcUserAuth->getAuthService()->hasIdentity())
{
if (!$this->user_entity)
{
$this->setUserEntity($zfcUserAuth->getAuthService()->getIdentity());
}
return $this->user_entity;
}
}

Related

How to get the instance of an injected dependency, by its type using Umbraco.Core.Composing (Umbraco 8)

I need to find a way to get an instance of DataProcessingEngine without calling it's constractor.
I am trying to find a way to do so using the registered DataProcessingEngine in composition object (please see the following code). But I could not find a way to do so.
Anyone have a suggestion? Thanks in advance.
public class Composer : IUserComposer
{
public void Compose(Composition composition)
{
composition.Register<IDataProcessingEngine, DataProcessingEngine>(Lifetime.Singleton);
//DataProcessingEngine dataProcessing = compostion.Resolve<IDataProcessingEngine>()??//no resolve function exists in Umbraco.Core.Composing
SaveImagesThread(dataProcessingEngine);
}
public Task SaveImagesThread(IDataProcessingEngine dataProcessingEngine)//TODO - decide async
{
string dataTimerTime = WebConfig.SaveProductsDataTimer;
double time = GetTimeForTimer(dataTimerTime);
if (time > 0)
{
var aTimer = new System.Timers.Timer(time);
aTimer.Elapsed += new ElapsedEventHandler(dataProcessingEngine.SaveImages);
aTimer.Start();
}
return default;
}
}
For all of you who are looking for a way to call a function (that's defined in another class in your code, an Engine or ...) from the composer(where the app starts) and want to avoid calling this function's class' constractor. I've found another way to do so:
public class QueuePollingHandler
{
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
public class SubscribeToQueuePollingHandlerComponentComposer :
ComponentComposer<SubscribeToQueuePollingHandler>
{ }
public class SubscribeToQueuePollingHandler : IComponent
{
private readonly IDataProcessingEngine _dataProcessingEngine;
public SubscribeToQueuePollingHandler(IDataProcessingEngine
dataProcessingEngine)
{
_dataProcessingEngine = dataProcessingEngine;
SaveImagesThread(_dataProcessingEngine);
}
public void SaveImagesThread(IDataProcessingEngine
dataProcessingEngine)
{
....
}
}
And the logic explenation: You create a class (SubscribeToQueuePollingHandlerComponentComposer from the example) and define its base class to be ComponentComposer<Class_that_inherits_IComponent>.
And when you start the application you could see that it gets to the registered class' constractor (SubscribeToQueuePollingHandler constructor).
That's the way that I found to be able to call a function right when the application starts without needing to call its class constractor and actualy use dependency injection.

How to test StreamSubscription and create Events in Dart?

I want to write some unit tests around an abstract Uploader class that I have written like so:
abstract class Uploader {
Future<StreamSubscription> subscribe(String filename, void onEvent(Event event));
}
class FirebaseUploader implements Uploader {
Future<StreamSubscription> subscribe(String filename, void onEvent(Event event)) async {
String userId = await auth.signInAnonymously();
DatabaseReference databaseReference = _databaseReference(userId, filename);
return databaseReference.onValue.listen(onEvent);
}
}
class UploaderMock implements Uploader {
Future<StreamSubscription> subscribe(String filename, void onEvent(Event event)) async {
Event event = new Event(); // The class 'Event' doesn't have a default constructor.
return Future.value(null);
}
}
The trouble is, I can't work out how to create my own Events in my UploaderMock, so I can call onEvent. If I try to create a new Event(), I get the following error:
The class 'Event' doesn't have a default constructor.
This is because Event has a private constructor:
Event._(this._data) : snapshot = new DataSnapshot._(_data['snapshot']);
This makes sense for production, but it doesn't really work for testing.
Any ideas? How can I test code that uses StreamSubscription?
You can implements Event on a custom class.
class Bar {
Bar._() {}
}
class Foo implements Bar {
Foo();
}
You can't, but you can make them public and annotate it with
#visibleForTesting to get an DartAnalyzer warning when they are
accessed from code that is not in in the same library or in test/
answered here How to test private functions/methods in Flutter?

zf2 view helper factory / service locator parameters

I have a view helper that acts as a factory by returning an entity-specific renderer.
I would like the factory to implement the FactoryInterface and MutableCreationOptionsInterface, so i can return different renderers depending on the type of object passed to it, eg:
$serviceLocator->get('entityRenderer', ['entity' => $user]); // returns UserRenderer
$serviceLocator->get('entityRenderer', ['entity' => $admin]); // returns AdminRenderer
$serviceLocator->get('entityRenderer'); // returns DefaultRenderer
However, there is no access to the servicelocator from within a view, and the factory view helper i have created is called using it's __invoke method. This means the type check is occuring here and returning the specific renderer without using the service manager, which is not desirable. eg
class EntityRendererFactory extends AbstractHelper{
public function __invoke(Entity $entity){
if($entity instanceof User){
$renderer = new UserRenderer($entity);
$renderer->setView($this->view);
}
if($entity instanceof Admin){
$renderer = new AdminRenderer($entity);
$renderer->setView($this->view);
}
if($renderer){
return $renderer;
}
}
}
Note how this "factory" is having to extend AbstractHelper (view) simply just to pass on the instance of the current view.
My "ideal" would be something like this (proof of concept, not working code):
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\MutableCreationOptionsInterface;
class EntityRendererFactory implements FactoryInterface, MutableCreationOptionsInterface{
protected $options = [];
protected $renderers = [];
public function createService(ServiceLocatorInterface $serviceLocator){
$this->addRenderer($serviceLocator->get('ViewHelperManager')->get('UserRenderer'), User::class);
$this->addRenderer($serviceLocator->get('ViewHelperManager')->get('AdminRenderer'), Admin::class);
$this->addRenderer($serviceLocator->get('ViewHelperManager')->get('DefaultRenderer'), 'default');
if(!array_key_exists('entity', $this->options)){
return $this->getRenderer('default');
}
$entity = $this->options['entity'];
foreach($this->getRenderers() as $renderer){
if($renderer->canRender($entity)){
return $renderer;
}
}
//Alternatively, more specific hard-coding interface type check
if($entity instanceof User){
return $serviceLocator->get('ViewHelperManager')->get('UserRenderer');
}
//etc.
}
public function setCreationOptions(array $options){
$this->options = $options;
}
}
...but with the above demonstration, i would be unsure how to call it from within the view (as view helpers are typically called from their __invoke method and not from the service manager)?
(With an eye to migrating to ZF3, i do not want to use the ServiceLocatorAwareInterface).
You can declare your viewhelperin the factories section of module.config.php as :
return [
...
'view_helpers' => [
'factories' => [
'entityRenderer' => EntityRendererFactory::class
]
],
...
]
then use the following model :
class EntityRendererFactory extends AbstractHelper implement FactoryInterface
{
private $sm;
public function createService(ServiceLocatorInterface $serviceLocator){
$this->sm = $serviceLocator;
return $this;
}
public function _invoke() {
// your code
}
}
Personally, I start by creating a specific service manager containing only the necessary classes and it is this one that I record in the class.
$this->sm = $servicelocator->getServiceLocator()->get('mySpecificSM');
Incidentally, this model does not work under ZF3 where you need a factory class that builds the viewhelper class. A change not too complicated however.

How can I set up Lazy Loading with ZF3 (no ServiceLocator pattern from anywhere)

I am writing a new ZF2 app. I have noticed that ServiceLocator usage pattern of calling services "from anywhere" has been deprecated from ZF3. I want to write code in mind for ZF3.
I was able to set up my Controller to call all dependencies at constructor time. But that means loading i.e. Doctrine object upfront before I need it.
Question
How do I set it up so that it is only loaded when I need it immediately? (lazy-loaded). I understand that ZF3 moves loading to Controller construction, which makes it not apparent as to how to load something Just-In-Time.
Old Code
class CommissionRepository
{
protected $em;
function getRepository()
{
//Initialize Doctrine ONLY when getRepository is called
//it is not always called, and Doctrine is not always set up
if (! $this->em)
$this->em = $this->serviceLocator->get('doctrine');
return $this->em;
}
}
Current Code after Refactor of ServiceLocator pattern
class CommissionRepository
{
protected $em;
function getRepository()
{
return $this->em;
}
function setRepository($em)
{
$this->em = $em;
}
function useRepository($id)
{
return $this->em->find($id);
}
}
class CommissionControllerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$parentLocator = $controllerManager->getServiceLocator();
// set up repository
$repository = new CommissionRepository();
$repository->setRepository($parentLocator->get('doctrine'));
// set up controller
$controller = new CommissionController($repository);
$controller->setRepository();
return $controller;
}
}
class CommissionController extends AbstractActionController
{
protected $repository;
public function setRepository(CommissionRepository $repository)
{
$this->repository = $repository;
}
public function indexAction()
{
//$this->repository already contains Doctrine but it should not
//I want it to be initialized upon use. How?
//Recall that it has been set up during Repository construction time
//and I cannot call it from "anywhere" any more in ZF3
//is there a lazy loading solution to this?
$this->repository->useRepository();
}
If you don't have any valid/strong reason to instantiate a custom entity repository, you should prefer extending of Doctrine\ORM\EntityRepository in your repositories like CommissionRepository. For example;
use Doctrine\ORM\EntityRepository;
class CommissionRepository extends EntityRepository
{
// No need to think about $em here. It will be automatically
// injected by doctrine when you call getRepository().
//
function fetchCommissionById($id)
{
// You can easily get the object manager directly (_em) or
// using getEntityManager() accessor method in a repository
return $this->_em->find($id);
}
}
By this way, entity manager will be automatically injected to the repository on construction when you call the $em->getRepository('App\Entity\Commission') method.
I assume that you already have a Commission entity in your app's Entity namespace:
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repo\CommissionRepository")
* #ORM\Table
*/
class Commission
{
}
Then you can simplify the injecting process of the repository in your factory something like:
// ZF2 Way
class CommissionControllerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $services)
{
$em = $services->getServiceLocator()->get('doctrine');
$repository = $em->getRepository('App\Entity\Commission');
return new CommissionController($repository);
}
}
UPDATE - With the release of Service Manager V3, FactoryInterface has been moved to Zend\ServiceManager\Factory namespace (1), factories are literally invokables (2) and works with any container-interop compatible DIC (3) Updated factory would be like below:
// ZF3 Way
use Zend\ServiceManager\Factory\FactoryInterface;
use Interop\Container\ContainerInterface;
use Doctrine\ORM\EntityManager;
class CommissionControllerFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $dic, $name, array $options = null) {
$em = $dic->get(EntityManager::class);
$repository = $em->getRepository('App\Entity\Commission');
return new CommissionController($repository);
}
}
For the question; as of marcosh's said, Lazy Services are way to go to create services when need it immediately. ZF3 will use the zend-servicemanager 3.0 component when released. (Currently zend-expressive uses it) As of servicemanager v3 you can create some proxied services by defining lazy_services and delegators in your service configuration:
'factories' => [],
'invokables' => [],
'delegators' => [
FooService::class => [
FooServiceDelegatorFactory::class,
],
],
'lazy_services' => [
// map of service names and their relative class names - this
// is required since the service manager cannot know the
// class name of defined services up front
'class_map' => [
// 'foo' => 'MyApplication\Foo',
],
// directory where proxy classes will be written - default to system_get_tmp_dir()
'proxies_target_dir' => null,
// namespace of the generated proxies, default to "ProxyManagerGeneratedProxy"
'proxies_namespace' => null,
// whether the generated proxy classes should be written to disk or generated on-the-fly
'write_proxy_files' => false,
];
Also, starting with service manager v3 factories are compatible with the ContainerInterface. For the forward-compatibility, you may want to keep both __invoke() and createService() methods in your factories for a smooth migration.
In the end, your ZF3 compatible factory may look like:
class CommissionControllerFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $name, array $options = null)
{
$em = $container->get('doctrine');
$repository = $em->getRepository('App\Entity\Commission');
return new CommissionController($repository);
}
public function createService(ServiceLocatorInterface $container, $name = null, $requestedName = null)
{
return $this($container, $requestedName, []);
}
}
Hope it helps.

code run before every actions in a module ZF2?

I want to write some code to run before every actions in my module. I have tried hooking onto onBootstrap() but the code run on the other modules too.
Any suggestions for me?
There are two ways to do this.
One way is to create a serice and call it in every controllers dispatch method
Use onDispatch method in controller.
class IndexController extends AbstractActionController {
/**
*
* #param \Zend\Mvc\MvcEvent $e
* #return type
*/
public function onDispatch(MvcEvent $e) {
//Call your service here
return parent::onDispatch($e);
}
public function indexAction() {
return new ViewModel();
}
}
don't forget to include following library on top of your code
use Zend\Mvc\MvcEvent;
Second method is to do this via Module.php using event on dispatch
namespace Application;
use Zend\Mvc\ModuleRouteListener;
use Zend\Mvc\MvcEvent;
class Module {
public function onBootstrap(MvcEvent $e) {
$sharedEvents = $e->getApplication()->getEventManager()->getSharedManager();
$sharedEvents->attach(__NAMESPACE__, 'dispatch', array($this, 'addViewVariables'), 201);
}
public function addViewVariables(Event $e) {
//your code goes here
}
// rest of the Module methods goes here...
//...
//...
}
How to create simple service using ZF2
reference2
reference3

Resources