getServiceLocator() outside Controller - php

I have a class: ClassA(), i need the Doctrine Service $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');.
I try implements the interface ServiceManagerAwareInterface, but the functions, getServiceLocator() and setServiceLocator(ServiceLocatorInterface $serviceLocator) not work.
Someone used the ServiceLocator outside Controller class in ZF2? It's possible?
<?php
namespace DbSession\Service;
use Zend\Session\SaveHandler\SaveHandlerInterface;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorAwareTrait;
/**
* Description of SessionDB
*
* #author rab
*/
class SessionDB implements SaveHandlerInterface, ServiceLocatorAwareInterface {
use ServiceLocatorAwareTrait;
/**
* Session Save Path
*
* #var string
*/
protected $sessionSavePath;
/**
* Session Name
*
* #var string
*/
protected $sessionName;
/**
* Lifetime
* #var int
*/
protected $lifetime;
/**
* Constructor
*
*/
public function __construct() {
}
/**
* Open the session
*
* #return bool
*/
public function open($savePath, $name) {
echo "open session";
}
/**
* Close the session
*
* #return bool
*/
public function close() {
echo "close session";
}
/**
* Read the session
*
* #param int session id
* #return string string of the sessoin
*/
public function read($id) {
echo "read session";
}
/**
* Write the session
*
* #param int session id
* #param string data of the session
*/
public function write($id, $data) {
$this->getServiceLocator()->get('');
echo "write";
}
/**
* Destoroy the session
*
* #param int session id
* #return bool
*/
public function destroy($id) {
echo "destroy session";
}
/**
* Garbage Collector
*
* #param int life time (sec.)
* #return bool
*/
public function gc($maxlifetime) {
echo "gc session";
}
}

The easiest way would be to use the ServiceLocatorAwareTrait (part of ZF2). If you do use that make sure your class implements ServiceLocatorAwareInterface (you don't actually have to implement it as the trait does that for you, but you do have to add it to your class' implements clause).
So you get something like this:
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorAwareTrait;
class ClassA implements ServiceLocatorAwareInterface {
use ServiceLocatorAwareTrait;
}
Then you can just call $this->getServiceLocator() to get a hold of a servicelocator instance.
However if you just need the Doctrine entitymanager it's better practice to just inject this one dependency instead of injecting the ServiceLocator.

Finally solved the problem. My class SessionDatabase() is correct. My instance was wrong.
Implements class:
class SessionDatabase implements SaveHandlerInterface, ServiceLocatorAwareInterface {
use ServiceLocatorAwareTrait;
public function write($id, $data) {
$em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
}
}
Instance:
private function initDbSession(MvcEvent $e) {
$serviceManager = $e->getApplication()->getServiceManager();
$saveHandler = new SessionDatabase();
$saveHandler->setServiceLocator($serviceManager);
}
Thanks everyone that helped!!! :D

Related

Facade Pattern Not Resolving Bind Property if app isn't initialize

Currently, I am working on Facade Pattern which doesn't resolve through the application main Container class where i have implement bind method through the interface.
Index.php
use Bundles\Support\Facades\Route;
Route::get('/users', function () {
return 'Hello';
});
Facade:
Route facade
namespace Bundles\Support\Facades;
class Route extends Facade
{
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor()
{
return 'route';
}
}
Facade.php
namespace Bundles\Support\Facades;
use Bundles\Foundations\Application;
use RuntimeException;
class Facade
{
/**
* The application instance being facaded.
*/
protected static Application $app;
/**
* The resolved object instances.
*
* #var array
*/
protected static $resolvedInstance;
/**
* Indicates if the resolved instance should be cached.
*
* #var bool
*/
protected static $cached = true;
/**
* #param $method
* #param $args
*/
public static function __callStatic($method, $args)
{
$instance = static::getFacadeRoot();
if (!$instance) {
throw new RuntimeException('A facade root has not been set.');
}
var_dump($method, $args, static::getFacadeAccessor());
Application::$app->bind(static::getFacadeAccessor(), $args, $method);
exit;
}
/**
* Get the root object behind the facade.
*
* #return mixed
*/
public static function getFacadeRoot()
{
return static::resolveFacadeInstance(static::getFacadeAccessor());
}
/**
* Get the registered name of the component.
*
* #throws \RuntimeException
*
* #return string
*/
protected static function getFacadeAccessor()
{
throw new RuntimeException('Facade does not implement getFacadeAccessor method.');
}
/**
* Resolve the facade root instance from the container.
*
* #param string $name
*
* #return mixed
*/
protected static function resolveFacadeInstance($name)
{
if (isset(static::$resolvedInstance[$name])) {
return static::$resolvedInstance[$name];
}
if (static::$app) {
if (static::$cached) {
return static::$resolvedInstance[$name] = static::$app[$name];
}
return static::$app[$name];
}
}
}
Container.php
namespace Bundles\Containers;
use Bundles\Foundations\Application;
use Bundles\Interfaces\Application as ApplicationContract;
use Bundles\Routes\Route;
class Container implements ApplicationContract
{
/**
* #var Route
*/
public Route $router;
/**
* #var Application
*/
public static Application $app;
// register method called in Application constructor
public function register()
{
$this->router = new Route();
}
/**
* > The `bind` function takes a string as the first argument, and a second argument that can be either a string or a
* closure.
*
* #param string abstract The abstract type to bind to
* #param concrete the class name or a closure that returns an instance of the class
* #param shared whether the object should be shared or not
* #param null|mixed $concrete
* #param mixed $shared
*/
public function bind(string $abstract, $concrete = null, $shared = ''): void
{
var_dump($abstract, $concrete);
exit;
}
}
anyone can help on this?
Thanks in advance

