ZF2 form removing nested collection after validation - doctrine-orm

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();
}

Related

Inserting data to database using zf3 and doctrine

i'm trying to insert data to database but submitted forms does nothing.
this is my service manager:
class AutosManager
{
/**
* Entity manager.
* #var Doctrine\ORM\EntityManager;
*/
private $entityManager;
/**
* Constructor.
*/
public function __construct($entityManager)
{
$this->entityManager = $entityManager;
}
public function addNewAutos($data)
{
$autos = new Autos();
$autos->setTitle($data['title']);
$autos->setDescription($data['description']);
$currentDate = date('Y-m-d H:i:s');
$autos->setDateCreated($currentDate);
$this->entityManager->persist($autos);
$this->entityManager->flush();
}
this is my controller addAction
public function addAction()
{
// Create the form.
$form = new PostForm();
if ($this->getRequest()->isPost()) {
// Get POST data.
$data = $this->params()->fromPost();
// Fill form with data.
$form->setData($data);
if ($form->isValid()) {
// Get validated form data.
$data = $form->getData();
$this->AutosManager->addNewAutos($data);
return $this->redirect()->toRoute('retrieve');
}
}
return new ViewModel([
'form' => $form
]);
}
i can retrieve data from database to the index page but i cannot add. hope to find the solution.
this is my Autos Entity
namespace Retrieve\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity(repositoryClass="\Retrieve\Repository\AutosRepository")
* #ORM\Table(name="auto")
*/
class Autos
{
/**
* #ORM\Id
* #ORM\Column(name="id")
* #ORM\GeneratedValue
*/
protected $id;
/**
* #ORM\Column(name="title")
*/
protected $title;
/**
* #ORM\Column(name="description")
*/
protected $description;
/**
* #ORM\Column(name="featured")
*/
protected $featured;
/**
* #ORM\Column(name="date_created")
*/
protected $dateCreated;
/**
* Returns ID of this post.
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Sets ID of this post.
* #param int $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* Returns title.
* #return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Sets title.
* #param string $title
*/
public function setTitle($title)
{
$this->title = $title;
}
/**
* Returns featured.
* #return integer
*/
public function getFeatured()
{
return $this->featured;
}
/**
* Sets featured.
* #param integer $featured
*/
public function setFeatured($featured)
{
$this->featured = $featured;
}
/**
* Returns post description.
*/
public function getDescription()
{
return $this->description;
}
/**
* Sets post description.
* #param type $description
*/
public function setDescription($description)
{
$this->description = $description;
}
/**
* Returns the date when this post was created.
* #return string
*/
public function getDateCreated()
{
return $this->dateCreated;
}
/**
* Sets the date when this post was created.
* #param string $dateCreated
*/
public function setDateCreated($dateCreated)
{
$this->dateCreated = $dateCreated;
}
}
hope this helps to find solution.
I found the problem: it was an inputfilter element I wasn't using that was authenticating in forms. But the solution only brings me to a different problem:
Notice: Undefined index: title in C:\xampp\htdocs\ameyaw\module\BusinessGhana\src\Service\AutosManager.php on line 38
Notice: Undefined index: description in C:\xampp\htdocs\ameyaw\module\BusinessGhana\src\Service\AutosManager.php on line 39
Notice: Undefined index: featured in C:\xampp\htdocs\ameyaw\module\BusinessGhana\src\Service\AutosManager.php on line 58
Message:
An exception occurred while executing 'INSERT INTO auto (title, description, featured, date_created) VALUES (?, ?, ?, ?)' with params [null, null, null, "2017-06-15 05:04:44"]:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'title' cannot be null
this is my form and fieldset
use Zend\Form\Fieldset;
use Doctrine\Common\Persistence\ObjectManager;
use DoctrineModule\Persistence\ObjectManagerAwareInterface;
use BusinessGhana\Entity\Autos;
class AddFieldset extends Fieldset
{
protected $objectManager;
public function init()
{
$this->add([
'type' => 'text',
'name' => 'title',
'attributes' => [
'id' => 'autoTitle'
],
'options' => [
'label' => 'Title',
'display_empty_item' => true,
'empty_item_label' => 'Maximum of 60 characters',
],
]);
$this->add([
'type' => 'textarea',
'name' => 'description',
'attributes' => [
'id' => 'autoDescription'
],
'options' => [
'label' => 'Description',
'display_empty_item' => true,
'empty_item_label' => 'description',
],
]);
$this->add([
'type' => 'radio',
'name' => 'featured',
'attributes' => [
'id' => 'autoFeatured'
],
'options' => array(
'label' => 'Featured',
'value_options' => array(
array('value' => '0',
'label' => 'No',
'selected' => true,
'label_attributes' => array(
'class' => 'col-sm-2 btn btn-default',
),
),
array(
'value' => '1',
'label' => 'Yes',
'label_attributes' => array(
'class' => 'col-sm-2 btn btn-danger',
),
),
),
'column-size' => 'sm-12',
'label_attributes' => array(
'class' => 'col-sm-2',
),
),
]);
}
}
use Zend\Form\Form;
//use Zend\InputFilter\InputFilter;
class AddForm extends Form
{
public function init()
{
$this->add([
'name' => 'dependentForm',
'type' => AddFieldset::class,
]);
$this->add([
'type' => 'submit',
'name' => 'submit',
'attributes' => [
'value' => 'Submit',
],
]);
}
}
i know hydration can solve this problem but i dont know how to use it yet.

Doctrine Object Select not hydrating as object

I have a form with a fieldset which contains a Doctrine ObjectSelect element.
$this->add(array(
'name' => 'vatRate',
'type' => 'DoctrineModule\Form\Element\ObjectSelect',
'options' => array(
'label' => _('VAT Rate:'),
'object_manager' => $this->getEntityManager(),
'target_class' => 'Application\Entity\VatRates',
'property' => 'title',
'is_method' => true,
'find_method' => array(
'name' => 'getVatRatesOrderRate',
),
'label_generator' => function($targetEntity) {
return $targetEntity->getTitle() . ' (' . $targetEntity->getVatRate() . '%)';
},
'disable_inarray_validator' => TRUE,
),
));
In my invoiceItems entity I have
/**
* #var \Application\Entity\VatRates
*
* #ORM\ManyToOne(targetEntity="Application\Entity\VatRates")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="vat_rate_id", referencedColumnName="vat_rate_id")
* })
*/
private $vatRate;
/**
*
* #param VatRates|NULL $vatRate
* #return \Application\Entity\InvoiceItems
*/
public function setVatRate(VatRates $vatRate = NULL)
{
$this->vatRate = $vatRate;
return $this;
}
The problem I am having is that when I validate the form Doctrine's DoctrineObject hydrator is not converting the vatRate to an entity before passing it to the setter. I get the following error.
Catchable fatal error: Argument 1 passed to Application\Entity\InvoiceItems::setVatRate() must be an instance of Application\Entity\VatRates, integer given, called in C:\Users\User\OneDrive\Documents\My Webs\freedomsnew\vendor\doctrine\doctrine-module\src\DoctrineModule\Stdlib\Hydrator\DoctrineObject.php on line 282 and defined in C:\Users\User\OneDrive\Documents\My Webs\freedomsnew\module\Application\src\Application\Entity\InvoiceItems.php on line 339
As can be seen by the error message the integer vatRateId is being sent to the invoiceItems entity setVatRate method.
I have other forms/fieldsets setup in a similar way and all work with no problems. Does anyone know what I have done wrong here?
The problem was that Doctrine had cached the entity. Clearing the cache solved the problem.
php ./vendor/doctrine/doctrine-module/bin/doctrine-module orm:clear-cache:query
php ./vendor/doctrine/doctrine-module/bin/doctrine-module orm:clear-cache:metadata
php ./vendor/doctrine/doctrine-module/bin/doctrine-module orm:clear-cache:result
I setup a batch file to do this from now on.

Dynamic added fieldset/ collection not added to database Zend 2 Doctrin 2

After browsing several tutorials reagrding Zend2 /Doctrine 2 and Fieldsets i finally figured out the filedset/collction.
But new "fields" wont be added to the database table. Any changes in the existing elements are stored. Major Class Organization callsthe fieldset ActBusinessCountry:
Major Class Organization
class Organization {
protected $inputFilter;
/**
* #ORM\Id
* #ORM\Column(type="integer");
*/
protected $id;
/**
* #ORM\Column(type="string")
*/
protected $organizational;
/**
* #ORM\Column(type="string")
*/
protected $structure;
/**
* #param \Doctrine\Common\Collections\ArrayCollection
* #ORM\OneToMany(targetEntity="People\Entity\ActBusinessCountry",mappedBy="company",cascade={"persist", "merge", "refresh", "remove"})
*/
protected $organizaton_opcountry;
public function __construct()
{
$this->organizaton_opcountry = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* #param \Doctrine\Common\Collections\ArrayCollection $organizaton_opcountry
*/
public function addOrganizaton_opcountry(Collection $organizaton_opcountry)
{
foreach ($organizaton_opcountry as $opcountry) {
$this->organizaton_opcountry->add($opcountry);
}
return $this->organizaton_opcountry;
}
public function removeOrganizaton_opcountry(Collection $organizaton_opcountry)
{
foreach ($organizaton_opcountry as $opcountry) {
$tag->setCompany(null);
$this->organizaton_opcountry->removeElement($opcountry);
}
}
/**
* #return Collection
*/
public function getOrganizaton_opcountry()
{
return $this->organizaton_opcountry;
}
Sub class/fieldset is ActBusinessCountry
class ActBusinessCountry {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
public $id;
/**
* #ORM\ManyToOne(targetEntity="People\Entity\Organization",inversedBy="organizaton_opcountry")
* #ORM\JoinColumn(name="company_id", referencedColumnName="id")
*/
public $company;
/**
* #ORM\Column(type="string")
*/
public $country;
/**
* #ORM\Column(type="string")
*/
public $company_id;
/**
* Allow null to remove association
*/
public function setId($id = null)
{
$this->id = $id;
}
public function getId()
{
return $this->id;
}
public function getCompany()
{
return $this->company;
}
public function setCompany(Company $company = null)
{
$this->company = $company;
}
public function getCountry()
{
return $this->country;
}
public function setCountry($country)
{
$this->country = $country;
}
}
Organization Form:
$countrySelect = new ActBusinessCountryFieldset($objectManager);
$this->add(array(
'type' => 'Zend\Form\Element\Collection',
'name' => 'organizaton_opcountry',
'options' => array(
'should_create_template' => true,
'use_as_base_fieldet' => true,
'count' => 1,
'allow_add' => true,
'target_element' => $countrySelect,
),
));
Fielset Elements:
class ActBusinessCountryFieldset extends Fieldset implements ObjectManagerAwareInterface
{
protected $objectManager;
public function __construct(ObjectManager $objectManager)
{
$this->setObjectManager($objectManager);
parent::__construct('fieldset');
$this ->setHydrator(new DoctrineHydrator($objectManager, 'People\Entity\ActBusinessCountry'))
->setObject(new \People\Entity\ActBusinessCountry());
$this->add(array(
'type' => 'Zend\Form\Element\Hidden',
'name' => 'id'
));
$this->add(array(
'type' => 'DoctrineModule\Form\Element\ObjectSelect',
'name' => 'country',
'attributes' => array(
'class' => 'form-control input-small',
),
'options' => array(
'object_manager' => $this->getObjectManager(),
'target_class' => 'People\Entity\Country',
'value' => 'country',
'property' => 'country_name',
'class'=>'form-control',
'label_attributes' => array(
'class'=> 'col-sm-3 control-label',
),
),
));
}
public function getInputFilterSpecification()
{
return array(
'id' => array(
'required' => false
)
);
return array(
'country' => array(
'required' => true
)
);
}
Controller Flushing Part:
if ($this->request->isPost()) {
// Cancel button
if(isset($_POST['cancel'])) {
echo "<script>window.close();</script>";
}
$form->setData($this->request->getPost());
var_dump($this->request->getPost('organizaton_opcountry'));
var_dump($queryresult->getOrganizaton_opcountry());
//$queryresult->addOrganizaton_opcountry();
if ($form->isValid()) {
// Security request
if ($this->isAllowed('admin_res','admin_priv')) {
$form->bindValues();
$this->getEntityManager()->persist($queryresult);
$this->getEntityManager()->flush();
}
//echo "<script>window.close();</script>";
}
}
I am afraid, that i just missed a point. Though the post var_dump($this->request->getPost('organizaton_opcountry')); in the controller does output the following, after adding a third element and submitting:
array
0 =>
array
'id' => string '1' (length=1)
'country' => string 'Chad' (length=4)
1 =>
array
'id' => string '2' (length=1)
'country' => string 'Bermuda' (length=7)
2 =>
array
'id' => string '' (length=0)
'country' => string '(Not Specified)' (length=15)
Maybe you guys have an idea, or you have had the same problem before.
Thank you very much for any hint.
Kind regards,
David
Maybe u take a look at:
Saving a Doctine 2 Entity that contains an ObjectSelect element using Zend Form
Check the inputFilter in the Fieldset and add an inputfilter for the fieldset in the form e.g.:
$this->setValidationGroup(array(
'User' => array(
'name',
'role' // <- Fieldset
)
));

Zend Framework 2 Doctrine 2 one-to-many checkbox hydration

I have a ManyToMany that I broke into OneToMany and ManyToOne relationship. I want to build a form that has checkboxes instead of collection, and I am using the 'DoctrineObject' hydrator, but it does not work and I don't know what is going wrong.
I removed from my code below all of the other not related fields.
Role Entity:
/**
* #orm\Entity
* #orm\Table(name="roles")
*/
class RolesEntity extends HemisEntity {
/**
* #orm\Id
* #orm\Column(type="integer");
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #orm\Column(name="role_code",type="string")
*/
protected $roleCode;
/**
* #orm\OneToMany(targetEntity="RolesPermissionsEntity", mappedBy="role", cascade={"persist"})
*/
protected $rolePermissions;
public function __construct()
{
$this->rolePermissions = new ArrayCollection();
}
public function setRolePermissions($rolePermissions)
{
$this->rolePermissions = $rolePermissions;
return $this;
}
public function addRolePermissions(Collection $rolePermissions)
{
foreach ($rolePermissions as $rolePermission) {
$rolePermission->setRole($this);
$this->rolePermissions->add($rolePermission);
}
}
public function removeRolePermissions(Collection $rolePermissions)
{
foreach ($rolePermissions as $rolePermission) {
$rolePermission->setRole(null);
$this->rolePermissions->removeElement($rolePermission);
}
}
public function getRolePermissions()
{
return $this->rolePermissions;
}
}
The ManyToMany table entity (it has more fields and so I broke it):
/**
* #orm\Entity
* #orm\Table(name="roles_permissions")
*/
class RolesPermissionsEntity extends HemisEntity {
/**
* #orm\Id
* #orm\Column(type="integer");
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #orm\ManyToOne(targetEntity="RolesEntity", inversedBy="rolePermissions")
* #orm\JoinColumn(name="role_id", referencedColumnName="id")
**/
protected $role;
/**
* #orm\ManyToOne(targetEntity="PermissionsEntity", inversedBy="permissionRoles")
* #orm\JoinColumn(name="permission_id", referencedColumnName="id")
**/
protected $permission;
public function setRole($role)
{
$this->role = $role;
return $this;
}
public function getRole()
{
return $this->role;
}
public function setPermission($permission)
{
$this->permission = $permission;
return $this;
}
public function getPermission()
{
return $this->permission;
}
}
My form look like this:
class RoleForm extends Form implements InputFilterProviderInterface
{
public function __construct(ObjectManager $objectManager)
{
parent::__construct('role');
$this->setHydrator(new DoctrineHydrator($objectManager))
->setObject(new RolesEntity());
$this->add(array(
'type' => 'Zend\Form\Element\Hidden',
'name' => 'id'
));
$this->add(array(
'type' => 'Zend\Form\Element\Text',
'name' => 'roleCode',
'options' => array(
'label' => 'Role Code'
),
));
$this->add(array(
'name' => 'rolePermissions',
'type' => 'DoctrineModule\Form\Element\ObjectMultiCheckbox',
'options' => array(
'label' => 'Permissions',
'object_manager' => $objectManager,
'target_class' => 'Hemis\Fnd\PermissionsEntity',
'property' => 'permissionDesc'
),
));
$this->add(array(
'name' => 'submit',
'type' => 'Submit',
'attributes' => array(
'value' => 'Submit',
),
));
}
public function getInputFilterSpecification()
{
return array(
'roleCode' => array(
'required' => false
),
'rolePermissions' => array(
'required' => true
)
);
}
}
The problem is that when I dump the $role it does not contains any rolePermissions and even that they are passed from the form they are just not hydrated into the object. I hope that my question is clear.
Any idea about what is wrong with my code or there is a better way to do that using checkboxes?
class RoleForm extends Form implements InputFilterProviderInterface
{
public function __construct(ObjectManager $objectManager)
{
// ...
$this->add(array(
'name' => 'rolePermissions',
'type' => 'Zend\Form\Element\Collection',
'options' => array(
'label' => 'Role Permissions',
'count' => 0,
'should_create_template' => true,
'allow_add' => true,
'target_element' => array(
'type' => 'Zend\Form\Fieldset',
'options' => array(
'use_as_base_fieldset' => true
),
'elements' => array(
// add form fields for the properties of the RolesPermissionsEntity class here
array(
'name' => 'id',
'type' => 'Zend\Form\Element\Hidden',
),
array(
'name' => 'role',
'type' => 'Zend\Form\Element\Checkbox',
// other options
),
// ...
),
),
),
));
// ...
}
// ...
}

How to paginate using Zend2/Doctrine combo (using the Doctrine provided paginator adapter)?

I've been looking for examples/guides on how to do what I asked.
I've found several examples and "best" I've found yet is this one => http://blog.loftdigital.com/blog/doctrine-plus-zf2-tips-pagination
2 problems
I'm not really sure if my paginator object contains the right number of records (I limited it to 5 records on my adapter object)
I don't know how to traverse the paginator object in my view file. it seems very complex. I did a print_r on the object enclosing the thing in a pre HTML tag and it's easily 20+K lines on my text editor (after copy/paste)
Can you please help?
thank you very much
my controller code based from the example (not really working but no zend/doctrine errors too. problem is that it gives me all the records instead of just 10)
$directory->populate($form->getData());
$adapter = new DoctrineAdapter(new ORMPaginator($directoryDao->searchStaffDirectory($this->getEntityManager()->createQueryBuilder(), $directory)));
$adapter->getItems(0, 5);
//var_dump($adapter->getItems(0, 5)); **//display the corrent number of records**
$paginator = new Paginator($adapter);
$paginator->setDefaultItemCountPerPage(5);
$page = (int)$this->params()->fromQuery("page");
if($page) $paginator->setCurrentPageNumber($page);
return array('staffList' => $paginator);
my DirectoryDAO class (the relevant parts)
public function searchStaffDirectory(QueryBuilder $queryBuilder, DirectoryModel $directory) {
$conditions = new Andx;
$queryBuilder
->select('directory')
->from('Directory\Model\DirectoryModel', 'directory');
if (strlen($directory->surnameSearch)) {
$conditions->add($queryBuilder->expr()->like('directory.surnameSearch', "'".preg_replace('/\s+/', '', $directory->surnameSearch)."%'"));
}
if (strlen($directory->surnameSoundsSearch)) {
$conditions->add($queryBuilder->expr()->like('directory.surnameSoundsSearch', preg_replace('/\s+/', '', $directory->surnameSoundsSearch)));
}
if (strlen($directory->firstnameSearch)) {
$conditions->add($queryBuilder->expr()->like('directory.firsnameSearch', preg_replace('/\s+/', '', $directory->firstnameSearch)));
}
if (strlen($directory->telephoneNumber)) {
$conditions->add($queryBuilder->expr()->like('directory.telephoneNumber', preg_replace('/\s+/', '', $directory->telephoneNumber)));
}
if (strlen($directory->departmentSearch)) {
$conditions->add($queryBuilder->expr()->like('directory.departmentSearch', preg_replace('/\s+/', '', $directory->departmentSearch)));
}
if (strlen($directory->roleSearch)) {
$conditions->add($queryBuilder->expr()->like('directory.roleSearch', preg_replace('/\s+/', '', $directory->roleSearch)));
}
if ($conditions->count()) {
$queryBuilder->andWhere($conditions);
}
$queryBuilder
->orderBy('directory.surname');
return $queryBuilder->getQuery();
}
my DirectoryModel class
<?php
namespace Directory\Model;
use Doctrine\ORM\Mapping;
use Zend\InputFilter\Factory;
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;
/**
* #Mapping\Entity
* #Mapping\Table(name="staffdirectory_vw")
*/
class DirectoryModel {
/**
*
* #Mapping\Id
* #Mapping\Column(name="mytable_pk", type="integer", unique=true)
*/
protected $pk;
/**
*
* #Mapping\Column(name="mytable_id", type="string")
*/
protected $id;
/**
*
* #Mapping\Column(name="mytable_parent_id", type="string")
*/
protected $parentId;
/**
*
* #Mapping\Column(name="mytable_auth_code", type="string")
*/
protected $fan;
/**
*
* #Mapping\Column(name="mytable_full_name", type="string")
*/
protected $fullname;
/**
*
* #Mapping\Column(name="mytable_name_title", type="string")
*/
protected $title;
/**
*
* #Mapping\Column(name="mytable_first_pref_name", type="string")
*/
protected $firstname;
/**
*
* #Mapping\Column(name="mytable_surname", type="string")
*/
protected $surname;
/**
*
* #Mapping\Column(name="mytable_bldg_long_desc", type="string")
*/
protected $building;
/**
*
* #Mapping\Column(name="mytable_display_department", type="string")
*/
protected $department;
/**
*
* #Mapping\Column(name="mytable_alias", type="string")
*/
protected $email;
/**
*
* #Mapping\Column(name="mytable_alias_list", type="string")
*/
protected $emailList;
/**
*
* #Mapping\Column(name="mytable_entity_type", type="string")
*/
protected $entityType;
/**
*
* #Mapping\Column(name="mytable_org_heirarchy", type="string")
*/
protected $organisationalHeirarchy;
/**
*
* #Mapping\Column(name="mytable_role", type="string")
*/
protected $role;
/**
*
* #Mapping\Column(name="mytable_room", type="string")
*/
protected $room;
/**
*
* #Mapping\Column(name="mytable_tele_number", type="string")
*/
protected $telephoneNumber;
/**
*
* #Mapping\Column(name="mytable_tele_number_formats", type="string")
*/
protected $telephoneNumberFormats;
/**
*
* #Mapping\Column(name="mytable_tele_rank", type="string")
*/
protected $teleRank;
/**
*
* #Mapping\Column(name="mytable_url", type="string")
*/
protected $url;
/**
*
* #Mapping\Column(name="mytable_search_surname", type="string")
*/
protected $surnameSearch;
/**
*
* #Mapping\Column(name="mytable_surname_soundex", type="string")
*/
protected $surnameSoundsSearch;
/**
*
* #Mapping\Column(name="mytable_search_first_name", type="string")
*/
protected $firstnameSearch;
/**
*
* #Mapping\Column(name="mytable_search_department", type="string")
*/
protected $departmentSearch;
/**
*
* #Mapping\Column(name="mytable_search_role", type="string")
*/
protected $roleSearch;
/**
*
* #Mapping\Column(name="mytable_tele_directory", type="string")
*/
protected $teleDirectory;
protected $inputFilter;
/**
* Magic getter to expose protected properties.
*
* #param string $property
* #return mixed
*/
public function __get($property) {
return $this->$property;
}
/**
*
* Magic setter to save protected properties.
*
* #param string $property
* #param mixed $value
*/
public function __set($property, $value) {
$this->$property = $value;
}
/**
* Convert the object to an array.
*
* #return array
*/
public function getArrayCopy() {
return get_object_vars($this);
}
/**
* Populate from an array.
*
* #param array $data
*/
public function populate($data = array()) {
$this->pk = isset($data['pk']) ? $data['pk'] : null;
$this->id = isset($data['id']) ? $data['id'] : null;
$this->fan = isset($data['fan']) ? $data['fan'] : null;
$this->fullname = isset($data['fullname']) ? $data['fullname'] : null;
$this->surname = isset($data['surname']) ? $data['surname'] : null;
$this->building = isset($data['building']) ? $data['building'] : null;
$this->department = isset($data['department']) ? $data['department'] : null;
$this->email = isset($data['email']) ? $data['email'] : null;
$this->emailList = isset($data['emailList']) ? $data['emailList'] : null;
$this->entityType = isset($data['entityType']) ? $data['entityType'] : null;
$this->organisationalHeirarchy = isset($data['organisationalHeirarchy']) ? $data['organisationalHeirarchy'] : null;
$this->role = isset($data['role']) ? $data['role'] : null;
$this->room = isset($data['room']) ? $data['room'] : null;
$this->telephoneNumber = isset($data['telephoneNumber']) ? $data['telephoneNumber'] : null;
$this->telephoneNumberFormats = isset($data['telephoneNumberFormats']) ? $data['telephoneNumberFormats'] : null;
$this->teleRank = isset($data['teleRank']) ? $data['teleRank'] : null;
$this->url = isset($data['url']) ? $data['url'] : null;
$this->surnameSearch = isset($data['surnameSearch']) ? $data['surnameSearch'] : null;
$this->surnameSoundsSearch = isset($data['surnameSoundsSearch']) ? $data['surnameSoundsSearch'] : null;
$this->firstnameSearch = isset($data['firstnameSearch']) ? $data['firstnameSearch'] : null;
$this->departmentSearch = isset($data['departmentSearch']) ? $data['departmentSearch'] : null;
$this->roleSearch = isset($data['roleSearch']) ? $data['roleSearch'] : null;
$this->teleDirectory = isset($data['teleDirectory']) ? $data['teleDirectory'] : null;
}
public function setInputFilter(InputFilterInterface $inputFilter) {
throw new \Exception("Not used");
}
public function getInputFilter() {
if (!$this->inputFilter) {
$inputFilter = new InputFilter();
$factory = new Factory();
$inputFilter->add($factory->createInput(array(
'name' => 'surnameSearch',
'required' => false,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringToUpper'),
array('name' => 'StringTrim'),
),
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'min' => 1,
'max' => 30,
),
),
),
)));
$inputFilter->add($factory->createInput(array(
'name' => 'surnameSoundsSearch',
'required' => false,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringToUpper'),
array('name' => 'StringTrim'),
),
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'min' => 1,
'max' => 30,
),
),
),
)));
$inputFilter->add($factory->createInput(array(
'name' => 'firstnameSearch',
'required' => false,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringToUpper'),
array('name' => 'StringTrim'),
),
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'min' => 1,
'max' => 30,
),
),
),
)));
$inputFilter->add($factory->createInput(array(
'name' => 'telephoneNumberSearch',
'required' => false,
'filters' => array(
array('name' => 'Int'),
),
)));
$inputFilter->add($factory->createInput(array(
'name' => 'departmentSearch',
'required' => false,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringToUpper'),
array('name' => 'StringTrim'),
),
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'min' => 1,
'max' => 30,
),
),
),
)));
$inputFilter->add($factory->createInput(array(
'name' => 'roleeSearch',
'required' => false,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringToUpper'),
array('name' => 'StringTrim'),
),
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'min' => 1,
'max' => 30,
),
),
),
)));
$this->inputFilter = $inputFilter;
}
return $this->inputFilter;
}
}
I assume DoctrineAdapter is actually DoctrineORMModule\Paginator\Adapter\DoctrinePaginator just you imported it with a different name. If not, then this is the class you should be using.
Your controller should be:
$directory->populate($form->getData());
$adapter = new DoctrineAdapter(new ORMPaginator($directoryDao->searchStaffDirectory($this->getEntityManager()->createQueryBuilder(), $directory)));
$paginator = new Paginator($adapter);
$paginator->setItemCountPerPage(5);
$page = (int)$this->params()->fromQuery("page");
$paginator->setCurrentPageNumber($page);
return array('staffList' => $paginator);
No need to call getItems and when you cast $page to int then it will automatically default to the first page if no page parameter is passed.
Using the paginator in the view is more complex. First you need to implement a view script that renders the paginator. There are a number of example scripts in the ZF2 documentation which you can either use outright or base your own paginator off:
http://framework.zend.com/manual/2.2/en/modules/zend.paginator.usage.html#example-pagination-controls
To use the paginator in your actual view, you can iterate over it like any other query result to display your items:
<?php foreach($staffList as $staff): ?>
Firstname: <?php echo $staff->firstname; ?>
etc.
<?php endforeach; ?>
This will only display items currently for the current page that the paginator is on, which is what you want.
To display the paginator controls:
<?php echo $this->paginationControl($staffList, '<paginator type>', '<my paginator view script>', array('route' => '<route name>')); ?>
Paginator type can be: All, Elastic, Jumping, Sliding and determines how and what page numbers are displayed on the paginator controls. Sliding is the default and is most likely the best choice.