Doctrine DQL Extention not working in Zend Framework 2 - doctrine-orm

I have just added a DQL extension into my ZF2 app but it is not working.
The extension should allow a match against query.
In my module.config.php I have
'doctrine' => array(
'driver' => array(
'Application_driver' => array(
'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
'cache' => 'array',
'paths' => array(__DIR__ . '/../src/Application/Entity')
),
'orm_default' => array(
'drivers' => array(
'Application\Entity' => 'Application_driver'
),
),
),
'configuration' => array(
'orm_default' => array(
'string_functions' => array(
'MatchAgainst' => 'Freedom\Doctrine\ORM\AST\Functions\MatchAgainstFunction',
),
'datetime_functions' => array(),
'numeric_functions' => array(),
'metadata_cache' => 'filesystem',
'query_cache' => 'filesystem',
'result_cache' => 'filesystem',
),
),
),
and in my DQL I have
$builder->andwhere('MATCH (`t.title`) AGAINST (:title)')
->setParameter('title', $param);
The extension is not even being executed all I get is an error.
Error: Expected known function, got 'MATCH'
Does anyone know what I am missing?
Many thanks in advance.
EDIT
I have got the extension working by changing the line from 'MatchAgainst' => 'Freedom\Doctrine\ORM\AST\Functions\MatchAgainstFunction', to 'Match' => 'Freedom\Doctrine\ORM\AST\Functions\MatchAgainstFunction',.
The problem I am having now is the DQL query is still not working.
My DQL extension looks like
namespace Freedom\Doctrine\ORM\AST\Functions;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
/**
* MatchAgainstFunction ::=
* "MATCH" "(" StateFieldPathExpression {"," StateFieldPathExpression}* ")" "AGAINST" "("
* StringPrimary ["BOOLEAN"] ["EXPAND"] ")"
*/
class MatchAgainstFunction extends FunctionNode
{
/** #var array list of \Doctrine\ORM\Query\AST\PathExpression */
protected $pathExp = null;
/** #var string */
protected $against = null;
/** #var boolean */
protected $booleanMode = false;
/** #var boolean */
protected $queryExpansion = false;
public function parse(Parser $parser)
{
// match
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
// first Path Expression is mandatory
$this->pathExp = array();
$this->pathExp[] = $parser->StateFieldPathExpression();
// Subsequent Path Expressions are optional
$lexer = $parser->getLexer();
while ($lexer->isNextToken(Lexer::T_COMMA)) {
$parser->match(Lexer::T_COMMA);
$this->pathExp[] = $parser->StateFieldPathExpression();
}
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
// against
if (strtolower($lexer->lookahead['value']) !== 'against') {
$parser->syntaxError('against');
}
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->against = $parser->StringPrimary();
if (strtolower($lexer->lookahead['value']) === 'boolean') {
$parser->match(Lexer::T_IDENTIFIER);
$this->booleanMode = true;
}
if (strtolower($lexer->lookahead['value']) === 'expand') {
$parser->match(Lexer::T_IDENTIFIER);
$this->queryExpansion = true;
}
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(SqlWalker $walker)
{
$fields = array();
foreach ($this->pathExp as $pathExp) {
$fields[] = $pathExp->dispatch($walker);
}
$against = $walker->walkStringPrimary($this->against)
. ($this->booleanMode ? ' IN BOOLEAN MODE' : '')
. ($this->queryExpansion ? ' WITH QUERY EXPANSION' : '');
return sprintf('MATCH (%s) AGAINST (%s)', implode(', ', $fields), $against);
}
}
and in my DQL I have
$builder->andWhere('MATCH (t.title) AGAINST (:title)')
->setParameter('title', $param);
Now I am getting the error
[Syntax Error] line 0, col 204: Error: Expected =, <, <=, <>, >, >=, !=, got 'ORDER'
Does anyone know why Doctrine is looking for a comparison operator?

I have got the extension working by changing the line from 'MatchAgainst' => 'Freedom\Doctrine\ORM\AST\Functions\MatchAgainstFunction', to 'Match' => 'Freedom\Doctrine\ORM\AST\Functions\MatchAgainstFunction',
In answer to my second question I found this works
$builder->andWhere('MATCH (t.title) AGAINST (:title BOOLEAN) > 0')
->setParameter('title', $param);

Related

ZF2 form removing nested collection after validation

I have three related Doctrine entities that I am trying to use with Zend Form collections.
The entities are InvoiceItems -> (one to many) -> InvoiceItemOptions -> (one to many) InvoiceItemOptionValues.
When I add a new item all options and values are populating the entity correctly. However when I edit a item the values are being removed from the options entity. The form displays correctly so the values are being pulled from the database and DoctrineObject hydrator is populating the form. The values are lost after the form is validated.
My entity code
InvoiceItems
/**
* #var \Doctrine\ORM\PersistentCollection
*
* #ORM\OneToMany(targetEntity="Application\Entity\InvoiceItemOptions", cascade={"persist"}, orphanRemoval=true, mappedBy="invoiceItem")
* })
*/
private $options;
InvoiceItemOptions
/**
* #var \Application\Entity\InvoiceItems
*
* #ORM\ManyToOne(targetEntity="Application\Entity\InvoiceItems", cascade={"persist"}, inversedBy="options")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="invoice_item_id", referencedColumnName="invoice_item_id")
* })
*/
private $invoiceItem;
/**
* #var \Doctrine\ORM\PersistentCollection $values
*
* #ORM\OneToMany(targetEntity="Application\Entity\InvoiceItemOptionValues", cascade={"persist"}, orphanRemoval=true, mappedBy="invoiceItemOption")
* })
*/
private $values;
InvoiceItemOptionValues
/**
* #var integer
*
* #ORM\Column(name="invoice_item_option_value_id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $invoiceItemOptionValueId;
/**
* #var \Application\Entity\InvoiceItemOptions
*
* #ORM\ManyToOne(targetEntity="Application\Entity\InvoiceItemOptions", cascade={"persist"}, inversedBy="values")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="invoice_item_option_id", referencedColumnName="invoice_item_option_id")
* })
*/
private $invoiceItemOption;
/**
* #var string
*
* #ORM\Column(name="value", type="text", length=65536, nullable=false)
*/
private $value;
/**
* #var string
*
* #ORM\Column(name="price", type="decimal", precision=9, scale=2, nullable=false)
*/
private $price;
And in my fieldsets I have
InvoiceItemFieldset
$this->add(array(
'type' => 'Collection',
'name' => 'options',
'options' => array(
'count' => 0,
'should_create_template' => TRUE,
'template_placeholder' => '__OPTION__',
'allow_add' => TRUE,
'allow_remove' => TRUE,
'target_element' => $this->invoiceItemOptionFieldset,
),
));
InvoiceItemOptionFieldset
$this->add(array(
'type' => 'Collection',
'name' => 'values',
'options' => array(
'count' => 0,
'should_create_template' => TRUE,
'template_placeholder' => '__VALUE__',
'target_element' => $this->invoiceItemOptionValuesFieldset,
),
));
InvoiceItemOptionValuesFieldset
public function init()
{
$this->add(array(
'name' => 'invoiceItemOptionValueId',
'type' => 'Hidden'
));
$this->add(array(
'name' => 'value',
'type' => 'Textarea',
'options' => array(
'label' => _('Value:'),
'label_attributes' => array('class' => 'required'),
),
'attributes' => array(
'cols' => 30,
'rows' => 5,
),
));
$this->add(array(
'name' => 'price',
'type' => 'Text',
'options' => array(
'label' => _('Price Inc. VAT:'),
),
'attributes' => array(
'size' => 10,
'maxlength' => 10,
),
));
}
EditItemModel
use Zend\Stdlib\Parameters;
...
public function processForm(Parameters $postData)
{
$entityManager = $this->getEntityManager();
$this->form->setData($postData);
if ($this->form->isValid()) {
// values lost here
$this->form->bind($this->entity);
$this->setFormValid(TRUE);
if ($this->entity->getQuantity() < 1) {
$this->entity->setQuantity(1);
}
$goodsTotal = $this->entity->getPriceEachIncVat() * $this->entity->getQuantity();
$optionsTotal = 0.00;
foreach ($this->entity->getOptions() as $option) {
foreach ($option->getValues() as $value) { // entity has no values
if ($value->getPrice() > 0) {
$optionsTotal = $optionsTotal + ($value->getPrice() * $this->entity->getQuantity());
}
}
}
$this->invoiceModel->calculateItemsVat($this->entity, $goodsTotal, $optionsTotal);
$entityManager->persist($this->entity);
if ($this->flushEntityManager($entityManager)) {
return $this->invoiceModel->calculateInvoiceTotals($this->getInvoice()->getInvoiceId());
}
}
return FALSE;
}
Finally my post data
Array
(
[items] => Array
(
[options] => Array
(
[0] => Array
(
[name] => Test Option 0
[invoiceItemOptionId] => 37
[values] => Array
(
[0] => Array
(
[value] => Test Option 0 Value 0
[price] => 0.00
[invoiceItemOptionValueId] => 37
)
[1] => Array
(
[value] => Test Option 0 Value 1
[price] => 29.99
[invoiceItemOptionValueId] => 38
)
)
)
)
[title] => Title
[sku] =>
[quantity] => 2
[priceEachIncVat] => 1000.00
[vatRate] => 1
[invoiceItemId] => 20
)
)
I am using Zend Framework version 2.5.1 and Doctrine ORM Module version 1.0.0
Hopefully someone knows what is going on here, many thanks in advance.
I have found a solution.
Adding the line $this->form->setBindOnValidate(FormInterface::BIND_MANUAL); before form validation solved the problem. I also added $this->form->bind($this->entity) after validation;
Hope this helps someone.
EDIT
I also found that the array collection for values in InvoiceItemOptions entity was not being cloned during hydration so the InvoiceItemOptionValues were wrong. I solved this issue by adding the magic method __clone() to my InvoiceItemOptions entity.
public function __clone()
{
$this->values = new ArrayCollection();
}

ZF2 inputfilter doctrine NoObjectExists editing object does not validate

So i got a ZF2 application, got a Form and a InputFilter in the InputFilter i have:
$this->add(
array(
'name' => 'email',
'required' => true,
'validators' => array(
array(
'name' => 'EmailAddress'
),
array(
'name' => 'DoctrineModule\Validator\NoObjectExists',
'options' => array(
'object_repository' => $sm->get('doctrine.entitymanager.orm_default')->getRepository('YrmUser\Entity\User'),
'fields' => 'email'
),
),
),
)
);
works great, however when i edit a existing object and save it the NoObjectExists validator says a matching object is found so it doesn't validate.
Is there a solution to this problem?
Or should i just remove the validator on the edit form and catch the exception when a duplicate is inserted?
UPDATE:
How to use DoctrineModule\Validator\NoObjectExists in edit forms - Zend Framework 2 & Doctrine 2
is the same issue but the answer is to just remove the validator on editing, this off-course is not a solution. As you would still have to catch the exception thrown for when inserting a duplicate. I could do that no problem but what im asking for is a solution to make it work WITH NoObjectExists (otherwise whats the use of this validator if i have to catch the exception for duplicates anyway)
UPDATE, added other relevant code (my form and entity have more fields than this but i removed them to keep it readable on here)
FORM:
namespace YrmUser\Form;
use Zend\Form\Form;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator;
use DoctrineORMModule\Stdlib\Hydrator\DoctrineEntity;
use YrmUser\Entity\User;
class UserForm extends Form
{
protected $objectManager;
/**
* __construct description
*
* #param String $name form name
*
* #return void
*/
public function __construct($name = null)
{
parent::__construct('new-user');
}
public function init()
{
$this->setHydrator(
new DoctrineHydrator($this->objectManager, 'YrmUser\Entity\User')
)->setObject(new User());
$this->setAttribute('method', 'post');
$this->add(
array(
'name' => 'email',
'attributes' => array(
'type' => 'email',
'placeholder' =>'Email',
),
'options' => array(
'label' => 'Email',
),
)
);
}
}
FILTER:
class UserFilter extends InputFilter
{
/**
* [__construct description]
*
* #param ServiceLocator $sm servicelocator
*/
public function __construct($sm)
{
$this->add(
array(
'name' => 'email',
'required' => true,
'validators' => array(
array(
'name' => 'EmailAddress'
),
array(
'name' => 'DoctrineModule\Validator\NoObjectExists',
'options' => array(
'object_repository' => $sm->get('doctrine.entitymanager.orm_default')->getRepository('YrmUser\Entity\User'),
'fields' => 'email'
),
),
),
)
);
}
}
CONTROLLER ACTION:
public function editAction()
{
$id = (int) $this->params('id', null);
if (null === $id) {
return $this->redirect()->toRoute('manage-users');
}
$em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
$formManager = $this->getServiceLocator()->get('FormElementManager');
$form = $formManager->get('UserForm');
$user = $em->find('YrmUser\Entity\User', $id);
$form->setInputFilter(new UserFilter($this->getServiceLocator()));
$form->bind($user);
$request = $this->getRequest();
if ($request->isPost()) {
$form->setData($request->getPost());
if ($form->isValid()) {
$em->persist($user);
$em->flush();
return $this->redirect()->toRoute('manage-users');
}
}
return array(
'form' => $form,
'id' => $id
);
}
ENTITY:
class User
{
/**
* #var int
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
* #ORM\Column(type="string", unique=true, length=255)
*/
protected $email;
/**
* Get id.
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set id.
*
* #param int $id user id
*
* #return void
*/
public function setId($id)
{
$this->id = (int) $id;
}
/**
* Get email.
*
* #return string
*/
public function getEmail()
{
return $this->email;
}
/**
* Set email.
*
* #param string $email user email adress
*
* #return void
*/
public function setEmail($email)
{
$this->email = $email;
}
}
thanks in advance,
Yrm
I lately had the same issue on my project, I spend lot of time searching for a solution and I've finally found this module LosBase.
It uses two customs validators which extend DoctrineModule\Validator\NoObjectExists : NoEntityExists for Add action and NoOtherEntityExists for Edit action.
So I used this appraoch to resolve my problem. This is the solution I've made so far :
NoOtherEntityExists validator :
use Zend\Validator\Exception\InvalidArgumentException;
use DoctrineModule\Validator\NoObjectExists;
class NoOtherEntityExists extends NoObjectExists
{
private $id; //id of the entity to edit
private $id_getter; //getter of the id
private $additionalFields = null; //other fields
public function __construct(array $options)
{
parent::__construct($options);
if (isset($options['additionalFields'])) {
$this->additionalFields = $options['additionalFields'];
}
$this->id = $options['id'];
$this->id_getter = $options['id_getter'];
}
public function isValid($value, $context = null)
{
if (null != $this->additionalFields && is_array($context)) {
$value = (array) $value;
foreach ($this->additionalFields as $field) {
$value[] = $context[$field];
}
}
$value = $this->cleanSearchValue($value);
$match = $this->objectRepository->findOneBy($value);
if (is_object($match) && $match->{$this->id_getter}() != $this->id) {
if (is_array($value)) {
$str = '';
foreach ($value as $campo) {
if ($str != '') {
$str .= ', ';
}
$str .= $campo;
}
$value = $str;
}
$this->error(self::ERROR_OBJECT_FOUND, $value);
return false;
}
return true;
}
}
NoEntityExists validator :
use Zend\Validator\Exception\InvalidArgumentException;
use DoctrineModule\Validator\NoObjectExists;
class NoEntityExists extends NoObjectExists
{
private $additionalFields = null;
public function __construct(array $options)
{
parent::__construct($options);
if (isset($options['additionalFields'])) {
$this->additionalFields = $options['additionalFields'];
}
}
public function isValid($value, $context = null)
{
if (null != $this->additionalFields && is_array($context)) {
$value = (array) $value;
foreach ($this->additionalFields as $field) {
$value[] = $context[$field];
}
}
$value = $this->cleanSearchValue($value);
$match = $this->objectRepository->findOneBy($value);
if (is_object($match)) {
if (is_array($value)) {
$str = '';
foreach ($value as $campo) {
if ($str != '') {
$str .= ', ';
}
$str .= $campo;
}
$value = $str;
}
$this->error(self::ERROR_OBJECT_FOUND, $value);
return false;
}
return true;
}
}
Using this validators with inputFilter :
In my custom input filters, I added two methods : one to append the NoEntityExists validator, and the other to append the NoOtherEntityExists validator :
/**
* Appends doctrine's NoObjectExists Validator for Add FORM .
*
* #param \Doctrine\ORM\EntityRepository $repository
* #return \Zend\InputFilter\InputFilter
*/
public function appendAddValidator(EntityRepository $repository)
{
$this->add($this->getFactory()->createInput( array(
'name' => 'libellesite', //unique field name
'validators' => array(
array(
'name' => 'Netman\Form\NoEntityExists',//use namespace
'options' => array(
'object_repository' => $repository,
'fields' => 'libellesite',
'messages' => array(
'objectFound' => 'custom message here'
),
),
),
)
)));
return $this;
}
/**
* Appends doctrine's NoObjectExists Validator for EDIT FORM.
*
* #param \Doctrine\ORM\EntityRepository $repository
* #return \Zend\InputFilter\InputFilter
*/
public function appendEditValidator(EntityRepository $repository, $id)
{
$this->add($this->getFactory()->createInput( array(
'name' => 'libellesite',
'validators' => array(
array(
'name' => 'Netman\Form\NoOtherEntityExists',
'options' => array(
'object_repository' => $repository,
'fields' => 'libellesite',
'id'=>$id, //
'id_getter'=>'getCodesite',//getter for ID
'messages' => array(
'objectFound' => 'custom message here'
),
),
),
)
)));
return $this;
}
Controller :
In the addAction :
$repository = $em->getRepository('Entity\Name');
$form->setInputFilter($filter->appendAddValidator($repository));
In the editAction :
$id = $this->params('id', null);
$repository = $em->getRepository('Entity\Name');
$form->setInputFilter($filter->appendEditValidator($repository,$id));

zend framework 2 Unable to render template resolver could not resolve to a file

I'm learning how to use Zend Framework2. According to some tutorials available on the Net I've wrote some pieces of code . The most important tutorial for me is this one: https://github.com/psamatt/zf2-doctrine-example It covers most of the basics that i've planned to write. I've stuck on one problem that looks strange to me. On my summary page, that display all the records from DB I have a links to add new record, edit existing record, and delete record. Routing is covered by module.config.php:
'router' => array(
'routes' => array(
'incident' => array(
'type' => 'segment',
'options' => array(
'route' => '/incident[/][:action][/:id]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
),
'defaults' => array(
'controller' => 'Helpdesk\Controller\Incident',
'action' => 'index',
),
),
),
),
),
When I use a link to a new record (h.t.t.p://helpdesk/incident/add) everything works correctly. But when I use a link to edit my record (h.t.t.p://helpdesk/incident/edit/1 - where 1 is example record ID) I receive an error:
Zend\View\Renderer\PhpRenderer::render: Unable to render template "helpdesk/incident/edit"; resolver could not resolve to a file
This is my IncidentController.php:
<?php
namespace Helpdesk\Controller;
use Application\Controller\EntityUsingController;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject;
use Doctrine\ORM\EntityManager;
use Zend\View\Model\ViewModel;
use Helpdesk\Form\IncidentForm;
use Helpdesk\Entity\Incident;
class IncidentController extends EntityUsingController
{
/**
* Index action
*
*/
public function indexAction()
{
$em = $this->getEntityManager();
$incidents = $em->getRepository('Helpdesk\Entity\Incident')->findAll();
return new ViewModel(array(
'incidents' => $incidents
));
}
/**
* Edit action
*
*/
public function editAction()
{
$incident = new Incident();
if ($this->params('id') > 0) {
$incident = $this->getEntityManager()->getRepository('Helpdesk\Entity\Incident')->find($this->params('id'));
}
$form = new IncidentForm($this->getEntityManager());
$form->bind($incident);
$form->setHydrator(new DoctrineObject($this->getEntityManager(),'Helpdesk\Entity\Incident'));
$request = $this->getRequest();
if ($request->isPost()) {
$form->setInputFilter($incident->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$em = $this->getEntityManager();
$em->persist($incident);
$em->flush();
$this->flashMessenger()->addSuccessMessage('Incident saved');
// Redirect to list of incidents
return $this->redirect()->toRoute('incident');
}
}
return array(
'incident' => $incident,
'form' => $form,
);
}
/**
* Add action
*
*/
public function addAction()
{
return $this->editAction();
}
/**
* Delete action
*
*/
public function deleteAction()
{
$id = (int)$this->getEvent()->getRouteMatch()->getParam('id');
if (!$id) {
return $this->redirect()->toRoute('incident');
}
$request = $this->getRequest();
if ($request->isPost()) {
$del = $request->post()->get('del', 'No');
if ($del == 'Yes') {
$id = (int)$request->post()->get('id');
$incident = $this->getEntityManager()->find('Helpdesk\Entity\Incident', $id);
if ($incident) {
$this->getEntityManager()->remove($incident);
$this->getEntityManager()->flush();
}
}
// Redirect to list of incidents
return $this->redirect()->toRoute('default', array(
'controller' => 'incident',
'action' => 'index',
));
}
return array(
'id' => $id,
'incident' => $this->getEntityManager()->find('Helpdesk\Entity\Incident', $id)->getArrayCopy()
);
}
}
What is the difference between these two? Why one works fine, while the second one generates an error?
Thanks for your help
Smok.
Most likely helpdesk/incident/edit.phtml does not exist, while add action is rendering an existing helpdesk/incident/add.phtml.
You can reuse the existing helpdesk/incident/add.phtml or create a new one.

Doctrine2 + Zend Framework 2 - EntitiesManager as variable in Controller

I want to set EntitiesManager instance available on my Controller. I want the Instance available with $this->em on Controller. This is my configuration :
module.config.php
[...]
'doctrine' => array(
'driver' => array(
'application_entities' => array(
'class' =>'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
'cache' => 'array',
'paths' => array(__DIR__ . '/../src/Application/Entity')
),
'orm_default' => array(
'drivers' => array(
'Application\Entity' => 'application_entities'
),
),
),
),
'di' => array(
'instance' => array(
'alias' => array(
'application' => 'Application\Controller\IndexController',
),
'Application\Controller\IndexController' => array(
'parameters' => array(
'em' => 'doctrine_em',
),
),
),
),
IndexController.php
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use \Doctrine\ORM\EntityManager;
class IndexController extends AbstractActionController
{
protected $em;
public function setEm(EntityManager $em) {
$this->em = $em;
return $this;
}
public function indexAction() {
$user1 = $this->em->find('\Application\Entity\User', 1);
var_dump($user1->getFullname());
}
I got this error : "Fatal error: Call to a member function find() on a non-object". It seem than EntityManager is not correctly instantiate.
What Am I missing?
Thank you!
You dont need anything in the module config
You edit the Module.php, onbootstrap function
public function onBootstrap(\Zend\EventManager\EventInterface $e) {
$serviceManager = $e->getApplication()->getServiceManager();
$em = $serviceManager;
$controllerLoader = $serviceManager->get('ControllerLoader');
$controllerLoader->addInitializer(function ($controller) use ($em) {
if (method_exists($controller, 'setEm')) {
$controller->setEm($em);
}
});
}
the controller stays as you have it, with the $em field, and the setEm method
//..
protected $em;
public function setEm(EntityManager $em) {
$this->em = $em;
return $this;
}
//..

Form collections in SF2

Offers.php
/**
* #var \ZGoffers\MainBundle\Entity\OfferParameter
*
* #ORM\OneToMany(targetEntity="OfferParameter", mappedBy="offer", cascade={"all"})
*/
private $parameters;
OfferParameter.php
/**
* #var \ZGoffers\MainBundle\Entity\Offer
*
* #ORM\ManyToOne(targetEntity="Offer", inversedBy="offer", cascade={"all"})
*/
private $offer;
OfferType.php
class OfferType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('advertiser')
->add('name')
->add('url', 'text', array('label' => 'URL'))
->add('externalUrl', 'text', array('label' => 'External URL'))
->add('dailyCap', 'text', array('label' => 'Daily Cap'))
->add('parameters', 'collection', array(
'type' => new OfferParameterType(),
'allow_add' => true,
'allow_delete' => true
))
->add('active', 'choice', array(
'choices' => array(0 => 'Disabled', 1 => 'Enabled')
));
}
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'ZGOffers\MainBundle\Entity\Offer'
);
}
}
OfferParameterType.php
class OfferParameterType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('field')
->add('type', 'choice', array(
'choices' => array(
'=' => 'EQUALS',
'>' => 'IS GREATER THAN',
'>=' => 'IS GREATER THAN OR EQUALS',
'<' => 'IS LESS THAN',
'<=' => 'IS GREATER THAN OR EQUALS'
)
))
->add('value');
}
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'ZGOffers\MainBundle\Entity\OfferParameter'
);
}
}
Form Handling
public function process()
{
if ('POST' == $this->request->getMethod()) {
// bind form data
$this->form->bindRequest($this->request);
// If form is valid
if ($this->form->isValid() && ($offer = $this->form->getData()) instanceof Offer) {
foreach ($offer->getParameters() as $parameter) {
$parameter->setOffer($offer); // THIS SHOULDNT BE NEEDED
}
// save offer to the database
$this->entityManager->persist($offer);
$this->entityManager->flush();
return true;
}
}
return false;
}
My question is.... How the hell do you delete elements in form collections in SF2????
I have multiple forms that are just like this one in my project and it's really putting a halt to development :(
Thanks for all help!
You may need to do something like below :
->add('parameters', 'collection', array(
'type' => new OfferParameterType(),
'allow_add' => true,
'allow_delete' => true,
'attr'=>array('style'=>'display:none;')
))
That makes your whole OfferParameterType collection hidden.
Or in OfferParameterType apply same thing for each field like below :
->add('field',null, array('attr'=>array('style'=>'display:none;')))