Sue
Sue

Reputation: 105

Check start date and end date to be a period of two weeks in Symfony

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

Upvotes: 0

Views: 2141

Answers (2)

Jenne
Jenne

Reputation: 883

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.

  1. You are using an array for arguments not two arguments as the function has.
  2. You are overwriting your form data entity because you are using the same variable name.
  3. 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 ...

Upvotes: 0

siju joseph
siju joseph

Reputation: 21

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

Upvotes: 1

Related Questions