Using a repository function in service Symofony

I am using a service within twig like this
{{ count_service.getCount(term.getId) }}
I want the service to use a repository function, repository function
<?php
namespace AppBundle\Repository;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Mapping;
class SynonymRepository extends EntityRepository
{
public function getCount($termId)
{
$qbSynonymType = $this->getEntityManager()->createQueryBuilder();
$synonymTypes = $qbSynonymType->select('synonymType.id, synonymType.type')
->from('AppBundle:SynonymType', 'synonymType')
->getQuery()->getResult();
$qb = $this->getEntityManager()->createQueryBuilder();
$count = [];
$qb->select('count(synonym.synonymId)')
->from('AppBundle:Synonym','synonym');
foreach($synonymTypes as $type) {
$count[$type['type']] = $qb
->where('synonym.term = :termId')
->andWhere('synonym.synonymType = :type')
->setParameter('termId', $termId)
->setParameter('type', $type['id'])
->getQuery()->getSingleScalarResult();
}
$qbTerm = $this->getEntityManager()->createQueryBuilder()->from('AppBundle:Term', 'term');
$count['parent'] = "NaN";
$count['children'] = "NaN";
return $count;
}
}
My service.yml looks like this
synonymrepository:
class: Doctrine\ORM\EntityRepository
factory: ["#doctrine.orm.entity_manager", getRepository]
arguments:
- AppBundle\Entity\SynonymType
term_count:
class: AppBundle\Services\TermCount
arguments:
- "#synonymrepository"
And finally my service looks like this
<?php
namespace AppBundle\Services;
use AppBundle\Repository\SynonymRepository;
class TermCount
{
private $repository;
public function __construct()
{
$this->repository = new SynonymRepository();
}
public function getCount($termId)
{
return $this->repository->getCount($termId);
}
}
When running this I am getting the following error
Type error: Too few arguments to function Doctrine\ORM\EntityRepository::__construct(), 0 passed in /var/www/html/src/AppBundle/Services/TermCount.php on line 15 and exactly 2 expected
I assume this is happening because extending SynonymRepository with the EntityRepository requires EntityManagerInterface $em and Mapping\ClassMetadata $class. But I am not sure how pass them to EntityRepository.
I was using this answer to get me here, lost on how to actually implement the finall bit.
Thanks for helping.
UPDATE
Entity
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Table(name="synonym")
* #ORM\Entity(repositoryClass="AppBundle\Repository\SynonymRepository")
*/
class Synonym
{
/**
* #var int
* #ORM\Id()
* #ORM\Column(name="synonym_id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $synonymId;
/**
* #var Term
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Term", inversedBy="synonyms")
*/
protected $term;
/**
* #var SynonymType[]
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\SynonymType", inversedBy="synonyms")
*/
protected $synonymType;
/**
* #var int
* #ORM\Column(name="language_id", type="integer")
*/
protected $languageId;
/**
* #var string
* #ORM\Column(name="synonym", type="string", length=255)
*/
protected $synonym;
public function __construct()
{
// $this->synonymType = new ArrayCollection();
}
/**
* #return int
*/
public function getSynonymId(): int
{
return $this->synonymId;
}
/**
* #return Term
*/
public function getTerm(): Term
{
return $this->term;
}
/**
* #param int $termId
* #return Term
*/
public function setTerm(int $termId): Term
{
$this->term = $termId;
return $this->term;
}
/**
* #return SynonymType[]
*/
public function getSynonymType()
{
return $this->synonymType;
}
/**
* #param SynonymType $synonymType
* #return SynonymType
*/
public function setSynonymType(SynonymType $synonymType): SynonymType
{
$this->synonymType = $synonymType;
return $this->synonymType;
}
/**
* #return int
*/
public function getLanguageId(): int
{
return $this->languageId;
}
/**
* #param int $languageId
* #return Synonym
*/
public function setLanguageId(int $languageId): Synonym
{
$this->languageId = $languageId;
return $this;
}
/**
* #return string
*/
public function getSynonym(): string
{
return $this->synonym;
}
/**
* #param string $synonym
* #return Synonym
*/
public function setSynonym(string $synonym): Synonym
{
$this->synonym = $synonym;
return $this;
}
}
You need to use DI (Dependency injection) in your construct insted of using new cause as i see the erreur your SynonymRepository depends on other services
<?php
namespace AppBundle\Services;
use AppBundle\Repository\SynonymRepository;
class TermCount
{
private $repository;
public function __construct(SynonymRepository $synonymRepository)
{
$this->repository = $synonymRepository;
}
public function getCount($termId)
{
return $this->repository->getCount($termId);
}
}

