I use zend on my company but i have never started setting it up.
I downloaded the framework and want to integrate doctrine... I tried to get the doctrine object using getServiceLocator() but on zend 2x it will be deprecated and when I try to do this:
public function indexAction()
{
$em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
}
I get the following exceptions:
1 - An exception was raised while creating
"Doctrine\ORM\EntityManager"; no instance returned 2 - An abstract
factory could not create an instance of
doctrine.entitymanager.ormdefault(alias:
doctrine.entitymanager.orm_default).
So I tried to pass the doctrine object by factory... but the factory is never called.
That's what I did:
'controllers' => array(
'invokables' => array(
'Album\Controller\Album' => 'Album\Controller\AlbumController'
),
'factories' => [
'Album\Controller\Album' => 'Album\Controller\AlbumControllerFactory'
]
),
On module.php
public function getControllerConfig()
{
return [
'factories' => [
'\Album\Controller\Album' => function() {
exit;
}
]
];
}
Nothing that I do seems to get inside the factory class.
class AlbumControllerFactory implements FactoryInterface
{
public function __construct()
{
exit;
}
public function createService(\Zend\ServiceManager\ServiceLocatorInterface $serviceLocator) {
exit;
/* #var $serviceLocator \Zend\Mvc\Controller\ControllerManager */
$sm = $serviceLocator->getServiceLocator();
$em = $sm->get('Doctrine\ORM\EntityManager');
$controller = new AlbumController($em);
return $controller;
}
}
class AlbumController extends AbstractActionController
{
public function indexAction()
{
$em = $this->getServiceLocator()
->get('Doctrine\ORM\EntityManager');
Here is how my structure looks like:
Thanks!
The mapping of your classes are wrong for your AlbumController as you use Album\Controller\Album instead of Album\Controller\AlbumController. Use the FQCN (Fully Qualified Class Name).
For your module.php, there is a '\' infront of the class name, aswell you forgot the Controller at the end.
use Album\Controller\AlbumController;
use Album\Controller\AlbumControllerFactory;
class Module implements ControllerProviderInterface
{
/**
* Expected to return \Zend\ServiceManager\Config object or array to seed
* such an object.
* #return array|\Zend\ServiceManager\Config
*/
public function getControllerConfig()
{
return [
'aliases' => [
'Album\Controller\Album' => AlbumController::class,
],
'factories' => [
AlbumController::class => AlbumControllerFactory::class,
]
];
}
Related
For example, in the following code:
/**
* #Route("/patients", service="bundle1.controller.patient.index")
*/
final class IndexController
{
private $router;
private $formFactory;
private $templating;
private $patientFinder;
public function __construct(RouterInterface $router, FormFactoryInterface $formFactory, EngineInterface $templating, PatientFinder $patientFinder)
{
$this->router = $router;
$this->formFactory = $formFactory;
$this->templating = $templating;
$this->patientFinder = $patientFinder;
}
/**
* #Route("", name="patients_index")
*/
public function __invoke(Request $request) : Response
{
$form = $this->formFactory->create(PatientFilterType::class, null, [
'action' => $this->router->generate('patients_index'),
'method' => Request::METHOD_GET,
]);
$form->handleRequest($request);
$patients = $this->patientFinder->matching($form->getData() ?: []);
return $this->templating->renderResponse('patient/index.html.twig', [
'form' => $form->createView(),
'patients' => $patients,
]);
}
}
Why is there a route annotation for __invoke that is empty?.
What is the lifecycle of this controller? I mean, when does Symfony creates the object and when executes the class to make use of __invoke?
Empty #Route annotation means that there is nothing after main route of class which is /patients. __invoke is a magic PHP method that is executed when you call your class as a function (without providing any method).
So __invoke method is executed when you hit the route /patients or when you call your service from any code.
Currently I have such Types.php:
namespace Application\GraphQL;
use Application\GraphQL\Type\NodeType;
use Application\GraphQL\Type\QueryType;
use GraphQL\Type\Definition\NonNull;
use GraphQL\Type\Definition\Type;
use Application\GraphQL\Type\PersonType;
/**
* Class Types
*
* Acts as a registry and factory for your types.
*
* As simplistic as possible for the sake of clarity of this example.
* Your own may be more dynamic (or even code-generated).
*
* #package GraphQL\Examples\Blog
*/
class Types
{
private static $query;
private static $person;
private static $node;
public static function person()
{
return self::$person ?: (self::$person = new PersonType());
}
/**
* #return QueryType
*/
public static function query()
{
return self::$query ?: (self::$query = new QueryType());
}
/**
* #return NodeType
*/
public static function node()
{
return self::$node ?: (self::$node = new NodeType());
}
/**
* #return \GraphQL\Type\Definition\IDType
*/
public static function id()
{
return Type::id();
}
/**
* #return \GraphQL\Type\Definition\StringType
*/
public static function string()
{
return Type::string();
}
/**
* #param Type $type
* #return NonNull
*/
public static function nonNull($type)
{
return new NonNull($type);
}
}
In query() function it creates QueryType instance. I added to QueryType constructor PersonTable model class so that it could query persons from database.
QueryType.php
public function __construct(PersonTable $table)
{
$config = [
'name' => 'Query',
'fields' => [
'person' => [
'type' => Types::person(),
'description' => 'Returns person by id',
'args' => [
'id' => Types::nonNull(Types::id())
]
],
'hello' => Type::string()
],
'resolveField' => function($val, $args, $context, ResolveInfo $info) {
return $this->{$info->fieldName}($val, $args, $context, $info);
}
];
$this->table = $table;
parent::__construct($config);
}
I have set up factories in module\Application\src\Module.php:
/**
* #link http://github.com/zendframework/ZendSkeletonApplication for the canonical source repository
* #copyright Copyright (c) 2005-2016 Zend Technologies USA Inc. (http://www.zend.com)
* #license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Application;
use Application\Model\PersonTable;
use Application\Model\Person;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\TableGateway;
class Module
{
const VERSION = '3.0.2dev';
public function getConfig()
{
return include __DIR__ . '/../config/module.config.php';
}
// Add this method:
public function getServiceConfig()
{
return array(
'factories' => array(
'Application\Model\PersonTable' => function($sm) {
$tableGateway = $sm->get('PersonTableGateway');
$table = new PersonTable($tableGateway);
return $table;
},
'PersonTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Person());
return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);
},
),
);
}
}
I am doing by this example which does not have any framework:
https://github.com/webonyx/graphql-php/tree/master/examples/01-blog
So the question is - how do I create queryType instance with injected PersonTable instance? I should somehow get from the factory the PersonTable instance but I do not understand how.
Update:
I decided to try to inject QueryType into the controller. Created such function:
public function __construct(QueryType $queryType)
{
$this->queryType = $queryType;
}
Now module\Application\src\Module.php getServiceConfig looks like this:
public function getServiceConfig()
{
return array(
'factories' => array(
'Application\Model\PersonTable' => function($sm) {
$tableGateway = $sm->get('PersonTableGateway');
$table = new PersonTable($tableGateway);
return $table;
},
'PersonTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Person());
return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);
},
QueryType::class => function ($sm) {
return new QueryType($sm->get(PersonTable::class));
}
// when putting in namespace does not find??????????
//QueryType::class => Application\GraphQL\Type\Factories\QueryTypeFactory::class
//QueryType::class => \QueryTypeFactory::class
),
);
}
But I get error:
Catchable fatal error: Argument 1 passed to Application\Controller\IndexController::__construct() must be an instance of Application\GraphQL\Type\QueryType, none given, called in E:\projektai\php projektai\htdocs\graphQL_zend_3\vendor\zendframework\zend-servicemanager\src\Factory\InvokableFactory.php on line 32 and defined in E:\projektai\php projektai\htdocs\graphQL_zend_3\module\Application\src\Controller\IndexController.p
How can none be given if I configured in that function?
If I could inject into the controller, then I plan to do like this:
$schema = new Schema([
//'query' => Types::query()
'query' => $this->queryType
]);
So I would not need to call query() function which return the QueryType instance anyway.
And then PersonTable would be automatically injected into QueryType class.
Update:
I had created the factory, similar as in the asnswer:
class QueryTypeFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
return new QueryType($container->get(PersonTable::class));
}
}
In the IndexController I have constructor:
public function __construct(QueryType $queryType)
{
$this->queryType = $queryType;
}
In the Module.php I use this factory:
public function getServiceConfig()
{
return array(
'factories' => array(
'Application\Model\PersonTable' => function($sm) {
$tableGateway = $sm->get('PersonTableGateway');
$table = new PersonTable($tableGateway);
return $table;
},
'PersonTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Person());
return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);
},
// QueryType::class => function ($sm) {
// //return new QueryType($sm->get(PersonTable::class));
//
// }
//QueryType::class => Application\GraphQL\Type\Factories\QueryTypeFactory::class
//QueryType::class => \QueryTypeFactory::class
QueryType::class => QueryTypeFactory::class
),
);
}
It simply does not work, I get error:
Catchable fatal error: Argument 1 passed to Application\Controller\IndexController::__construct() must be an instance of Application\GraphQL\Type\QueryType, none given, called in E:\projektai\php projektai\htdocs\graphQL_zend_3\vendor\zendframework\zend-servicemanager\src\Factory\InvokableFactory.php on line 32 and defined in E:\projektai\php projektai\htdocs\graphQL_zend_3\module\Application\src\Controller\IndexController.php on line
I also tried this way:
$queryTypeFactory = new QueryTypeFactory();
// GraphQL schema to be passed to query executor:
$schema = new Schema([
//'query' => Types::query()
//'query' => $this->queryType
// 'query' => $queryType
'query' => $queryTypeFactory()
]);
But the $queryTypeFactory() needs parameter $container. Which is not what I want, I guess. I should be able to create an instance without passing parameters.
I hope it is ok to use QueryType::class in the factories array as key. It will create with full name space which is set:
use Application\GraphQL\Type\QueryType;
And in index controller I also call that use statement.
<?php
namespace Application\Service\Factory;
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\FactoryInterface;
use Application\Service\CurrencyConverter;
use Application\Service\PurchaseManager;
/**
* This is the factory for PurchaseManager service. Its purpose is to instantiate the
* service and inject its dependencies.
*/
class PurchaseManagerFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container,
$requestedName, array $options = null)
{
// Get CurrencyConverter service from the service manager.
$currencyConverter = $container->get(CurrencyConverter::class);
// Instantiate the service and inject dependencies.
return new PurchaseManager($currencyConverter);
}
}
In the code above we have the PurchaseManagerFactory class which implements the Zend\ServiceManager\Factory\FactoryInterface interface. The factory class has the __invoke() method whose goal is to instantiate the object. This method has the $container argument which is the service manager. You can use $container to retrieve services from service manager and pass them to the constructor method of the service being instantiated.
I'm doing a query on a really simple table in a typo 3 task. However, only the fields "uid" and "pid" are returned, the other fields are NULL.
My Entity:
<?php
namespace Name\SampleExtension\Domain\Model;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
class MailAgent extends AbstractEntity
{
/**
* #var integer
*/
protected $uid;
/**
* #var string
*/
protected $customeremail;
/**
* #var string
*/
protected $searchparameters;
/**
* #var string
*/
protected $resultlist;
public function getUid()
{
return $this->uid;
}
public function setCustomerEmail($customeremail)
{
$this->customeremail = $customeremail;
}
public function getCustomerEmail()
{
return $this->customeremail;
}
public function setSearchParameters($searchparameters)
{
$this->searchparameters = $searchparameters;
}
public function getSearchParameters()
{
return $this->searchparameters;
}
public function setResultList($resultlist)
{
$this->resultlist = $resultlist;
}
public function getResultList()
{
return $this->resultlist;
}
}
?>
The Repository:
<?php
namespace Name\SampleExtension\Domain\Repository;
use TYPO3\CMS\Extbase\Persistence\Repository;
class MailAgentRepository extends Repository
{
public function findByUids($uids)
{
$query = $this->createQuery();
foreach ($uids as $uid) {
$constraints[] = $query->equals('uid', $uid);
}
return $query->matching(
$query->logicalOr(
$constraints
)
)->execute();
}
}
?>
And the query inside the task:
<?php
namespace Name\SampleExtension\Task;
use TYPO3\CMS\Scheduler\Task\AbstractTask;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
use Name\SampleExtension\Domain\Model\MailAgent;
use Name\SampleExtension\Domain\Repository\MailAgentRepository;
class MailAgentCheckup extends AbstractTask
{
public function execute() {
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
$this->MailAgentRepository = $objectManager->get(MailAgentRepository::class);
$query = $this->MailAgentRepository->createQuery();
$allCustomers = $this->MailAgentRepository->findAll();
foreach ($allCustomers as $customer) {
var_dump($customer);
}
return true;
}
}
?>
I have no idea why the other fields are not returned, but the uid and the pid are. My guess is that I need to declare the mapping somewhere else.
EDIT: Heres the content of my TCA, which is probably wrong or not enough, but since I'm working on a existing extension I was copying from the TCA's of the tables that work.
tx_sampleextension_domain_model_mailagent.php
return [
'columns' => [
'uid' => [],
'customer_email' => [],
'search_parameters' => [],
'result_list' => [],
],
'types' => [],
];
This is from another table for which querys etc work
return [
'columns' => [
'immovable' => [],
'type' => [],
'title' => [],
'path' => [],
'mark_to_delete' => [],
],
];
Give a try to inject your repository
<?php
namespace Name\SampleExtension\Task;
use TYPO3\CMS\Scheduler\Task\AbstractTask;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
use Name\SampleExtension\Domain\Model\MailAgent;
use Name\SampleExtension\Domain\Repository\MailAgentRepository;
use TYPO3\CMS\Extbase\Utility\DebuggerUtility;
class MailAgentCheckup extends AbstractTask
{
/**
* mailAgentRepository
*
* #var \Name\SampleExtension\Domain\Repository\MailAgentRepository
* #inject
*/
protected $mailAgentRepository = NULL;
public function injectMailAgentRepository(\Name\SampleExtension\Domain\Repository\MailAgentRepository $mailAgentRepository) {
$this->mailAgentRepository = $mailAgentRepository;
}
public function execute() {
$allCustomers = $this->mailAgentRepository->findAll();
DebuggerUtility::var_dump($allCustomers);exit;
// OR
$arguments = $this->request->getArguments();
$uid = $arguments['uid'];
$singleCustomer = $this->mailAgentRepository->findByUid(intval($uid));
DebuggerUtility::var_dump($singleCustomer);exit;
/*foreach ($allCustomers as $customer) {
var_dump($customer);
}*/
return true;
}
}
?>
I was missing the TCA file for the table. After adding it and declaring all the columns in there, the extbase domain object variables got filled.
I used Zend Framework 2.1(not 2.0x) method to populate a select/drop down that is described in following links:
http://zf2.readthedocs.org/en/develop/modules/zend.form.advanced-use-of-forms.html#handling-dependencies
http://www.michaelgallego.fr/blog/2012/11/09/discover-whats-coming-for-zendform-in-zf-2-1/
Though it seems I have done as they told I got a error message like:
*... ::__construct() must be an instance of Zend\Db\TableGateway\TableGateway, none given, called in ...*
which seems service locator is not used properly.
My form code that adds my FieldSet SupplierFieldset:
namespace Inventory\Form;
use Zend\Form\Form;
use Inventory\Model;
class ItemForm extends Form
{
public function init()
{
$this->add(array(
'name' => 'sup_code',
'type' => 'Inventory\Form\SupplierFieldset'
));
}
}
My 'SupplierFieldset' class:
namespace Inventory\Form;
use Inventory\Model;
use Zend\Form\Element;
use Zend\Form\Fieldset;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\InputFilter\InputFilterProviderInterface;
use Inventory\Model\SupplierTable;
use Inventory\Model\Supplier;
class SupplierFieldset extends Fieldset implements ServiceLocatorAwareInterface
{
protected $serviceLocator;
protected $supplierTable;
public function init()
{
parent::__construct('Suppliers Code');
$this->setLabel('Supplier Code');
$this->setName('supplier_code');
$suppliers = $this->getSupplierTable()->fetchAll();
$select = new Element\Select('supplier_code');
$options = array();
foreach ($suppliers as $supplier) {
$options[$supplier->id] = $supplier->sup_code;
}
$select->setValueOptions($options);
}
public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
{
$this->serviceLocator = $serviceLocator;
}
public function getServiceLocator()
{
return $this->serviceLocator;
}
public function getSupplierTable()
{
if (!$this->supplierTable) {
$sm = $this->getServiceLocator();
$this->supplierTable = $sm->get('Inventory\Model\SupplierTable');
}
return $this->supplierTable;
}
}
My Module.php getFormElementConfig() function:
public function getFormElementConfig()
{
return array(
'factories' => array(
'SupplierFieldset' => function($sm) {
$serviceLocator = $sm->getServiceLocator();
$supplierTable = $serviceLocator->get('Inventory\Model\SupplierTable');
$fieldset = new SupplierFieldset($supplierTable);
return $fieldset;
}
)
);
}
My SupplierTable.php model:
namespace Inventory\Model;
use Zend\Db\TableGateway\TableGateway;
class SupplierTable
{
protected $tableGateway;
public function __construct(TableGateway $tableGateway)
{
$this->tableGateway = $tableGateway;
}
public function fetchAll()
{
$resultSet = $this->tableGateway->select();
return $resultSet;
}
}
I know SupplierTable model's constructor needs a TableGateway $tableGateway parameter. But this model is working properly when called from SupplierController.
I know this question is already answered here. But this doesnt work for me.
The Form is generated by using the PluginLoader:
$formClass = Zend_Registry::get('formloader')->load('Payment');
$form = new $formClass(array('someval' => $my_arr));
Payment.php:
class Form_Payment extends Zend_Form
{
protected $_someval = array();
public function init()
{
$this->setAction('payment/save');
//....
$this->addElement('multiCheckbox', 'store_id', array('label' => 'Someval:', 'required' => true, 'multiOptions' => $this->getSomeval()))
}
public function setSomeval($someval) {
$this->_someval = $someval;
}
public function getSomeval() {
return $this->_someval;
}
}
As I can see the load method only returns the class name, so new $formClass(); is equal new Form_Payment() but why this isn't accept params?
Ok I found a way by myself. I was looking for a way to inject some params while my Zend_Form was initialised. It seems the only way for this is to pass the params to the constructor - which is executed before the init method.
class Form_Payment extends Zend_Form
{
private $_someval;
public function __construct(array $params = array())
{
$this->_someval = $params['someval'];
parent::__construct();
}
public function init()
{
$this->setAction('payment/save');
//....
$this->addElement('multiCheckbox', 'store_id',
array('label' => 'Someval:',
'required' => true,
'multiOptions' => $this->_someval // passed params now available
))
}
}
You can add custom function to your form class like
class Form_Payment extends Zend_Form
{
public function init()
{
$this->setAction('payment/save');
// and so on
}
public function doSome()
{
$this->setAction('other/action');
}
}
and call it after instanciating form in controller
$form = new $formClass();
$form->doSome();