TYPO3 Extbase - Failing to render json via typnum
Next to list/edit/new/remove action (which work) I tried to render the output in json. But no values render. If I do a simple ...
$data = array('value'=>'001');
return json_encode($data);
It does return ...
{"value":"001"}
What am I missing?
Edit: With using and referencing to the same repository its working:
JSONController.php
<?php
namespace Vendor\Lei\Controller;
use Vendor\Lei\Domain\Model\Lei;
/**
* JSONController
*/
class JSONController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController {
/**
* leiRepository
*
* #var \Vendor\Lei\Domain\Repository\LeiRepository
* #inject
*/
protected $leiRepository;
/**
* #var string
*/
protected $defaultViewObjectName = 'TYPO3\CMS\Extbase\Mvc\View\JsonView';
/**
* action jsonRequest
*
* #return void
*/
public function jsonRequestAction() {
//$data = array('value'=>'001');
//return json_encode($data);
$this->view->setVariablesToRender(array('records'));
$this->view->assign('records', $this->leiRepository->jsonRequest());
}
}
LeiRepository.php
<?php
namespace Vendor\Lei\Domain\Repository;
use TYPO3\CMS\Extbase\Persistence\QueryInterface;
class LeiRepository extends \TYPO3\CMS\Extbase\Persistence\Repository {
...
public function jsonRequest() {
$query = $this->createQuery();
$result = $query->setLimit(100)->execute();
return $result;
}
}
If you inject and use a JsonRepository extbase expexts a domain object called Json. If you just want to render already existing domain objects as their JSON representation, just use the same repositories you used in your listAction() and detailAction().
Have a look at my example: https://usetypo3.com/json-view.html
Also, a debug after the return like you did in your repository will never be executed.
Related
I'm having an issue that I thought would be VERY simple to accomplish. I can not get this very basic request validation to work. I can enter "Bob" on the create form and the edit form and get no error messages. It simply inserts into the database.
Here's my code. I feel I'm doing/not doing something stupid.
UserCrudController.php
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Requests\UserRequest;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
/**
* Class UserCrudController
* #package App\Http\Controllers\Admin
* #property-read \Backpack\CRUD\app\Library\CrudPanel\CrudPanel $crud
*/
class UserCrudController extends CrudController
{
use \Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\CreateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\ShowOperation;
/**
* Configure the CrudPanel object. Apply settings to all operations.
*
* #return void
*/
public function setup()
{
CRUD::setModel(\App\Models\User::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/user');
CRUD::setEntityNameStrings('user', 'users');
}
/**
* Define what happens when the List operation is loaded.
*
* #see https://backpackforlaravel.com/docs/crud-operation-list-entries
* #return void
*/
protected function setupListOperation()
{
CRUD::column('name');
CRUD::column('email');
//CRUD::column('password');
/**
* Columns can be defined using the fluent syntax or array syntax:
* - CRUD::column('price')->type('number');
* - CRUD::addColumn(['name' => 'price', 'type' => 'number']);
*/
}
/**
* Define what happens when the Create operation is loaded.
*
* #see https://backpackforlaravel.com/docs/crud-operation-create
* #return void
*/
protected function setupCreateOperation()
{
CRUD::setValidation(UserRequest::class);
CRUD::field('name');
CRUD::field('email');
//CRUD::field('password');
/**
* Fields can be defined using the fluent syntax or array syntax:
* - CRUD::field('price')->type('number');
* - CRUD::addField(['name' => 'price', 'type' => 'number']));
*/
}
/**
* Define what happens when the Update operation is loaded.
*
* #see https://backpackforlaravel.com/docs/crud-operation-update
* #return void
*/
protected function setupUpdateOperation()
{
$this->setupCreateOperation();
}
}
UserRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// only allow updates if the user is logged in
return backpack_auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => ['required','min:5','max:255'],
];
}
/**
* Get the validation attributes that apply to the request.
*
* #return array
*/
public function attributes()
{
return [
//
];
}
/**
* Get the validation messages that apply to the request.
*
* #return array
*/
public function messages()
{
return [
//
];
}
}
I think what is happening is that you are not loading that controller.
If you have installed PermissionManager and now want to configure the UserCrudController you need to either manually register the routes yourself and point to your new controller, or alternativelly (and probably recommended) bind your new controller to the package one so your controller gets "served" instead of the package controller.
// In AppServiceProvider.php or any other provider of your choice:
$this->app->bind(
\Backpack\PermissionManager\app\Http\Controllers\UserCrudController::class,
\App\Http\Controllers\Admin\UserCrudController::class
);
If you don't need to change everything in the Controller you can directly extend the package UserCrudController and only change the things you need.
<?php
namespace App\Http\Controllers\Admin;
class UserCrudController extends \Backpack\PermissionManager\app\Http\Controllers\UserCrudController
{
}
The package controller already extends the CrudController.
The validation is added on setupCreateOperation() that you can override to fit your needs.
Cheers
I recently decided to use Zend Framework 3 after 3 years of using Zend Framework 1. This decision has given me headaches, Zend 3 instead of making things easier made things more difficult.
In Zend 1, I customize the url for the selected template in the database as follows:
public function getUrl(string $file = '')
{
if($this->_helperBaseUrl === null) {
$this->_helperBaseUrl = new Zend_View_Helper_BaseUrl();
}
return $this->_helperBaseUrl->baseUrl($file);
}
public function getSkinUrl(string $file = '')
{
$themePath = 'themes/my-theme/'; //get from database
return $this->getUrl($themePath . ltrim($file, '/\\'));
}
Then in any part of the application (models, helpers, plugins and views) I can access this function like this:
//view/scripts/index/index.phtml
$url_logo = My::app()->getSkinUrl('logo.jpg');
//this return http://example.com/themes/my-theme/logo.jpg
In Zend 3 it has been very difficult for me. Does anyone know of any way to do it in Zend 3? Or How to get the baseUrl from a model in Zend 3?
In Zend Framework 2/3 you can inject almost any class into another. For example if you need basePath plugin (which is available in view context) you can inject this plugin into your model/service or controller class. This is the recommended way:
This is class where you need this plugin or any other service
use Zend\View\Helper\BasePath;
class MyService
{
/**
* #var BasePath
*/
protected $plugin;
/**
* MyService constructor.
*
* #param BasePath $basePath
*/
public function __construct(BasePath $basePath)
{
$this->plugin = $basePath;
}
/**
* #return BasePath
*/
public function getPlugin()
{
return $this->plugin;
}
/**
* #param BasePath $plugin
*/
public function setPlugin($plugin)
{
$this->plugin = $plugin;
}
}
Now, you need to factory to inject one dependency into another
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use MyNamespace\Service\MyService;
class MyServiceFactory implements FactoryInterface
{
/**
*
* #param ContainerInterface $container
* #param string $requestedName
* #param null|array $options
* #return MyService
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$class = $requestedName ? $requestedName : MyService::class;
$plugin = $container->get('ViewHelperManager')->get('BasePath'); // inject this class
$myService = new $class($plugin); // into this class
return $myService;
}
/**
* Provided for backwards compatibility; proxies to __invoke().
*
* #param ContainerInterface|ServiceLocatorInterface $container
* #return MyService
*/
public function createService(ServiceLocatorInterface $container)
{
return $this($container, MyService::class);
}
}
Ok, now MyService has basePath plugin, but to use it in controller you have to inject your service into controller. So...
IndexController
use MyNamespace\Service\MyService;
use Zend\Mvc\Controller\AbstractActionController;
class IndexController extends AbstractActionController
{
/**
* #var MyService
*/
protected $service;
/**
* IndexController constructor.
*
* #param MyService $service
*/
public function __construct(MyService $service)
{
$this->service = $service;
}
public function indexAction()
{
$plugin = $this->service->getPlugin(); // Zend\View\Helper\BasePath object
//...
}
}
... and factory for our controller...
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use MyNamespace\Controller\IndexController;
class IndexControllerFactory implements FactoryInterface
{
/**
*
* #param ContainerInterface $container
* #param string $requestedName
* #param null|array $options
* #return IndexController
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$class = $requestedName ? $requestedName : IndexController::class;
$myService = $container->getServiceLocator()->get('MyNamespace\Service\MyService');
$controller = new $class($myService);
return $controller;
}
/**
* Provided for backwards compatibility; proxies to __invoke().
*
* #param ContainerInterface|ServiceLocatorInterface $container
* #return IndexController
*/
public function createService(ServiceLocatorInterface $container)
{
return $this($container, IndexController::class);
}
}
It's almost done. Last step is to set configuration in module.config.php file
use MyNamespace\Controller;
use MyNamespace\Factory;
return [
//...
'service_manager' => [
'factories' => [
Service\MyService::class => Factory\Service\MyServiceFactory::class
]
],
'controllers' => [
'factories' => [
Controller\IndexController::class => Factory\Controller\IndexControllerFactory::class
],
],
]
Easy, isn't it?
If you need plugin in controller, but not in your model/service class, you can skip MyService part of this "tutorial" and inject plugin directly into controller class
I'm using FOSRestBundle in a Symfony project. When it I try to handle a view, it fails during the serialization of my data with the Symfony serializer as well as with the JMSSerializer.
This is the method rendering the response:
DefaultController.php
$em = $this->getDoctrine()->getManager('magellan');
$qb = $em->createQueryBuilder();
$query = $qb->select('h')
->from('DataBundle:Holding', 'h')
->where($qb->expr()->eq('h.id', ':holding_id'))
->setParameter('holding_id', $holding_id)
->getQuery();
$results = $query->getResult();
$view = $this->view($results, 200);
// Everything's ok up to this point
return $this->handleview($view);
And these are my entities:
Holding.php
class Holding
{
...
/**
* #ORM\OneToMany(targetEntity="Subsidiary", mappedBy="holding")
*/
private $subsidiaries;
}
Subsidiary.php
class Subsidiary
{
...
/**
* #ORM\ManyToOne(targetEntity="Holding", inversedBy="subsidiaries")
* #ORM\JoinColumn(name="id_holding", referencedColumnName="id_holding")
*/
private $holding;
/**
* #ORM\OneToMany(targetEntity="Brand", mappedBy="subsidiary")
*/
private $brands;
}
Brand.php
class Brand
{
...
/**
* #ORM\ManyToOne(targetEntity="Subsidiary", inversedBy="brands")
* #ORM\JoinColumn(name="id_subsidiary", referencedColumnName="id_subsidiary")
*/
private $subsidiary;
/**
* #ORM\OneToMany(targetEntity="Product", mappedBy="brand")
*/
private $products;
}
Product.php
class Product
{
...
/**
* #ORM\ManyToOne(targetEntity="Brand", inversedBy="products")
* #ORM\JoinColumn(name="id_brand", referencedColumnName="id_brand")
*/
private $brand;
/**
* #ORM\ManyToOne(targetEntity="Sector", inversedBy="products")
* #ORM\JoinColumn(name="id_sector", referencedColumnName="id_sector")
*/
private $sector;
/**
* #ORM\OneToMany(targetEntity="Commercial", mappedBy="product")
*/
private $commercials;
}
Commercial.php
class Commercial
{
...
/**
* #ORM\ManyToOne(targetEntity="Product", inversedBy="commercials")
* #ORM\JoinColumn(name="id_product", referencedColumnName="id_product")
*/
private $product;
/**
* #ORM\OneToMany(targetEntity="CommercialReport", mappedBy="commercial")
*/
private $reports;
CommercialReport.php
class CommercialReport
{
...
/**
* #ORM\ManyToOne(targetEntity="Commercial", inversedBy="reports")
* #ORM\JoinColumn(name="id_commercial", referencedColumnName="id_commercial")
*/
private $commercial;
}
Sector.php
class Sector
{
...
/**
* #ORM\OneToMany(targetEntity="Product", mappedBy="sector")
*/
private $products;
}
When using the default symfony serializer, I get the following error:
"message":"A circular reference has been detected (configured limit:
1).","class":"Symfony\Component\Serializer\Exception\CircularReferenceException"
And when using the JMSSerializer, when I go to the corresponding page of the controller, the page just never finishes loading. At the same time in the dev.log file new Doctrine.debug entries with requests to my DB are added every second.
$normalizers->setCircularReferenceHandler(function ($object) {
return $object->getId();
});
Just add it after you make the instance if your objectNormalizer()
it worl perfectly for me
If you use FosRestBundle, you can use the GROUPS for the serializer. There is an annotation given by FosRestBundle : #FOS\RestBundle\Controller\Annotations\View(serializerGroups={"user"})
Your group can exclude the circular property.
Another idea you can do this. In your app/config/services.yml
circular_reference_handler:
public: false
class: callback
factory: [AppBundle\Serializer\CircularHandlerFactory, getId]
serializer.normalizer.object:
class: Symfony\Component\Serializer\Normalizer\ObjectNormalizer
arguments: ["#serializer.mapping.class_metadata_factory", null, "#serializer.property_accessor"]
public: false
tags: [serializer.normalizer]
calls:
- method: setCircularReferenceLimit
arguments: [1]
- method: setCircularReferenceHandler
arguments: ["#circular_reference_handler"]
The factory can be like this:
namespace AppBundle\Serializer;
class CircularHandlerFactory
{
/**
* #return \Closure
*/
public static function getId()
{
return function ($object) {
return $object->getId();
};
}
}
I'm trying to use a m:n relation, the same way as FrontEndUser is related to FrontEndUserGroup, e.g. without intermediate mm table. In my controller, I build my object, then I call $barRepository->update($barObject); to update the values of my object. However, it fails on the update function with the error:
Fatal error: Call to undefined method Cbrunet\Up\Domain\Model\Foo::getPosition() in /home/cbrunet/websites/typo3_src-6.1.1/typo3/sysext/extbase/Classes/Persistence/Generic/Backend.php on line 486
where Foo is the type of the object contained in the ObjectStorage of Bar. My understanding is that getPosition should be called on the ObjectStorage, not on the object contained into that ObjectStorage. However, I cannot figure out why this is not working in my case.
This is in TYPO3 6.1.5. Any hint would be appreciated.
The model of Bar which has a m:n relation to Foo looks like:
namespace Cbrunet\Up\Domain\Model;
class Bar extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {
/**
* #var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Cbrunet\Up\Domain\Model\Foo>
*/
protected $myprop;
public function __construct() {
$this->myprop = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
}
/**
* #param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $myprop
* #return void
*/
public function setMyprop(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $myprop) {
$this->myprop = $myprop;
}
/**
* #param \Cbrunet\Up\Domain\Model\Foo $myprop
* #return void
*/
public function addMyprop(\Cbrunet\Up\Domain\Model\Foo $myprop) {
$this->myprop->attach($myprop);
}
/**
* #param \Cbrunet\Up\Domain\Model\Foo $myprop
* #return void
*/
public function removeMyprop(\Cbrunet\Up\Domain\Model\Foo $myprop) {
$this->myprop->detach($myprop);
}
/**
* #return \TYPO3\CMS\Extbase\Persistence\ObjectStorage
*/
public function getMyprop() {
return $this->myprop;
}
}
The relevant code in my controller looks like:
/**
* action update
*
* #return void
*/
public function updateAction() {
$args = $this->request->getArgument('myargs');
foreach ($args as $k=>$val) {
$pp = $this->barRepository->findOneByAprop($k); // another prop of Bar, not illustrated in the code above.
$listepour = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
foreach ($val as $p) {
$ap = $this->fooRepository->findOneByUid(intval($p));
$listepour->attach($ap);
}
$pp->setMyprop($listepour);
$this->barRepository->update($pp); // error occurs here
}
$this->redirect('list');
}
Do you also have configured your TCA?
do you have an initStorageObjects-function in your domain model?
Also you can try to build these case with the extension-manager and compare the code.
How do I inject the service manager into a Doctrine repository to allow me to retrieve the Doctrine Entity Manager?
I using the ZF2-Commons DoctrineORMModule and are trying to implement the repository example listed in the Doctrine Tutorial (bottom of tutorial in link below):
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/getting-started.html
However, I keep getting a message "Fatal error: Call to a member function get() on a non-object in C:\zendProject\zf2 ... ", which suggests that I do not have a working instance of the service locator.
My Doctrine repository looks like this:
namespace Calendar\Repository;
use Doctrine\ORM\EntityRepository,
Calendar\Entity\Appointment,
Calendar\Entity\Diary;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class ApptRepository extends EntityRepository implements ServiceLocatorAwareInterface
{
protected $services;
public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
{
$this->services = $serviceLocator;
}
public function getServiceLocator()
{
return $this->services;
}
public function getUserApptsByDate()
{
$dql = "SELECT a FROM Appointment a";
$em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
$query = $em()->createQuery($dql);
return $query->getResult();
}
}
I then want to call this in my controller using the following pattern:
$diary = $em->getRepository('Calendar\Entity\Appointment')->getUserApptsByDate();
EDIT: The attached link suggests that I may need to convert the class to a service,
https://stackoverflow.com/a/13508799/1325365
However, if this is the best route, how would I then make my Doctrine Entity aware of the service. At the moment I include an annotation in the doc block pointing to the class.
#ORM\Entity (repositoryClass="Calendar\Repository\ApptRepository")
The way i approach things is this:
First i register a Service for each entity. This is done inside Module.php
public function getServiceConfig()
{
return array(
'factories' => array(
'my-service-entityname' => 'My\Factory\EntitynameServiceFactory',
)
);
}
Next thing would be to create the factory class src\My\Factory\EntitynameServiceFactory.php. This is the part where you inject the EntityManager into your Entity-Services (not into the entity itself, the entity doesn't need this dependency at all)
This class looks something like this:
<?php
namespace My\Factory;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\ServiceManager\FactoryInterface;
use My\Service\EntitynameService;
class EntitynameServiceFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$service = new EntitynameService();
$service->setEntityManager($serviceLocator->get('Doctrine\ORM\EntityManager'));
return $service;
}
}
Next thing in line is to create the src\My\Service\EntitynameService.php. And this is actually the part where you create all the getter functions and stuff. Personally i extend these Services from a global DoctrineEntityService i will first give you the code for the EntitynameService now. All this does is to actually get the correct repository!
<?php
namespace My\Service;
class EntitynameService extends DoctrineEntityService
{
public function getEntityRepository()
{
if (null === $this->entityRepository) {
$this->setEntityRepository($this->getEntityManager()->getRepository('My\Entity\Entityname'));
}
return $this->entityRepository;
}
}
This part until here should be quite easy to understand (i hope), but that's not all too interesting yet. The magic is happening at the global DoctrineEntityService. And this is the code for that!
<?php
namespace My\Service;
use Zend\EventManager\EventManagerAwareInterface;
use Zend\EventManager\EventManagerInterface;
use Zend\ServiceManager\ServiceManagerAwareInterface;
use Zend\ServiceManager\ServiceManager;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityRepository;
class DoctrineEntityService implements
ServiceManagerAwareInterface,
EventManagerAwareInterface
{
protected $serviceManager;
protected $eventManager;
protected $entityManager;
protected $entityRepository;
/**
* Returns all Entities
*
* #return EntityRepository
*/
public function findAll()
{
$this->getEventManager()->trigger(__FUNCTION__ . '.pre', $this, array('entities' => $entities));
$entities = $this->getEntityRepository()->findAll();
$this->getEventManager()->trigger(__FUNCTION__ . '.post', $this, array('entities' => $entities));
return $entities;
}
public function find($id) {
return $this->getEntityRepository()->find($id);
}
public function findByQuery(\Closure $query)
{
$queryBuilder = $this->getEntityRepository()->createQueryBuilder('entity');
$currentQuery = call_user_func($query, $queryBuilder);
// \Zend\Debug\Debug::dump($currentQuery->getQuery());
return $currentQuery->getQuery()->getResult();
}
/**
* Persists and Entity into the Repository
*
* #param Entity $entity
* #return Entity
*/
public function persist($entity)
{
$this->getEventManager()->trigger(__FUNCTION__ . '.pre', $this, array('entity'=>$entity));
$this->getEntityManager()->persist($entity);
$this->getEntityManager()->flush();
$this->getEventManager()->trigger(__FUNCTION__ . '.post', $this, array('entity'=>$entity));
return $entity;
}
/**
* #param \Doctrine\ORM\EntityRepository $entityRepository
* #return \Haushaltportal\Service\DoctrineEntityService
*/
public function setEntityRepository(EntityRepository $entityRepository)
{
$this->entityRepository = $entityRepository;
return $this;
}
/**
* #param EntityManager $entityManager
* #return \Haushaltportal\Service\DoctrineEntityService
*/
public function setEntityManager(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
return $this;
}
/**
* #return EntityManager
*/
public function getEntityManager()
{
return $this->entityManager;
}
/**
* Inject an EventManager instance
*
* #param EventManagerInterface $eventManager
* #return \Haushaltportal\Service\DoctrineEntityService
*/
public function setEventManager(EventManagerInterface $eventManager)
{
$this->eventManager = $eventManager;
return $this;
}
/**
* Retrieve the event manager
* Lazy-loads an EventManager instance if none registered.
*
* #return EventManagerInterface
*/
public function getEventManager()
{
return $this->eventManager;
}
/**
* Set service manager
*
* #param ServiceManager $serviceManager
* #return \Haushaltportal\Service\DoctrineEntityService
*/
public function setServiceManager(ServiceManager $serviceManager)
{
$this->serviceManager = $serviceManager;
return $this;
}
/**
* Get service manager
*
* #return ServiceManager
*/
public function getServiceManager()
{
return $this->serviceManager;
}
}
So what does this do? This DoctrineEntityService pretty much is all what you globally need (to my current experience). It has the fincAll(), find($id) and the findByQuery($closure)
Your next question (hopefully) would only be "How to use this from my controller now?". It's as simple as to call your Service, that you have set up in the first step! Assume this code in your Controllers
public function someAction()
{
/** #var $entityService \my\Service\EntitynameService */
$entityService = $this->getServiceLocator()->get('my-service-entityname');
// A query that finds all stuff
$allEntities = $entityService->findAll();
// A query that finds an ID
$idEntity = $entityService->find(1);
// A query that finds entities based on a Query
$queryEntity = $entityService->findByQuery(function($queryBuilder){
/** #var $queryBuilder\Doctrine\DBAL\Query\QueryBuilder */
return $queryBuilder->orderBy('entity.somekey', 'ASC');
});
}
The function findByQuery() would expect an closure. The $queryBuilder (or however you want to name that variable, you can choose) will be an instance of \Doctrine\DBAL\Query\QueryBuilder. This will always be tied to ONE Repository though! Therefore entity.somekey the entity. will be whatever repository you are currently working with.
If you need access to the EntityManager you'd either only instantiate only the DoctrineEntityService or call the $entityService->getEntityManager() and continue from there.
I don't know if this approach is overly complex or something. When setting up a new Entity/EntityRepository, all you need to do is to add a new Factory and a new Service. Both of those are pretty much copy paste with two line change of code in each class.
I hope this has answered your question and given you some insight of how work with ZF2 can be organized.
As long as you extend the Doctrine\ORM\EntityRepository, you have immediate access to the entity manager by calling EntityRepository::getEntityManager() or the $_em attribute. The inheritence from the Doctrine\ORM\EntityRepository class allow you to do so.
Your method should now look like this:
public function getUserApptsByDate()
{
$dql = "SELECT a FROM Appointment a";
$em = $this->getEntityManager();// Or $em=$this->_em;
$query = $em()->createQuery($dql);
return $query->getResult();
}
I always keep in mind that access to my data should go from the web front (Zend MVC, Service Manager) to the persistence layer (Doctrine). My persistence (entities, repositories...) layer should not refer to the web front or neither know that it exists. If my system is doing the inverse at some level, then probably I'm doing something wrong.
Happy end of year