Doctrine 2 + Zend Form - Populate Dynamic Select Menus - zend-framework

I'm building a Zend form that has a dropdown/select menu populated with data from a Doctrine 2 query.
In my repository class, I have the following query in a method named selectUser():
$query = $em->createQuery('SELECT u.id, u.name FROM XX\Entity\Users u ORDER BY u.name ASC');
$users = $query->getResult();
This returns a multidimensional array, which I'm trying to loop through like this (within the same method):
$options = array();
foreach ($users as $key => $value) {
$options[$value['id']] = $value['name'];
}
return $options;
Then in my Zend form class, I try to populate the Select element like this:
$id = new Zend_Form_Element_Select('id');
$options = $this->usersRepository->selectUser();
$id->AddMultiOptions($options);
The result is an error for each user row that states "Undefined index: [name] in ...UsersRepository.php..." where [name] is the value of the 'name' column in each row.
Does anyone see what I'm doing wrong or how to populate a dynamic select menu using Doctrine 2 and Zend Framework?
(By the way, in order to run the repository method, the form class has protected properties representing the Doctrine container, entity manager, and Users repository. If this isn't considered best practice, I'd welcome any suggestions on improving my technique.)

I think your problem is here
$options[$value['id'] = $value['name']];
this would be better
$options[$value['id']] = $value['name'];

Related

CakePHP 3 - Exclude fields by default in query unless specifically selected

Title pretty much says it all. I have some tables with fields that contain a lot of data. To save some performance I would like to not SELECT these by default.
The emphasis on the new default behaviour, differentiating the question from e.g. Select all except one field in cakephp 3 query
Example:
$cities = $this->Cities->find();
// A $city does not include the field `shape` (which is a huge polygon)
$cities = $this->Cities->find(['id', 'name', 'shape']);
// A $city now does include the `shape` property
I looked at the accessible and hidden properties of an entity, but these don't seem to affect the SELECT statement.
EDIT: The selectAllExcept query seems usefull. I combined this with the beforeFilter event like this:
public function beforeFind($event, $query, $options, $primary)
{
$query->selectAllExcept($this, ['shape']);
}
This works well for empty queries, shape is now excluded. But now I have no control over the other fields that might want to include or not:
$this->Cities->find()->select(['id', 'shape']) will then also select the other fields because the selectAllExcept().
You can simple overwrite find('all') method in your table.
For example in UsersTable:
public function findAll(Query $query, array $options)
{
$query->selectAllExcept($this, ['password']);
return $query;
}
then in your controller:
// select all except password
$users = $this->Users->find();
debug($users);
OR
// we try to select some fields, without success
$users = $this->Users->find()->select(['id', 'username', 'password']);
debug($users);
OR
// we try to select some fields incl. password, with success
$users = $this->Users->find()->select(['id', 'username', 'password'], true); // <-- this overwrite select / selectAllExcept in custom finder
debug($users);

Yii2: How to do a simple join query?

I am learning how to do simple queries using the Yii2 framework. I use PostgreSQL.
I am trying to join two tables and get the data from both tables with a where condition.
The tables are called Admins and Persons.
The join use field called idadm.
The condition is idadm = 33. This works great but the result has data only from the Admins table and I need data from the other table.
Here is my example:
$query = \app\models\Admins::find()
->select('*')
->leftJoin('persons', 'persons.idadm = admins.idadm')
->where(['admins.idadm' => 33])
->with('persons')
->all();
I am following the Yii2 official guide: http://www.yiiframework.com/doc-2.0/guide-db-active-record.html
Update: Here I show the updated code that doesn't solve de problem:
You need to write all column name in select().
$query = \app\models\Admins::find()
->select('admin.*,persons.*') // make sure same column name not there in both table
->leftJoin('persons', 'persons.idadm = admins.idadm')
->where(['admins.idadm' => 33])
->with('persons')
->all();
And also you need to define person table attributes in Admin model.
Second way is get records as array,so you dont need to define attributes in Admin model.
$query = \app\models\Admins::find()
->select('admin.*,persons.*') // make sure same column name not there in both table
->leftJoin('persons', 'persons.idadm = admins.idadm')
->where(['admins.idadm' => 33])
->with('persons')
->asArray()
->all();
Ensure that active record has required relations, e.g. something like follows:
class Admins extends \yii\db\ActiveRecord {
public function table() {
return "admins";
}
public function getPersons()
{
return $this->hasMany(Person::className(), ['idadm' => 'idadm']);
}
}
class Person extends \yii\db\ActiveRecord {
public function table() {
return "persons";
}
}
Then use joinWith to build query:
$query = Admins::find()
->joinWith('persons')
->limit(1);
$result = $query->createCommand()->getSql();
echo $result;
Here is produced query:
SELECT `admins`.* FROM `admins`
LEFT JOIN `person` ON `admins`.`idadm` = `person`.`idadm` LIMIT 1

How should a `FormType` be structured in order to include an `EntityType` field which doesn't exist in the `FormType` entity?