How to use an getter method as a property when I json_encode a Doctrine entity?

For example, in the class
/**
* #Doctrine\ORM\Mapping\Entity
*/
class Example
{
/**
* #var int The id
*
* #Doctrine\ORM\Mapping\Id
* #Doctrine\ORM\Mapping\GeneratedValue
* #Doctrine\ORM\Mapping\Column(type="integer")
*/
public $id;
/**
* #var string
*
* #Doctrine\ORM\Mapping\Column(type="string")
*/
public $name;
public function getRandomNumber()
{
return rand();
}
}
When I call the json_encode() with this entity, it not bring the getRandomNumber() value as an property of the class.
I would like it returns:
{
"id": 1,
"name": "foo",
"randomNumber": 123456
}
But it returns:
{
"id": 1,
"name": "foo"
}
You should use JMSSerializer bundle!
I use it in all my websites, and it is really a great solution.
https://jmsyst.com/libs/serializer
It uses annotations, and creates json-serialized entities. It takes attributes values of your entity, but with a specific annotation #Accessor, it uses the specified getter to get his value.
For example:
use JMS\Serializer\Annotation\ExclusionPolicy;
use JMS\Serializer\Annotation\Expose;
use JMS\Serializer\Annotation\Accessor;
/**
* #Expose
* #Accessor("getRandomNumber")
*/
public $randomNumber;
public function getRandomNumber(){
return rand();
}
json_encode will return a JSON object with the public properties of the object passed to it. If you want to include randomNumber you could make it a public property and set it in the constructor like
/**
* #Doctrine\ORM\Mapping\Entity
*/
class Example
{
/**
* #var int The id
*
* #Doctrine\ORM\Mapping\Id
* #Doctrine\ORM\Mapping\GeneratedValue
* #Doctrine\ORM\Mapping\Column(type="integer")
*/
public $id;
/**
* #var string
*
* #Doctrine\ORM\Mapping\Column(type="string")
*/
public $name;
/**
* #var int
*/
public $randomNumber;
public function __construct() {
$this->randomNumber = $this->getRandomNumber();
}
public function getRandomNumber()
{
return rand();
}
}
For more complex serialization of objects you might want to look at the symfony serializer
You could implement the interface \JsonSerializable to specify data which should be serialized to JSON:
class Example implements \JsonSerializable
{
// ...
public function jsonSerialize()
{
// mixed data which can be serialized by json_encode()
return array(
'id' => $this->id,
'name' => $this->name,
'randomNumber' => $this->getRandomNumber(),
);
}
}
Use the virtual property
Info: https://jmsyst.com/libs/serializer/master/reference/annotations#virtualproperty
/**
* #Doctrine\ORM\Mapping\Entity
*/
class Example
{
/**
* #var int The id
*
* #Doctrine\ORM\Mapping\Id
* #Doctrine\ORM\Mapping\GeneratedValue
* #Doctrine\ORM\Mapping\Column(type="integer")
*/
public $id;
/**
* #var string
*
* #Doctrine\ORM\Mapping\Column(type="string")
*/
public $name;
/**
* #Serializer\VirtualProperty()
*/
public function getRandomNumber()
{
return rand();
}
}

Laravel Modular Request to a different Controller

