I have 2 entity (Rule and analysisRule)( association one to many)
I try to make a query that counts the number of idAnalyseRule that have an idAnalyse pass as a parameter in the function
example:
I pass idRule = 15 as a parameter, the query will count all IdAnalysisRules that have an idAnalysis = 15
I do not know how it works but I try it like that
$qb = $this->createQueryBuilder('p');
$expr = $qb->expr();
$qb->andWhere(
$expr->eq('p.analyse', ':analyse')
)
->setParameter('analyse', $analyse);
return $qb->getQuery()->getSingleResult();
this is the manager
/**
* #param $analyse
* #return mixed
*/
public function errorsAnalyseRule(Analyse $analyse){
return $this->repository->totalErrors($analyse);
}
this is controller
/**
*
* Get a totalError by idAnalyse.
* #param Analyse $analyse
* #param AnalyseRuleManager $analyseRuleManager
* #return ApiResponse
*
* #SWG\Parameter(name="id", in="path", type="integer", description="Supplier Id"))
* #SWG\Response(response=200, description="Returns the nbErrors")
*
* #Rest\Get("analyses/{id}", requirements={"id"="\d+"})
*/
public function getTotalErrorsAction(Analyse $analyse, AnalyseRuleManager $analyseRuleManager)
{
return new ApiResponse(['nbErrors' => $analyseRuleManager->errorsAnalyseRule($analyse)]);
}
I am in a state of blockage for 3 days
This works with an inner join. In the repository of analysisRule you have to add the function that makes the query and returns the count:
public function countAnalysisRule(Rule $rule)
{
return $this-createQueryBuilder('a')
->select('count(a)')
->innerJoin('a.Rule', 'rule')
->where('rule.id = :rule')
->setParameter('rule', $rule->getId())
->getQuery()
->getSingleScalarResult();
}
Don't forget ofcourse to add a use of the Rule class.
According to https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/query-builder.html
You should use:
$qb = $entityManager->createQueryBuilder();
$qb->select($qb->expr()->count('p.id'))
->from('App:AnalyseRule','p')
->where('p.analyse', ':analyse')
->setParameter('analyse', $analyse);
$count = $qb->getQuery()->getSingleScalarResult();
where $analyse = 15 in your case !
If you are under 2.6 for doctrine prefer:
$qb = $entityManager->createQueryBuilder();
$qb->select('count(p.id)')
->from('App:AnalyseRule','p')
->where('p.analyse', ':analyse')
->setParameter('analyse', $analyse);
$count = $qb->getQuery()->getSingleScalarResult();
Related
Hi I need to save information in my db, what I mean is, how to persist when the relationship is manytomany, I am doing like this but it doesn't work!...I will put some code of entity Menu.
/** Agrega nuevo menù
*
* #Route("/save", name="admin_menu_save")
* #Method({"GET", "POST"})
* #param Request $request
* #return Response
*/
public function saveAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$fecha_menu = $request->get('fecha');
$fecha_comprar = $request->get('fechacomprado');
$fecha_vencimiento = $request->get('fechavencimiento');
$alimentos = $request->get('select_alimentos');
$a = $em->getRepository('AdminBundle:Alimento')->findBy($alimentos);
$menu = new Menu();
$menu->setFecha(new \DateTime($fecha_menu));
$menu->setFechacomprar(new \DateTime($fecha_comprar));
$menu->setFechavence(new \DateTime($fecha_vencimiento));
$menu->setPrecio(6);
$menu->addAlimento($a);
$em->persist($menu);
$em->flush();
return new Response('Guardado OK');
}
//Menu Entity Definition (Just the necessary code):
/**
* #ORM\ManyToMany(targetEntity="Alimento", inversedBy="menu")
* #ORM\JoinTable(name="alimento_menu",
* joinColumns={
* #ORM\JoinColumn(name="menu_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="alimento_id", referencedColumnName="id")
* }
* )
*/
private $alimento;
/**
* Constructor
*/
public function __construct()
{
$this->alimento = new ArrayCollection();
}
/**
* Add alimento
*
* #param \AdminBundle\Entity\Alimento $alimento
*
* #return Menu
*/
public function addAlimento(Alimento $alimento)
{
$this->alimento[] = $alimento;
return $this;
}
/**
* Remove alimento
*
* #param \AdminBundle\Entity\Alimento $alimento
*/
public function removeAlimento(Alimento $alimento)
{
$this->alimento->removeElement($alimento);
}
/**
* Get alimento
*
* #return ArrayCollection
*/
public function getAlimento()
{
return $this->alimento;
}
}
I have not experience working with manytomany relations, I hope to solve this problem, that´s show very good, but I don´t know how to save,edit or remove in that manytomany table!....
First, this bit seems weird.
$alimentos = $request->get('select_alimentos');
$a = $em->getRepository('AdminBundle:Alimento')->findBy($alimentos);
Doctrine findBy takes an array with the entity field as a key and the specific entity value as the value. Like this:
$em-getRepository('AdminBundle:Alimento')->findBy(['id' => $id]);
If that's how your $alimentos variable is structured, that's fine. It just looks strange.
If this is a bi-directional relationship, you have to update both entities. So your controller code is like:
$a = $em->getRepository('AdminBundle:Alimento')->findBy($alimentos);
$menu = new Menu();
// -- more code ---//
$menu->addAlimento($a);
$a->addMenu($menu);
$em->persist($menu);
$em->flush();
Check this documentation.
I just realized what was...This was my solution:
foreach ($alimentos as $item) {
$a = $em->getRepository('AdminBundle:Alimento')->find($item);
$menu->addAlimento($a);
}
And of course later I persist menu.
I would like to extends ObjectHydrator to benefit of the hydration of my ManyToOne relation and add extra field to the Entity.
Here is my hydrator: StatisticsDataHydrator.php
namespace AppBundle\Hydrator\ProjectAssignment;
use AppBundle\Entity\ProjectAssignment;
use Doctrine\ORM\Internal\Hydration\ObjectHydrator;
class StatisticsDataHydrator extends ObjectHydrator
{
/**
* {#inheritdoc}
*/
protected function hydrateRowData(array $data, array &$result)
{
$hydrated_result = array();
parent::hydrateRowData($data, $hydrated_result);
/** #var ProjectAssignment $project_assignment */
$project_assignment = $hydrated_result[0][0];
$result[] = $project_assignment;
}
}
Here is my config: config.yml
doctrine:
orm:
hydrators:
project_assignment_statisticsdata_hydrator: AppBundle\Hydrator\ProjectAssignment\StatisticsDataHydrator
Where I don't use the hydrator I have no problem:
/**
* #param ProjectStage $stage
* #return array
*/
public function findByStageWithStatisticsData(ProjectStage $stage){
$qb = $this->createQueryBuilder('pa');
$qb
//->addSelect('44')
->where($qb->expr()->eq('pa.project_stage', ':stage'))
->setParameter('stage', $stage);
return $qb->getQuery()->getResult();
}
But when I use my hydrator:
/**
* #param ProjectStage $stage
* #return array
*/
public function findByStageWithStatisticsData(ProjectStage $stage){
$qb = $this->createQueryBuilder('pa');
$qb
->addSelect('1234') // referencial value
->where($qb->expr()->eq('pa.project_stage', ':stage'))
->setParameter('stage', $stage);
return $qb->getQuery()->getResult('project_assignment_statisticsdata_hydrator');
}
The strangest behavior is that the same occure with this config: config.yml
doctrine:
orm:
hydrators:
project_assignment_statisticsdata_hydrator: Doctrine\ORM\Internal\Hydration\ObjectHydrator
I have tried all kind of fetch on relation with no success:
#ORM\ManyToOne(... , fetch="EAGER")
#ORM\ManyToOne(... , fetch="LAZY")
...
Maybe I have to use a Proxy on my Entity, I really don't know :(
Thank you for any help!
Great! I found the problem, it was with my query builder. I had to manually add the joins and the select of related objects.
/**
* #param ProjectStage $stage
* #return array
*/
public function findByStageWithStatisticsData(ProjectStage $stage){
$qb = $this->createQueryBuilder('pa');
$qb
->addSelect('e') // added
->addSelect('r') // added
->addSelect('1234')
->leftJoin('pa.employee', 'e') // added
->leftJoin('pa.role', 'r') // added
->where($qb->expr()->eq('pa.project_stage', ':stage'))
->setParameter('stage', $stage);
return $qb->getQuery()->getResult('project_assignment_statisticsdata_hydrator');
}
Bonus, here is my Hydrator (it can help someone):
namespace AppBundle\Hydrator\ProjectAssignment;
use AppBundle\Entity\Hydrator\ProjectAssignment\StatisticsData;
use AppBundle\Entity\ProjectAssignment;
use Doctrine\ORM\Internal\Hydration\ObjectHydrator;
class StatisticsDataHydrator extends ObjectHydrator
{
/**
* {#inheritdoc}
*/
protected function hydrateRowData(array $data, array &$result)
{
$hydrated_result = array();
parent::hydrateRowData($data, $hydrated_result);
/** #var ProjectAssignment $project_assignment */
$project_assignment = $hydrated_result[0][0];
$keys = array_keys($hydrated_result); $key = end($keys);
$statistics_data = new StatisticsData($project_assignment);
$statistics_data->setTotalWorkedTime((int)$hydrated_result[$key][1]);
$project_assignment->setStatisticsData($statistics_data);
$result[] = $project_assignment;
}
}
In my Entity I have the folowing attribute/getter/setter
/********** NON SYNCED FIELDS **********/
/** #var StatisticsData $statistics_data */
private $statistics_data;
/**
* #return StatisticsData
*/
public function getStatisticsData()
{
return $this->statistics_data;
}
/**
* #param StatisticsData $statistics_data
*/
public function setStatisticsData($statistics_data)
{
$this->statistics_data = $statistics_data;
}
/***************************************/
The problem is that the Doctrine SqlWalker will not load meta columns, which include subclasses and associations, if the query Hydration Mode is not HYDRATE_OBJECT or if the query hint HINT_INCLUDE_META_COLUMNS is not set to true:
$addMetaColumns = ! $this->query->getHint(Query::HINT_FORCE_PARTIAL_LOAD) &&
$this->query->getHydrationMode() == Query::HYDRATE_OBJECT
||
$this->query->getHydrationMode() != Query::HYDRATE_OBJECT &&
$this->query->getHint(Query::HINT_INCLUDE_META_COLUMNS);
The problem has already been reported in this issue.
As mentioned by the author of the issue, you can either implement the suggested fix, or set the query hint HINT_INCLUDE_META_COLUMNS to true:
$query = $queryBuilder->getQuery();
$query->setHint(Query::HINT_INCLUDE_META_COLUMNS, true);
$result = $query->getResult('CustomHydrator');
Could someone assist me with this. I'm having a trouble with creating a query or how to add changes to createAction to achieve the following. On clicking create it checks if a payroll period is valid, because in the payroll week table it is populated with a one week while the user enters a two week period.
Payroll period: payrollperiodid, start date, enddate and state
Payroll Week: id, startDAte, enddate, numofdays, normal hours.
for eg. user enters startdate: 16-07-2017 enddate: 29-07-2017 in payroll period then in the payroll week table period 1 startdate: 16-07-2017 endDate:22-07-2017 period 2 startdate:23-07-2017 enddate:29-07-2017.
Thus the period would be considered valid else error, and then also on create once the period is valid checks if it exists in the payroll period table else error. But i'm not sure how to add the part that ensures that the user enters a period of 2weeks. >7days <=14days, I wouldn't want to use hard numbers how could i achieve this
public function createAction(Request $request,$startDate, $endDate)
{
$entity = new Payrollperiod();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('comtwclagripayrollBundle:Payrollperiod')->findByPayrollPeriod(array('startDate'=>$startDate,'endDate'=> $endDate));
if ($entity){
$this->addFlash('error','ERROR! Payroll Period exist');
return $this->redirect($this->generateUrl('payrollperiod_create'));
}
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('payrollperiod_show', array('payrollperiodid' => $entity->getpayrollperiodid())));
}
return array(
'entity' => $entity,
'form' => $form->createView(), );
}
public function findByPayrollPeriod($startDate, $endDate)
{
return $this->getEntityManager()
->createQuery(
'SELECT p FROM comtwclagripayrollBundle:PayrollWeek
WHERE startDate = :startDate or endDate = :endDate'
)
->setParameter('startDate', $startDate)
->setParameter('endDate', $endDate)
->getResult();
}
****Updates****
<?php
namespace com\twcl\agripayrollBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
//use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
/**
* Payrollperiod
*
* #ORM\Table(name="PayrollPeriod")
* #ORM\Entity
*
*/
class Payrollperiod
{
/**
* #var integer
*
* #ORM\Column(name="payrollperiodid", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $payrollperiodid;
/**
* #var \DateTime
*
* #ORM\Column(name="startDate", type="datetime", nullable=false)
* #Assert\Type("DateTime")
*/
private $startdate;
/**
* #var \DateTime
*
* #ORM\Column(name="endDate", type="datetime", nullable=false)
* #Assert\Type("DateTime")
*
*/
private $enddate;
/**
* #var integer
*
* #ORM\Column(name="State", type="integer", nullable=false)
*
*/
private $state;
public function getPayrollperiodid() {
return $this->payrollperiodid;
}
public function getStartdate() {
return $this->startdate;
}
public function getEnddate() {
return $this->enddate;
}
public function getState() {
return $this->state;
}
public function setPayrollperiodid($payrollperiodid) {
$this->payrollperiodid = $payrollperiodid;
}
public function setStartdate(\DateTime $startdate) {
$this->startdate = $startdate;
}
public function setEnddate(\DateTime $enddate) {
$this->enddate = $enddate;
}
public function setState($state) {
$this->state = $state;
}
/**
* Render a payrollPeriodID as a string.
*
* #return string
*/
public function __toString()
{
return (string) $this->getPayrollperiodid();
}
/**
* #Assert\Callback
*/
public function validatePayrollPeriod(Payrollperiod $Payrollperiod,ExecutionContextInterface $context)
{
$conflicts = $this->getDoctrine()
->getRepository('comtwclagripayrollBundle:Payrollperiod')
->findbyPayrollPeriod($Payrollperiod->getstartDate(), $Payrollperiod->getendDate())
;
if (count($conflicts) > 0) {
$context->buildViolation('Start date and end date exists')
->atPath('startdate')
->addViolation();
}
}
}
public function findbyPayrollPeriod(\DateTime $startDate, \DateTime $endDate)
{
$qb = $this->createQueryBuilder('e');
return $qb->andWhere('e.startDate = :startDate AND e.endDate = :endDate')
->setParameter('startDate', $startDate)
->setParameter('endDate', $endDate)
->getQuery()
->execute()
;
}
But i'm still not getting the error message, am I missing something
I think you can solve the issue, the following way
//create new trait
<?php
namespace yourBundlePath\Form\Type\Utility;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
*
* #package Daim\CoreBundle\Form\Type\Utility
*/
trait ContainerTrait
{
/**
* #var ContainerInterface
*/
private $containerObject;
/**
* #param ContainerInterface $container
* #return ContainerInterface
*/
public function setContainer(ContainerInterface $container)
{
return $this->containerObject = $container;
}
/**
* #return ContainerInterface
*/
public function getContainer()
{
return $this->containerObject;
}
}
//form
use yourBundlePath\Form\Type\Utility\ContainerTrait;
class yourFormClass
{
//call after the class declaration
use ContainerTrait;
$builder->addEventListener(
FormEvents::SUBMIT,
function (FormEvent $event) {
$form = $event->getForm();
$em = $this->getContainer()->get('doctrine');
$startDate = $form->get('startDate')->getData();
$endDate = $form->get('endDate')->getData();
$entity = $em->getRepository('comtwclagripayrollBundle:Payrollperiod')->findByPayrollPeriod(array('startDate'=>$startDate,'endDate'=> $endDate));
if ($entity){
$form->get('startDate')->addError(
new FormError(
'ERROR! Payroll Period exist'
)
);
}
}
);
Also you can refer the url: https://symfony.com/doc/current/form/dynamic_form_modification.html
One can solve this in various ways. If this is a common problem (and/ or you prefer a global solution) use the Class Constraint Validator. If you don't mind a 'local' solution look at Callback Constraint.
Both are explained in the documentation pages. Another reference is this SO question.
All that is left is how to calculate the difference between dates for that I'd suggest using PHP's DateTime::diff as something like:
$days = $startDate->diff($endDate)->days;
if ($days <= 7 && $days > 14) {
// build my constraint error message because the period is invalid.
}
Update #1
So let me first say after our comment spam, maybe start somewhere a little lighter. It seems your diving in right in the middle without any foundation on Symfony and/ or even PHP. Symfony has excellent tutorials and examples, but if you can't apply those your going to have a hard time.
The callback validate is only to check the difference between the two dates. An entity in general should not talk to the database but just itself / related entity classes.
class Payrollperiod {
...
/**
* #Assert\Callback
*/
public function validatePayrollPeriod(ExecutionContextInterface $context) {
$days = $this->startdate->diff($this->enddate)->days;
if ($days <= 7 && $days > 14) {
$context->buildViolation('There have to be at least 7 and a maximum of 13 days for your payroll period.')
->atPath('enddate') // this is where the message is bound to, can be either start or end date depending on where you prefer.
->addViolation();
}
}
}
Your findbyPayrollPeriod seems valid, as long as it is in your PayrollperiodRepository class file. And you do want to have a single equals check and not see if ranges overlap etc.
This function could also be handled using doctrine's unique constraints on multiple columns eg (user, startdate) and (user, enddate). This should give you an error when you attempt to add it as it then requires a unique value for the two. Even without the findbyPayrollPeriod function.
In your controller your repository line has multiple problems.
You are using an array for arguments not two arguments as the function has.
You are overwriting your form data entity because you are using the same variable name.
And your $startdate and $enddate appear like magic. They are from the entity, so use the getters.
And as a side note you might not want to redirect on the flash, but just continue as normal (so you don't loose your form data).
All in all you would get something partially like:
...
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$entityExists = $em->getRepository('comtwclagripayrollBundle:Payrollperiod')
->findByPayrollPeriod($entity->getStartdate(), $entity->getEnddate());
// If the entity does not exist we can add it and redirect to the new page.
if (!$entityExists) {
// Add our form entity to the database.
$em->persist($entity);
$em->flush();
// redirectToRoute is a controller helper function and is a tiny bit shorter.
return $this->redirectToRoute('payrollperiod_show', array(
'payrollperiodid' => $entity->getPayrollperiodid()
));
}
// Form is valid but we didn't return anything so far.
// So there is an entity with the same period start or end.
// Add a flash and show the form again.
$this->addFlash('error', 'A payroll period is already present
with the same start or end date.');
}
return ...
How can I solve
Error: Call to a member function getDateTime() on a non-object
Here are is my code:
$repository = $this->getDoctrine()
->getRepository('AppBundle\Entity\Menu');
$today = date_create_from_format('Y-m-d H:i', date('Y-m-d H:i'));
$menu = $repository->findAll();
if($menu->getDateTime() == \DateTime('now')){
$primiOne = $menu->getPrimiOne();
$primiTwo = $menu->getPrimiTwo();
$primiThree = $menu->getPrimiThree();
$secondOne = $menu->getSecondOne();
$secondTwo = $menu->getSecondTwo();
$secondThree = $menu->getSecondThree();
$sideOne = $menu->getSideOne();
$sideTwo = $menu->getSideTwo();
$sideThree = $menu->getSideThree();
and the entity is:
/**
* #var \DateTime
*
* #ORM\Column(name="date_time", type="string")
*/
private $dateTime;
/**
* Set dateTime
*
* #param string $dateTime
*
* #return Menu
*/
public function setDateTime($dateTime)
{
$this->dateTime = $dateTime;
return $this;
}
/**
* Get dateTime
*
* #return string
*/
public function getDateTime()
{
return $this->dateTime;
}
You are calling this:
$menu = $repository->findAll();
which will never be instance of your entity because findAll() method returns all objects from given table from db, so this is going to be an array of your entities - this is your mistake - you should query for one object, not all objects.
So, either do:
$menuItems = $repository->findAll();
$menu = $menuItems[0];
if ($menu->getDateTime() (...) )
or
$menu = $repository->findOneBy($criteriaArray);
if ($menu->getDateTime() (...) )
I have view table in my Database, how can I retrieve the data from this views?
I tried to use
$em = $this->getDoctrine()->getEntityManager();
$query = $em->createQuery('SELECT * FROM my_views');
$result = $query->getResult();
but it doesn't work.
If you want to perform a simple SQL query, you can do that :
$con = $this->getDoctrine()->getEntityManager()->getConnection();
$stmt = $con->executeQuery('SELECT * FROM my_views');
foreach ($stmt->fetchAll() as $row){
print_r($row);
}
When you use $em->createQuery(), you need to work with Doctrine entities.
If you want to use the mapping with your view, juste create an entity :
namespace Your\Bundle\Entity;
/**
* #ORM\Entity
* #ORM\Table(name="my_view")
*/
class MyView
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
*/
protected $id;
/**
* #ORM\Column(type="string")
*/
protected $someVarcharColumn;
public function getId()
{
return $this->id;
}
public function getSomeVarcharColumn()
{
return $this->someVarcharColumn;
}
}
And you can query it with DQL like this :
$results = $em->createQuery('
SELECT v
FROM YourBundle:MyView v
')->getResult();