Taking the below as an example, OrderType is based on the entity Order. The form that is required needs to contain the following two EntityType dropdowns within it:
Category (this does not exist in Order - it is just to subset the dropdown of Product to make it more manageable)
Product
The identifying Category variables (Category_id and CatName) only exists within the Product entity (the Order can include multiple Products) and as a result, Symfony throws back an error saying:
Neither the property "category_id" nor one of the methods "getcategory_id()", "category_id()", "iscategory_id()", "hascategory_id()", "__get()" exist and have public access in class "AppBundle\Entity\Order".
Is there a way that this Category field can be included even though it doesn't exist in the Order entity?
It doesn't seem right to add category_id to the Order entity. I was thinking of something along the lines of below using 'mapped'=>'false' but I can't get it to work:
$builder
->add('category_id','entity',array(
'class'=>'AppBundle:Product',
'placeholder' => '-- Choose --',
'choice_label'=>'CatName',
'mapped'=>'false',
'query_builder'=>function(EntityRepository $er) {
return $er->createQueryBuilder('p');
}))
...and then after an Ajax response, feed in the category back in with $category?
->add('products','entity',array(
'class'=>'AppBundle:Order',
'placeholder' => '-- Choose --',
'choice_label'=>'ProductName',
'query_builder'=>function(EntityRepository $er, $category ) {
return $er->createQueryBuilder('p')
->where('p.category_id = :id')
->setParameter('id', $category )
->orderBy('p.ProductName','ASC');
}));
}
As you say, adding a Category property to the Order entity just for forms is less than ideal. What I would do is make a OrderCategoryType and pass in Order and Category as an array.
// Controller
$order = new Order();
$category = new Category(); // Or create from $order->getProduct()
$data = ['order' => $order, 'category' => $category);
$form = $this->createFormBuilder($data)
->add('order',new OrderType(),
->add('category',new CategoryType()
);
You will have to do some messing around to keep everything in sync but it should work just fine.

Query in multiple embedded Collection Forms

In addition to my previous question. I now want to limit the input fields of my form. So that there are only input fields for the Supplier for example with the id: 2 . And not the whole collection of suppliers related to the Order. The problem is, that I have an embedded collection in an embedded collection. And i give $order to my first formtype.
$order = $this->getDoctrine()
->getRepository('AcmeAppBundle:PurchaseOrder')
$form = $this->createForm(new ProducedAmountOrderType(), $order);
My problem is, that I can't use query builder in a form type for collections. So, how can I display only the input fields for one supplier and not for everyone related to the Entity?
I solved it with this $order query:
$order = $this->getDoctrine()->getManager()->createQuery("
SELECT o, a , s
FROM AcmeAppBundle:PurchaseOrder o
JOIN o.purchaseOrders a
JOIN a.articleOrderReferences s
WHERE o.id = :orderId
AND s.supplier = :supplierId
AND s.amount > 0
")
->setParameter('orderId', $orderId)
->setParameter('supplierId', $supplierId)
->getOneOrNullResult();

How to get a Doctrine2 result object as an associative array?

I have a simple entity which is a table holding my user data
and I want to fetch all columns of a specific user as an array and then json_encode them but what I get is an entity object which I will have to use get method for every value. I just want an associative array of my user table values.
The codes I tried and didn't work (returned entity object) are as follows:
1.
$qb = $this->em->createQueryBuilder();
$qb->add('select', 'a')
->add('from', 'Entities\Adminprofile a')
->add('where', 'a.userid = 3333');
$accounts = $qb->getQuery()->getResult();
2.
$account = $this->em->getRepository('Entities\Adminprofile')->findOneBy(
array('userid' => '3333'));
PS: im using z2d2 Project,which is doctrine2 integration into Zend framework.
When you do $accounts = $qb->getQuery()->getResult(); the argument you pass to getResult tells it how to hydrate the result set which is will return.
Array Hydration
If you want arrays, than you should pass the CONSTANT for array hydrations Doctrine\ORM\Query::HYDRATE_ARRAY.
$accounts = $qb->getQuery()->getResult( Doctrine\ORM\Query::HYDRATE_ARRAY );
If you are using findOneBy() then it will always return an entity. Due to the internals of how find works, you cannot tell it to hydrate by any other means other than to return entities.
In this scenario, what you need to do is create a getValues() method inside of your entity which returns an array of your entity, like this:
public function getSimpleValues(){
return array(
'id' => $this->getId(),
'lft' => $this->getLft(),
'rgt' => $this->getRgt(),
'name' => $this->getName(),
'md5Name' => $this->getMd5Name(),
'owner' => $this->getOwner()->getId(),
'etag' => $this->getEtag()
);
}
Hydration API Docs: http://www.doctrine-project.org/api/orm/2.1/namespace-Doctrine.ORM.Internal.Hydration.html
You can also use getArrayResult() as a shortcut to passing in the constant to get an array back:
$accounts = $qb->getQuery()->getArrayResult();
You should use constant containing value 2 and it is inbuilt, you can do it like this at the end part of your query
$qb->getQuery()->getResult( Doctrine\ORM\Query::HYDRATE_ARRAY );
$data = $this->entity->findOneBy(array('key' => $value));
$hydrator = new \DoctrineModule\Stdlib\Hydrator\DoctrineObject($this->_em, $entity_name);
$array = $hydrator->extract($data);