I am using a github project named mnabialek/laravel-modular. The package works fine but I cant pass requests to a different controller in diffrent module. How can I do that.
TestModule Controller
<?php
namespace App\Modules\TestModule\Http\Controllers;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Http\Response;
use App\Modules\TestModule\Http\Requests\TestModuleRequest;
use App\Modules\Admin\Http\Requests\AdminRequest;
use App\Modules\TestModule\Repositories\TestModuleRepository;
use App\Modules\TestModule\Services\TestModuleService;
class TestModuleController extends Controller
{
/**
* #var TestModuleRepository
*/
protected $repo;
/**
* #var TestModuleService
*/
protected $service;
/**
* TestModuleController constructor.
*
* #param TestModuleRepository $repo
* #param TestModuleService $service
*/
public function __construct(TestModuleRepository $repo, TestModuleService $service)
{
$this->repo = $repo;
$this->service = $service;
}
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
//
//echo "Here you are";
//$data["data"] = "Here you are";
//return view("welcome")->with($data);
$working = "Its Working";
$message = App::make("App\\Modules\\Admin\\Http\\Controllers\\AdminController")->create($working);
}
/**
* Show the form for creating a new resource.
*
* #return Response
*/
}
AdminController.php
<?php
namespace App\Modules\Admin\Http\Controllers;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Http\Response;
use App\Modules\Admin\Http\Requests\AdminRequest;
use App\Modules\Admin\Repositories\AdminRepository;
use App\Modules\Admin\Services\AdminService;
class AdminController extends Controller
{
/**
* #var AdminRepository
*/
protected $repo;
/**
* #var AdminService
*/
protected $service;
/**
* AdminController constructor.
*
* #param AdminRepository $repo
* #param AdminService $service
*/
public function __construct(AdminRepository $repo, AdminService $service)
{
$this->repo = $repo;
$this->service = $service;
}
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
//
}
/**
* Show the form for creating a new resource.
*
* #return Response
*/
public function create($working)
{
die(print_r($working));
//
}
}
Here is the error I am getting.
Class 'App\Modules\TestModule\Http\Controllers\App' not found
Try the following:
$message = Illuminate\Support\Facades\App::make("App\\Modules\\Admin\\Http\\Controllers\\AdminController")->create($working);
As App does not exist in the current namespace, you have to call it from where it is defined.

Zend Framework issue with accessing a method from another controller

I have been trying to use the _forward method to access a method in my IndexController from another controller, but it won't seem to work. I have tried:
$this->_forward('permissions', 'Index')
$this->_forward('permissions', 'index')
$this->_forward('permissions', 'IndexController')
$this->_forward('permissions', 'indexcontroller')
None of which have worked. Here is my code.
Controller
class IndexController extends Zend_Controller_Action
{
/**
* facebookConfig
*
* #var mixed
* #access protected
*/
protected $facebookConfig;
/**
* signed_request
*
* #var mixed
* #access protected
*/
protected $signed_request;
/**
* facebookConfig
*
* #var mixed
* #access protected
*/
protected $permissions;
/**
* init function.
*
* #access public
* #return void
*/
public function init()
{
// get the model
$this->app = new Application_Model_Admin();
// get config data
$this->facebookConfig = $this->app->configData();
// get the apps permissions
$this->permissions = $this->permissions();
// get the data for the head
$data = $this->app->configData();
if(empty($data->ogimage))
$data->ogimage = '';
// set the page title
$this->view->headTitle($data->title, 'PREPEND');
// set the meta data
$this->view->headMeta()->setName('fb:app_id', $data->appid);
$this->view->headMeta()->setName('og:type', $data->ogtype);
$this->view->headMeta()->setName('og:title', $data->ogtitle);
$this->view->headMeta()->setName('og:description', $data->ogdesc);
$this->view->headMeta()->setName('og:url', $data->applink);
$this->view->headMeta()->setName('og:image', $data->ogimage);
}
/**
* permissions function.
*
* #access public
* #return void
*/
public function permissions(){
// return the permissions
return 'publish_stream, read_stream, friends_likes';
}
}
Second Controller
<?php
class ThanksController extends Zend_Controller_Action
{
/**
* facebookConfig
*
* #var mixed
* #access protected
*/
protected $permissions;
/**
* init function.
*
* #access public
* #return void
*/
public function init()
{
// get the model
// get the permissions
$this->permissions = $this->_forward('permissions', 'index');
print_r('<pre>');var_dump($this->_forward('permissions', 'index'));print_r('</pre>');die;
}
}
_forward is used only to call controller actions, not regular methods
_forward('index') actually refers to method indexAction()
Change this:
public function permissions(){
// return the permissions
return 'publish_stream, read_stream, friends_likes';
}
to this:
public function permissionsAction(){
// return the permissions
return 'publish_stream, read_stream, friends_likes';
}
I wasn't thinking particularly clearly, instead I just put the code in a model and accessed the data from their.

Categories