I'd like to map an entity of a form by myself. The thing is I'm working with 36 000 cities in a database and Doctrine doesn't return any result when I'm performing a request using findBy. But I set this up by writting my owns methods.
The problem is in a form I need to ask for a city through an entity field (because there are a lot of data, I'm using select2 with remote's data). So far, no problem but when I'm submiting the form, Symfony can't bind the city's id to a database entry because of the none result of the classic method of Doctrine.
So, my question is : How can I tell Symfony to use my repository's method instead of the Doctrine's one to bind my data?
Thank you very much ! And have a good day ;)
The method findBy() request an array parameter sometimes people miss that:
$result = $this->getDoctrine()->getManager()
->getRepository("AcmeDemoBundle")->findBy(array(
"city" => $city)
);
If you want to use repository you just need to map it to your class:
/**
* #ORM\Entity(repositoryClass="Acme/DemoBundle/Repository/CountryRepository")
*/
class Country
{ ... }
Then in
class CountryRepository extends EntityRepository
{
public function getMySpecificCity($city)
{
$qb = $this->createQueryBuilder('c');
$cities = $qb->select(*)
->where("c.city =:city ")->setParameter('city', $city)
->getQuery()
->getResult();
return $cities;
}
...
}
So you can use it as follow:
$result = $this->getDoctrine()->getManager()
->getRepository("AcmeDemoBundle")->getMySpecificCity($city);
Related
I have in my Item ORM entity a relationship with Packs.
Now in my code I have a PackId and I have an Item. Now here's what I am trying in my code:
$item->getPackById($pack->getId);
In my Item Entity I try something like this:
public function getPackById(UuidInterface $packId)
{
return $this->packs[$packId];
}
I am not sure If I can do this without a repository or is there a better way?
Normally we try to avoid to much work in an entity but as you are certain that the packs UUID are unique you could try something with an array filter like :
public function getPackById(Uuid $uuid): ?Pack
{
$matching = array_filter((array)$this->packs, fn(Pack $pack) => $pack->getUuid() === $uuid);
return $matching[0];
}
i want to select all users in the database that have the role ROLE_USER only but i get this problm when i call the function they say "Call to a member function getNbr() on null" i think bcoz i use Findby() , bcoz i use the same function in another call and it works great look at the code :
public function indexAction(Request $request)
{
$us = $this->getDoctrine()->getManager();
$locationus = $us->getRepository('AppBundle:Usr')->findBy(
[ 'roles' => ["ROLE_USER"] ]);
echo $nb_us = $locationus->getNbr();
if($authChecker->isGranted(['ROLE_ADMIN']))
{
return $this->render('settingAdmin/profiladmin.html.twig' , array(
'nb_us' => $nb_us,
));
}
and this is the other function in the UserRepository:
class UserRepository extends \Doctrine\ORM\EntityRepository
{
public function getNbr() {
return $this->createQueryBuilder('l')
->select('COUNT(l)')
->getQuery()
->getSingleScalarResult();
}
}
getNbr is method of UserRepository class, so it can be called only for this UserRepository class instance. This method returns total users count.
findBy returns array of entities (in you case all users with role ROLE_USER), not UserRepository class instance, so you can't use getNbr in context of this variable
If you want to get the length of array of entities (in you case all users with role ROLE_USER), just use count function:
echo $nb_us = count($locationus);
if($authChecker->isGranted(['ROLE_ADMIN']))
{
return $this->render('settingAdmin/profiladmin.html.twig' , array(
'nb_us' => $nb_us, 'locationus' => $locationus
));
}
There looks to be quite many things going on in the code there:
1) $us->getRepository('AppBundle:Usr') is probably typoed and should be $us->getRepository('AppBundle:User') instead (?) In general it would be safer to use $us->getRepository(AppBundle\User::class) so that syntax errors can be caught easier/earlier.
2) You are trying to invoke repository method on array with $locationus->getNbr() which is incorrect on multiple accounts (you cannot invoke functions on arrays - and repository methods cannot be invoked from entities either).
3) why is the code using echo?
4) as an additional note (assuming that this is roughly the full intended code), it would make sense to move all the getters & handling inside the if section so that the code will perform better (it doesn't do unnecessary database queries etc when the user doesn't have enough rights to access the view/information).
If I understood the intention correctly, in this case, the second repository function getNbr is superfluous here. If that is intending to just calculate the number of instances returned by the first find:
$locationus = $us->getRepository('AppBundle:User')->findBy(['roles' => ["ROLE_USER"] ]);
$nb_us = count($locationus);
Or alternatively (if you want to use and fix the getNbr repository function) then you don't need the first repository getter. This will require some rewriting of the repository function as well though:
$nb_us = $us->getRepository('AppBundle:User')->getNbr("ROLE_USER");
Using Symfony2.3.4 and Doctrine.
I have a class Student with a ManyToMany relation with a class Edition.
Now in my StudentController I have this IndexAction($edition_id) to list not all students in the DB but only those related to the given Edition id.
$entities = $em->getRepository('PersonBundle:Student')->findBy(array(
????????
));
I'm thinking of some kind of criteria to use with $edition_id but can't come up with any.
Tips appreciated, thanks.
#dmnptr:
I'm trying that, I'm quite new to this so tell me if I did something wrong.
I put that function you wrote in the controller and in the method IndexAction($edition) I added
$students = this->findAllByEdition($edition);
now the problem is that the parameter $edition is coming from a twig template like this:
<a href="{{ path('student', { 'edition': entity}) }}"</a>
being entity who holds the Edition object.
But when I do it like this entity returns the __toString() method, meaning a string with the name of the edition, not the edition itself which is what the function you gave me uses.
Now, do you happen to know a way to get the object itself from the template, not the __toString() method, thanks...
You should use custom repository method. Pass $edition as a parameter, not just an id. Something like this:
public function findAllByEdition($edition)
{
$em = $this->getEntityManager();
$queryText = "SELECT s FROM PersonBundle:Student s ";
$queryText .= "WHERE :edition MEMBER OF s.editions";
$query = $em->createQuery($queryText);
$query->setParameter('edition', $edition)
return $query->getResult();
}
I'm new with Symfony2 and i would like to know whether there is a way to use the "findBy" with a param which is present only in a mapped entity.
This is my snippet controller:
$prods = $em->getRepository('EcommerceProductBundle:ProductData')
->findBy(array(
'product_id'=>46
));
It works good but if i try to add another element to the array, which is present in a mapped entity, it get (rightly) this error
Unrecognized field: ProductImage.is_visible
What i would like to do, is just to know wehether i can use the "filterBy" with a mapped element of the entity ProductData.
I'm in wrong but this is my idea:
->findBy(array(
'product_id'=>46,
'ProductImage.is_visible'=>1
));
Not possible as far as i know. Just add this custom method to your repository:
public function findByIdAndVisibleImage($id)
{
return $this->createQueryBuilder('product')
->lefJoin("product.image","i")
->where("product.product_id = :id")
->andWhere("i.is_visible = 1")
->setParameter("id", $id)
->getQuery()
->getSingleResult();
}
You can't do that, you need to write a custom method in the repository with a join clause.
The findBy method just add a where clause on the criteria.
I'm using Zend Framework and following the design pattern of separating the Data layer from the Domain layer
the problem raises when implementing the methods for the Data mapper
so i implemented the save() which insert & update based on whether domain model contains id property and find() which return the records domain object based on id parameter
but what if i need to
search all/some rows in a table and return all the columns
search the same rows and return a mysql COUNT value
should i just directly use the class the inherited the Zend_Db_Table_Abstract for these needs or
should i implement method for every need ?
i'm a little confused on how to divide the functionality of the Data Mapper that will fit my needs and my future needs
You can add individual finder Methods, e.g.
class PersonMapper
{
… // other code
public function findByLastName()
{
// … fetch rowset and map them
}
public function countByLastName()
{
…
However, that will quickly get out of hand when you need to query multiple columns or want to handle CRUD by arbitrary criteria. You don't want methods like
public function findByLastNameAndBirthdayAndMaritalStatus()
The easy solution would be to use Zend_Db_Table_Select to create the queries and then pass those to the Data Mapper to execute and map them, e.g. in your DataMapper
public function getSelect()
{
return $this->personTable->select();
}
public function findBy(Zend_Db_Table_Select $select)
{
$people = $this->personTable->fetchAll($select);
// map people to People objects
}
You could abstract this further with the Mapper returning and accepting PersonQueryBuilder instead, which hides the SQL Semantics inside and let's you specify against your Domain Objects instead. It's more effort though.
Also have a look at the Repository and Specification Pattern.
As much as Gordon very likely has the correct answer, I find it overly complex for my tastes and needs at the moment.
I use a base mapper class for all of my domain mappers and I put as much functionality into the base class as I can.
I use a find by column method that works fairly well in all of my mappers:
//from abstract class Model_Mapper_Abstract
//The constructor of my base class accepts either a dbtable model
// or the name of a table stored in the concrete mapper tablename property.
public function __construct(Zend_Db_Table_Abstract $tableGateway = null)
{
if (is_null($tableGateway)) {
$this->tableGateway = new Zend_Db_Table($this->tableName);
} else {
$this->tableGateway = $tableGateway;
}
}
/**
* findByColumn() returns an array of entity objects
* filtered by column name and column value.
* Optional orderBy value.
*
* #param string $column
* #param string $value
* #param string $order optional
* #return array of entity objects
*/
public function findByColumn($column, $value, $order = null)
{
//create select object
$select = $this->getGateway()->select();
$select->where("$column = ?", $value);
//handle order option
if (!is_null($order)) {
$select->order($order);
}
//get result set from DB
$result = $this->getGateway()->fetchAll($select);
//turn DB result into domain objects (entity objects)
$entities = array();
foreach ($result as $row) {
//create entity, handled by concrete mapper classes
$entity = $this->createEntity($row);
//assign this entity to identity map for reuse if needed
$this->setMap($row->id, $entity);
$entities[] = $entity;
}
//return an array of entity objects
return $entities;
}
I hope you find this useful as an idea generator at the least. Also if you wish to implement a SQL Count() statement in a method similar to this it will go easier if you use Zend_Db_Expr() when you build that select().