I have the following query that should check the start and end date in another entity and compare it against the start and end dates enter to create an instance of an entity, however its not returning anything.
public function createAction(Request $request)
{
$entity = new Payrollperiod();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$qb = $em->getRepository('comtwclagripayrollBundle:PayrollWeek')->createQueryBuilder('p');
$qb->select('p')
->where('p.startDate = :entityStart')
->andWhere('p.endDate = :entityEnd')
->setParameter('entityStart',$entity->getstartDate())
->setParameter('entityEnd',$entity->getendDate())
->getQuery()
->getResult();
How long I've been using Doctrine, I've never seen:
In MySQL (and PostgreSQL, SQLite) equal symbol is =, not ==.
In DQL you can't use entities' methods like getStartDate(), only attributes (in detail you can use only fields and associations defined in entity's mapping).
So:
$qb->select('p')
->where('p.getstartDate()==entity.startDate')
->andWhere('p.getendDate()==entity.endDate');
Should be:
$qb->select('p')
->where('p.startDate = entity.startDate')
->andWhere('p.getEndDate = entity.endDate')
What is entity.*? You have not declared entity Entity in your DQL.
[EDIT] If entity.* is another entity and you not define its in Query, then you must parameterize it:
$qb->select('p')
->where('p.startDate = :entityStart')
->andWhere('p.getEndDate = :entityEnd')
->setParameter('entityStart', $entity->getStartDate())
->setParameter('entityEnd', $entity->getEndDate())
Without exception message I cannot tell more about your code. It could be NonUniqueResultException because query finds more than 1 result.
Doctrine (and Symfony) have so many exceptions where everything is nice explain - what's crashed, why, where. Sometimes even the name of exception tell us everything - like UniqueConstraintViolationException.
Related
I am trying to use native query in doctrine and for now created something really simple:
$rsm = new ResultSetMapping();
$rsm->addEntityResult('ObjectA', 'a');
$rsm->addFieldResult('a', 'id', 'id');
$query = $em->createNativeQuery('SELECT * FROM table a', $rsm);
What I try using this code, I am getting an error that ObjectA is not a valid entity or mapped super class. Which is totally true.
My question is: Is there any way to mad result of a native query to any arbitrary class (not Entity), but still user Doctrine's tools to do it.
Note: I am trying to avoid usage of lower level PDO.
Thank you.
Nothing like that, neither in the doc nor in the source code Doctrine\ORM\Query\ResultSetMapping (and it happens that some features are not documented).
I'd go with using scalar results and mapping the query result back to the object. Something like this:
$rsm = new ResultSetMapping();
$rsm->addScalarResult('a', 'a');
$rsm->addScalarResult('b', 'b');
$query = $em->createNativeQuery('SELECT a, b FROM table LIMIT 1', $rsm);
$result = $query->getSingleResult();
$a = new ObjectA();
$a->setA($result['a']);
// or
$a = new ObjectA($result); // with mapping passed to the constructor
I want to increase a value in my doctrine entity.
Currently I'm doing it this way.
$file->setDownloadCounter($file->getDownloadCounter() + 1);
$em = $this->getDoctrine()->getManager();
$em->persist($fileVersion);
$em->flush();
Is there way to execute something like this in doctrine:
UPDATE file SET downloadCounter = downloadCounter + 1 WHERE id = 1
EDIT:
The problem in the doctrine example above is that between loading and flush is time where others could download the file and so the counter is not correct.
You can also do the following in an entity repository:
return $this
->createQueryBuilder('f')
->update($this->getEntityName(), 'f')
->set('f.downloadCounter', $file->getDownloadCounter() + 1)
->where('f.id = :id')->setParameter('id', $file->getId())
->getQuery()
->execute();
Or using DQL:
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery(
'UPDATE YourBundle:File f
SET f.downloadCounter = :downloadCounter'
)->setParameter('downloadCounter', $file->getDownloadCounter() + 1);
Or through a simplified DQL:
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery(
'UPDATE YourBundle:File f
SET f.downloadCounter = f.downloadCounter + 1'
);
The drawback with these solutions: if your entity was already loaded it will have the previous count and not the incremented count.
The way you did is perfectly fine but a better way is to add an increment method to your entity.
Follow-up from Radu C comment below: the simplified DQL is the only solution that guarantees proper count.
The query increments based on the value in the database and locks the table guaranteeing queries to be executed in a sequence.
Whereas the other queries use the value in PHP runtime which may be an outdated value: some other request may have already incremented the value in the database therefore incrementing based on value in PHP memory will override increment made by other requests.
Safest way to do this is using Doctrine DBAL and call raw SQL that way you remove the chance of race condition and make the change atomic. Other option is to make the field versioned and use optimistic locking or pessimistic DB-level locking.
You could simply add an increment method to your model.
class File {
public function increaseDownloadCounter()
{
$this->downloadCounter++;
}
}
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('AcmeDemoBundle:EntityName')->find($entityId);
$valueToIncrement = $entity->getMyField(); // where MyField is the DB field to increment
$entity->setMyField(++$valueToIncrement);
$em->persist($entity);
$em->flush();
I created a database on phpMyAdmin localhost. I have set database configurations in symfony and created doctrine mapper (entity). Now all I need is to make SELECT query and get information from database:
TABLE NAME: Profile
ROWS: 1
CONTROLLER CODE:
...
use Ignas\IgnasBundle\Entity\Profilis;
use Symfony\Component\HttpFoundation\Response;
class DefaultController extends Controller
{
public function indexAction()
{
$profilis = new Profilis();
return new Response('Id '.$profilis->getId());
}
}
getId method is from Entity/Profilis file Profilis class.
Is there any easy way to do this? I searched for a while and all I could find was doctrine syntax that is not familliar to me at all.
you can do it in different ways:
first of all, get the EntityManager in your Controller
$em = $this->getDoctrine()->getEntityManager();
in case it says it's deprecated you can also get it like:
$em = $this->getDoctrine()->getManager();
then you can do it with the QueryBuilder or with the createQuery method
With Select method (as suggested in the comments)
$profilis= $em->select('p.id')
->from('BundleName:EntityName', 'p')
->getQuery()
->getResult();
simple Query:
$query = $em->createQuery("SELECT * FROM Profilis p");
$profilis = $query->getResult();
NOTE
both methods return an array of Profilis so you can simply loop them this way:
foreach($profilis as $p){
// do whatever you want
}
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 working with Entity objects from Doctrine queries and i end up with a very big array, with all information from all entities related. This ends up being a huge data tree... how can i limit this? Avoid listing all data from all relationships?
You can always remove not needed associations (this is a best practice for speeding up Doctrine). Or you can select only fields that you need in your presentation layer (as read-only data):
public function getAll()
{
$qb = $this->createQueryBuilder('u'); // Where are in User custom repository
return $qb
->select(array('u.id', 'u.first', 'u.last'))
->getQuery()
->getResult();
}
If you still need to work with objects (or for complex queries that needs plain SQL) a possibility is filling only needed properties (and eventually, associations/nested collections) of your domain object.
An example, more on native SQL:
public function getAll()
{
$mapping = new \Doctrine\ORM\Query\ResultSetMapping();
$mapping->addEntityResult('Acme\HelloBundle\User', 'e');
$mapping->addFieldResult('e', 'id', 'id');
$mapping->addFieldResult('e', 'first', 'first');
$mapping->addFieldResult('e', 'last', 'last');
$sql = "SELECT id, first, last FROM user ";
$result = $this->_em->createNativeQuery($sql, $mapping)->getResult();
// Or hust return $result itself (array)
return new \Doctrine\Common\Collections\ArrayCollection($result);
}
Of course the disadvance (?) is use of native SQL. I don't believe that ResultSetMapping can be used with DQL.
EDIT: take a look at http://docs.doctrine-project.org/projects/doctrine-orm/en/2.0.x/reference/best-practices.html