This commit is contained in:
2025-09-30 22:47:43 +02:00
parent b7b9cebacb
commit b0894e0267
7 changed files with 523 additions and 568 deletions

53
.php-cs-fixer.dist.php Normal file
View File

@@ -0,0 +1,53 @@
<?php
$finder = PhpCsFixer\Finder::create()
->in(__DIR__)
->exclude([
'vendor',
'var',
'web',
'app/DoctrineMigrations',
'bin',
'doc',
])
->name('*.php')
;
// TODO: Définir les règles de style communes
// spécifiques au projet
return (new PhpCsFixer\Config())
->setRules([
'@Symfony' => true,
'concat_space' => ['spacing' => 'none'],
'array_syntax' => ['syntax' => 'short'],
'combine_consecutive_issets' => true,
'explicit_indirect_variable' => true,
'no_useless_return' => true,
'ordered_imports' => true,
'no_unused_imports' => true,
'no_spaces_after_function_name' => true,
'no_spaces_inside_parenthesis' => true,
'ternary_operator_spaces' => true,
'class_definition' => ['single_line' => true],
'whitespace_after_comma_in_array' => true,
// phpdoc
'phpdoc_add_missing_param_annotation' => ['only_untyped' => true],
'phpdoc_order' => true,
'phpdoc_types_order' => [
'null_adjustment' => 'always_last',
'sort_algorithm' => 'alpha',
],
'phpdoc_no_empty_return' => false,
'phpdoc_summary' => false,
'general_phpdoc_annotation_remove' => [
'annotations' => [
'expectedExceptionMessageRegExp',
'expectedException',
'expectedExceptionMessage',
'author',
],
],
])
->setFinder($finder)
;

View File

@@ -2,50 +2,47 @@
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Form\FormError;
use Knp\Bundle\SnappyBundle\Snappy\Response\PdfResponse;
use App\Service\icsService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
class ApiController extends AbstractController
{
public function api($key,Request $request)
public function api($key): Response
{
$em = $this->getDoctrine()->getManager();
$user=$em->getRepository("App:User")->findBy(["apikey"=>$key]);
if(!$user) {
return new Response("Accès refusé", 403);
$user = $em->getRepository('App:User')->findBy(['apikey' => $key]);
if (!$user) {
return new Response('Accès refusé', 403);
}
$ics = new icsService();
$ics->debug(false);
$content=$ics->writeheader();
$content = $ics->writeheader();
$events=$em->getRepository("App:Event")->findBy(["user"=>$user]);
foreach($events as $event) {
$task=$event->getTask();
$project=$task->getProject();
$customer=$project->getCustomer();
$events = $em->getRepository('App:Event')->findBy(['user' => $user]);
foreach ($events as $event) {
$task = $event->getTask();
$project = $task->getProject();
$customer = $project->getCustomer();
$ics->set(
[
'allday' => $event->getAllday(),
'description' => $event->getDescription(),
'dtstart' => $event->getStart()->format("Y-m-d H:i:s"),
'dtend' => $event->getEnd()->format("Y-m-d H:i:s"),
'summary' => $customer->getName()."-".$project->getName()."-".$task->getName(),
'uid' => "schedule".$event->getId()
'dtstart' => $event->getStart()->format('Y-m-d H:i:s'),
'dtend' => $event->getEnd()->format('Y-m-d H:i:s'),
'summary' => $customer->getName().'-'.$project->getName().'-'.$task->getName(),
'uid' => 'schedule'.$event->getId(),
]
);
$content.=$ics->writeevent();
$content .= $ics->writeevent();
}
$content.=$ics->writefooter();
$content .= $ics->writefooter();
return new Response($content);
}

View File

@@ -2,169 +2,101 @@
namespace App\Controller;
use App\Entity\Breakday;
use App\Form\BreakdayType;
use App\Repository\BreakdayRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Form\FormError;
use Knp\Bundle\SnappyBundle\Snappy\Response\PdfResponse;
use App\Entity\Breakday as Entity;
use App\Form\BreakdayType as Form;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class BreakdayController extends AbstractController
{
private $data = "breakday";
private $route = "app_breakday";
private $render = "Breakday/";
private $entity = "App:Breakday";
private EntityManagerInterface $em;
private BreakdayRepository $breakdayRepository;
private $knpSnappy;
public function __construct(\Knp\Snappy\Pdf $knpSnappy) { $this->knpSnappy = $knpSnappy; }
public function list(Request $request)
public function __construct(EntityManagerInterface $em, BreakdayRepository $breakdayRepository)
{
$em = $this->getDoctrine()->getManager();
$datas = $em->getRepository($this->entity)->findAll();
$this->em = $em;
$this->breakdayRepository = $breakdayRepository;
}
if($request->query->get('fgprint')) {
$render = $this->renderView($this->render.'list.html.twig',[
$this->data."s" => $datas,
"useheader" => true,
"usesidebar" => true,
"fgprint" => true,
]);
public function list()
{
$breakdays = $this->breakdayRepository->findAll();
return new PdfResponse(
$this->knpSnappy->getOutputFromHtml($render),
'joursferiee.pdf'
);
}
else {
return $this->render($this->render.'list.html.twig',[
$this->data."s" => $datas,
"useheader" => true,
"usesidebar" => true,
]);
}
return $this->render('Breakday/list.html.twig', [
'breakdays' => $breakdays,
'useheader' => true,
'usesidebar' => true,
]);
}
public function submit(Request $request)
{
// Initialisation de l'enregistrement
$em = $this->getDoctrine()->getManager();
$data = new Entity();
// Création du formulaire
$form = $this->createForm(Form::class,$data,array("mode"=>"submit"));
// Récupération des data du formulaire
$breakday = new Breakday();
$form = $this->createForm(BreakdayType::class, $breakday, ['mode' => 'submit']);
$form->handleRequest($request);
// Sur erreur
$this->getErrorForm(null,$form,$request,$data,"submit");
// Sur validation
if ($form->get('submit')->isClicked() && $form->isValid()) {
$data = $form->getData();
$end = clone $data->getStart();
if ($form->isSubmitted() && $form->isValid()) {
$end = clone $breakday->getStart();
$end->add(new \DateInterval('P1D'));
$data->setEnd($end);
$em->persist($data);
$em->flush();
$breakday->setEnd($end);
$this->em->persist($breakday);
$this->em->flush();
// Retour à la liste
return $this->redirectToRoute($this->route);
return $this->redirectToRoute('app_breakday');
}
// Affichage du formulaire
return $this->render($this->render.'edit.html.twig', [
'useheader' => true,
'usesidebar' => true,
$this->data => $data,
'mode' => 'submit',
'form' => $form->createView()
return $this->render('Breakday/edit.html.twig', [
'useheader' => true,
'usesidebar' => true,
'breakday' => $breakday,
'mode' => 'submit',
'form' => $form->createView(),
]);
}
public function update($id,Request $request)
public function update(int $id, Request $request)
{
// Initialisation de l'enregistrement
$em = $this->getDoctrine()->getManager();
$data=$em->getRepository($this->entity)->find($id);
// Création du formulaire
$form = $this->createForm(Form::class,$data,array("mode"=>"update"));
// Récupération des data du formulaire
$breakday = $this->breakdayRepository->find($id);
if (!$breakday) {
throw new NotFoundHttpException('La ressource demandée est introuvable.');
}
$form = $this->createForm(BreakdayType::class, $breakday, ['mode' => 'update']);
$form->handleRequest($request);
// Sur erreur
$this->getErrorForm(null,$form,$request,$data,"update");
// Sur validation
if ($form->get('submit')->isClicked() && $form->isValid()) {
$data = $form->getData();
$end = clone $data->getStart();
if ($form->isSubmitted() && $form->isValid()) {
$breakday = $form->getData();
$end = clone $breakday->getStart();
$end->add(new \DateInterval('P1D'));
$data->setEnd($end);
$breakday->setEnd($end);
$this->em->flush();
$em->persist($data);
$em->flush();
// Retour à la liste
return $this->redirectToRoute($this->route);
return $this->redirectToRoute('app_breakday');
}
// Affichage du formulaire
return $this->render($this->render.'edit.html.twig', [
'useheader' => true,
'usesidebar' => true,
$this->data => $data,
'mode' => 'update',
'form' => $form->createView()
return $this->render('Breakday/edit.html.twig', [
'useheader' => true,
'usesidebar' => true,
'breakday' => $breakday,
'mode' => 'update',
'form' => $form->createView(),
]);
}
public function delete($id,Request $request)
public function delete($id)
{
// Initialisation de l'enregistrement
$em = $this->getDoctrine()->getManager();
$data=$em->getRepository($this->entity)->find($id);
// Controle avant suppression
$error=false;
if($error)
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
else {
try {
$em->remove($data);
$em->flush();
}
catch(\Doctrine\DBAL\DBALException $e) {
// Création du formulaire
$this->get('session')->getFlashBag()->add('error', 'Impossible de supprimer cet enregistrement');
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
}
// Retour à la liste
return $this->redirectToRoute($this->route);
}
}
protected function getErrorForm($id,$form,$request,$data,$mode) {
if ($form->get('submit')->isClicked()&&$mode=="delete") {
$breakday = $this->breakdayRepository->find($id);
if (!$breakday) {
throw new NotFoundHttpException('La ressource demandée est introuvable.');
}
if ($form->get('submit')->isClicked() && $mode=="submit") {
try {
$this->em->remove($breakday);
$this->em->flush();
} catch (\Exception $e) {
$this->addflash('error', $e->getMessage());
}
if ($form->get('submit')->isClicked() && !$form->isValid()) {
$this->get('session')->getFlashBag()->clear();
$errors = $form->getErrors();
foreach( $errors as $error ) {
$request->getSession()->getFlashBag()->add("error", $error->getMessage());
}
}
return $this->redirectToRoute('app_breakday');
}
}

View File

@@ -2,23 +2,24 @@
namespace App\Controller;
use App\Entity\Yeardomaine as Yeardomaine;
use App\Entity\Yearproject as Yearproject;
use App\Form\YeardomaineType as YeardomaineType;
use App\Form\YearprojectType as YearprojectType;
use Knp\Bundle\SnappyBundle\Snappy\Response\PdfResponse;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Form\FormError;
use Knp\Bundle\SnappyBundle\Snappy\Response\PdfResponse;
use App\Entity\Yearproject as Yearproject;
use App\Entity\Yeardomaine as Yeardomaine;
use App\Form\YearprojectType as YearprojectType;
use App\Form\YeardomaineType as YeardomaineType;
class BudgetController extends AbstractController
{
private $knpSnappy;
public function __construct(\Knp\Snappy\Pdf $knpSnappy) { $this->knpSnappy = $knpSnappy; }
public function list($id=null,Request $request)
public function __construct(\Knp\Snappy\Pdf $knpSnappy)
{
$this->knpSnappy = $knpSnappy;
}
public function list($id = null, Request $request)
{
$em = $this->getDoctrine()->getManager();
@@ -26,289 +27,291 @@ class BudgetController extends AbstractController
$years = $em
->createQueryBuilder('year')
->select('year')
->from('App:Year','year')
->from('App:Year', 'year')
->orderBy('year.start')
->setFirstResult(1)
->getQuery()->getResult();
// Rechercher l'exercice demandé sinon le dernier
if($id)
$n2=$em->getRepository("App:Year")->find($id);
else
$n2=$em->getRepository("App:Year")->findOneBy([],['start'=>'DESC']);
if ($id) {
$n2 = $em->getRepository('App:Year')->find($id);
} else {
$n2 = $em->getRepository('App:Year')->findOneBy([], ['start' => 'DESC']);
}
// Rechercher l'exercice précendent à celui selectionné
$n1 = $em
->createQueryBuilder('year')
->select('year')
->from('App:Year','year')
->from('App:Year', 'year')
->Where('year.end<:start')
->setParameter('start',$n2->getStart())
->orderBy('year.start','DESC')
->setParameter('start', $n2->getStart())
->orderBy('year.start', 'DESC')
->setFirstResult(0)->setMaxResults(1)
->getQuery()->getResult();
if(empty($n1)) $n1=null;
else $n1=$n1[0];
if($n1) {
$startn1=clone $n1->getStart();
$startn1->setTime(0,0,0);
$endn1=clone $n1->getEnd();
$endn1->add(new \DateInterval('P1D'))->setTime(0,0,0);
if (empty($n1)) {
$n1 = null;
} else {
$n1 = $n1[0];
}
if($n2) {
$startn2=clone $n2->getStart();
$startn2->setTime(0,0,0);
$endn2=clone $n2->getEnd();
$endn2->add(new \DateInterval('P1D'))->setTime(0,0,0);
if ($n1) {
$startn1 = clone $n1->getStart();
$startn1->setTime(0, 0, 0);
$endn1 = clone $n1->getEnd();
$endn1->add(new \DateInterval('P1D'))->setTime(0, 0, 0);
}
if ($n2) {
$startn2 = clone $n2->getStart();
$startn2->setTime(0, 0, 0);
$endn2 = clone $n2->getEnd();
$endn2->add(new \DateInterval('P1D'))->setTime(0, 0, 0);
}
// Pour chaque domaine
$tbdomaines=[];
$domaines = $em->getRepository("App:Domaine")->findBy([],['category'=>'ASC','name'=>'ASC']);
foreach($domaines as $domaine) {
$tbdomaines = [];
$domaines = $em->getRepository('App:Domaine')->findBy([], ['category' => 'ASC', 'name' => 'ASC']);
foreach ($domaines as $domaine) {
// Filtre par Domaine
if($this->get('session')->get('iddomaine')!="all") {
if($domaine->getId()!=$this->get('session')->get('iddomaine'))
if ('all' != $this->get('session')->get('iddomaine')) {
if ($domaine->getId() != $this->get('session')->get('iddomaine')) {
continue;
}
}
// On calcume le réel validé pour les deux périodes pour les domaines
$tbdomaines[$domaine->getId()]=[
"id" => $domaine->getId(),
"category" => $domaine->getCategory(),
"name" => $domaine->getCategory()." - ".$domaine->getName(),
$tbdomaines[$domaine->getId()] = [
'id' => $domaine->getId(),
'category' => $domaine->getCategory(),
'name' => $domaine->getCategory().' - '.$domaine->getName(),
"nbdayrealn1" => 0,
"nbetprealn1" => 0,
"nbcaarealn1" => 0,
"nbdaybudgn1" => 0,
"nbetpbudgn1" => 0,
"nbcaabudgn1" => 0,
'nbdayrealn1' => 0,
'nbetprealn1' => 0,
'nbcaarealn1' => 0,
'nbdaybudgn1' => 0,
'nbetpbudgn1' => 0,
'nbcaabudgn1' => 0,
"nbdayrealn2" => 0,
"nbetprealn2" => 0,
"nbcaarealn2" => 0,
"nbdaybudgn2" => 0,
"nbetpbudgn2" => 0,
"nbcaabudgn2" => 0,
'nbdayrealn2' => 0,
'nbetprealn2' => 0,
'nbcaarealn2' => 0,
'nbdaybudgn2' => 0,
'nbetpbudgn2' => 0,
'nbcaabudgn2' => 0,
"projects" => [],
'projects' => [],
];
// Période précédente n1
if($n1) {
if ($n1) {
// Events
$start=clone $n1->getStart();
$start->setTime(0,0,0);
$end=clone $n1->getEnd();
$end->add(new \DateInterval('P1D'))->setTime(0,0,0);
$start = clone $n1->getStart();
$start->setTime(0, 0, 0);
$end = clone $n1->getEnd();
$end->add(new \DateInterval('P1D'))->setTime(0, 0, 0);
$events = $em
$events = $em
->createQueryBuilder('event')
->select('SUM(event.duration) as somme')
->from('App:Project','project')
->from('App:Task','task')
->from('App:Event','event')
->from('App:Project', 'project')
->from('App:Task', 'task')
->from('App:Event', 'event')
->Where('project.domaine=:domaine')
->andWhere('task.project=project')
->andWhere('event.task=task')
->andWhere('event.start >=:start')
->andWhere('event.end <=:end')
->andWhere('event.validate=:validate')
->setParameter('domaine',$domaine)
->setParameter('start',$startn1)
->setParameter('end',$endn1)
->setParameter('validate',true)
->setParameter('domaine', $domaine)
->setParameter('start', $startn1)
->setParameter('end', $endn1)
->setParameter('validate', true)
->getQuery()->getResult();
$tbdomaines[$domaine->getId()]["nbdayrealn1"]=($events[0]["somme"]?$events[0]["somme"]:0);
$tbdomaines[$domaine->getId()]["nbetprealn1"]=$tbdomaines[$domaine->getId()]["nbdayrealn1"]/$n1->getNbday();
$tbdomaines[$domaine->getId()]['nbdayrealn1'] = ($events[0]['somme'] ? $events[0]['somme'] : 0);
$tbdomaines[$domaine->getId()]['nbetprealn1'] = $tbdomaines[$domaine->getId()]['nbdayrealn1'] / $n1->getNbday();
// Yeardomaine
$yeardomaine=$em->getRepository("App:Yeardomaine")->findOneBy(["domaine"=>$domaine,"year"=>$n1]);
if($yeardomaine) {
$tbdomaines[$domaine->getId()]["nbcaarealn1"]=$yeardomaine->getCareal();
$yeardomaine = $em->getRepository('App:Yeardomaine')->findOneBy(['domaine' => $domaine, 'year' => $n1]);
if ($yeardomaine) {
$tbdomaines[$domaine->getId()]['nbcaarealn1'] = $yeardomaine->getCareal();
$tbdomaines[$domaine->getId()]["nbdaybudgn1"]=$yeardomaine->getNbdaybudget();
$tbdomaines[$domaine->getId()]["nbetpbudgn1"]=$yeardomaine->getNbdaybudget()/$n1->getNbday();
$tbdomaines[$domaine->getId()]["nbcaabudgn1"]=$yeardomaine->getCabudget();
$tbdomaines[$domaine->getId()]['nbdaybudgn1'] = $yeardomaine->getNbdaybudget();
$tbdomaines[$domaine->getId()]['nbetpbudgn1'] = $yeardomaine->getNbdaybudget() / $n1->getNbday();
$tbdomaines[$domaine->getId()]['nbcaabudgn1'] = $yeardomaine->getCabudget();
}
}
// Période encour n2
if($n2) {
$events = $em
if ($n2) {
$events = $em
->createQueryBuilder('event')
->select('SUM(event.duration) as somme')
->from('App:Project','project')
->from('App:Task','task')
->from('App:Event','event')
->from('App:Project', 'project')
->from('App:Task', 'task')
->from('App:Event', 'event')
->Where('project.domaine=:domaine')
->andWhere('task.project=project')
->andWhere('event.task=task')
->andWhere('event.start >=:start')
->andWhere('event.end <=:end')
->andWhere('event.validate=:validate')
->setParameter('domaine',$domaine)
->setParameter('start',$startn2)
->setParameter('end',$endn2)
->setParameter('validate',true)
->setParameter('domaine', $domaine)
->setParameter('start', $startn2)
->setParameter('end', $endn2)
->setParameter('validate', true)
->getQuery()->getResult();
$tbdomaines[$domaine->getId()]["nbdayrealn2"]=($events[0]["somme"]?$events[0]["somme"]:0);
$tbdomaines[$domaine->getId()]["nbetprealn2"]=$tbdomaines[$domaine->getId()]["nbdayrealn2"]/$n2->getNbday();
$tbdomaines[$domaine->getId()]['nbdayrealn2'] = ($events[0]['somme'] ? $events[0]['somme'] : 0);
$tbdomaines[$domaine->getId()]['nbetprealn2'] = $tbdomaines[$domaine->getId()]['nbdayrealn2'] / $n2->getNbday();
// Yeardomaine
$yeardomaine=$em->getRepository("App:Yeardomaine")->findOneBy(["domaine"=>$domaine,"year"=>$n2]);
if($yeardomaine) {
$tbdomaines[$domaine->getId()]["nbcaarealn2"]=$yeardomaine->getCareal();
$yeardomaine = $em->getRepository('App:Yeardomaine')->findOneBy(['domaine' => $domaine, 'year' => $n2]);
if ($yeardomaine) {
$tbdomaines[$domaine->getId()]['nbcaarealn2'] = $yeardomaine->getCareal();
$tbdomaines[$domaine->getId()]["nbdaybudgn2"]=$yeardomaine->getNbdaybudget();
$tbdomaines[$domaine->getId()]["nbetpbudgn2"]=$yeardomaine->getNbdaybudget()/$n2->getNbday();
$tbdomaines[$domaine->getId()]["nbcaabudgn2"]=$yeardomaine->getCabudget();
$tbdomaines[$domaine->getId()]['nbdaybudgn2'] = $yeardomaine->getNbdaybudget();
$tbdomaines[$domaine->getId()]['nbetpbudgn2'] = $yeardomaine->getNbdaybudget() / $n2->getNbday();
$tbdomaines[$domaine->getId()]['nbcaabudgn2'] = $yeardomaine->getCabudget();
}
}
// Pour chaque project du domaine
foreach($domaine->getProjects() as $project) {
foreach ($domaine->getProjects() as $project) {
// On calcume le réel validé pour les deux périodes pour les projects
$tbdomaines[$domaine->getId()]["projects"][$project->getId()]=[
"id" => $project->getId(),
"name" => $project->getCustomer()->getName()." - ".$project->getName(),
"nbdayrealn1" => 0,
"nbetprealn1" => 0,
"nbcaarealn1" => 0,
"nbdaybudgn1" => 0,
"nbetpbudgn1" => 0,
"nbcaabudgn1" => 0,
$tbdomaines[$domaine->getId()]['projects'][$project->getId()] = [
'id' => $project->getId(),
'name' => $project->getCustomer()->getName().' - '.$project->getName(),
'nbdayrealn1' => 0,
'nbetprealn1' => 0,
'nbcaarealn1' => 0,
'nbdaybudgn1' => 0,
'nbetpbudgn1' => 0,
'nbcaabudgn1' => 0,
"nbdayrealn2" => 0,
"nbetprealn2" => 0,
"nbcaarealn2" => 0,
"nbdaybudgn2" => 0,
"nbetpbudgn2" => 0,
"nbcaabudgn2" => 0,
'nbdayrealn2' => 0,
'nbetprealn2' => 0,
'nbcaarealn2' => 0,
'nbdaybudgn2' => 0,
'nbetpbudgn2' => 0,
'nbcaabudgn2' => 0,
];
// Période précédente n1
if($n1) {
$events = $em
if ($n1) {
$events = $em
->createQueryBuilder('event')
->select('SUM(event.duration) as somme')
->from('App:Task','task')
->from('App:Event','event')
->from('App:Task', 'task')
->from('App:Event', 'event')
->Where('task.project=:project')
->andWhere('event.task=task')
->andWhere('event.start >=:start')
->andWhere('event.end <=:end')
->andWhere('event.validate=:validate')
->setParameter('project',$project)
->setParameter('start',$startn1)
->setParameter('end',$endn1)
->setParameter('validate',true)
->setParameter('project', $project)
->setParameter('start', $startn1)
->setParameter('end', $endn1)
->setParameter('validate', true)
->getQuery()->getResult();
$nbdayrealn1=($events[0]["somme"]?$events[0]["somme"]:0);
$tbdomaines[$domaine->getId()]["projects"][$project->getId()]["nbdayrealn1"]=$nbdayrealn1;
$tbdomaines[$domaine->getId()]["projects"][$project->getId()]["nbetprealn1"]=$nbdayrealn1/$n1->getNbday();
$nbdayrealn1 = ($events[0]['somme'] ? $events[0]['somme'] : 0);
$tbdomaines[$domaine->getId()]['projects'][$project->getId()]['nbdayrealn1'] = $nbdayrealn1;
$tbdomaines[$domaine->getId()]['projects'][$project->getId()]['nbetprealn1'] = $nbdayrealn1 / $n1->getNbday();
// Yearproject
$yearproject=$em->getRepository("App:Yearproject")->findOneBy(["project"=>$project,"year"=>$n1]);
if($yearproject) {
$tbdomaines[$domaine->getId()]["projects"][$project->getId()]["nbcaarealn1"]=$yearproject->getCareal();
$yearproject = $em->getRepository('App:Yearproject')->findOneBy(['project' => $project, 'year' => $n1]);
if ($yearproject) {
$tbdomaines[$domaine->getId()]['projects'][$project->getId()]['nbcaarealn1'] = $yearproject->getCareal();
$tbdomaines[$domaine->getId()]["projects"][$project->getId()]["nbdaybudgn1"]=$yearproject->getNbdaybudget();
$tbdomaines[$domaine->getId()]["projects"][$project->getId()]["nbetpbudgn1"]=$yearproject->getNbdaybudget()/$n1->getNbday();
$tbdomaines[$domaine->getId()]["projects"][$project->getId()]["nbcaabudgn1"]=$yearproject->getCabudget();
$tbdomaines[$domaine->getId()]['projects'][$project->getId()]['nbdaybudgn1'] = $yearproject->getNbdaybudget();
$tbdomaines[$domaine->getId()]['projects'][$project->getId()]['nbetpbudgn1'] = $yearproject->getNbdaybudget() / $n1->getNbday();
$tbdomaines[$domaine->getId()]['projects'][$project->getId()]['nbcaabudgn1'] = $yearproject->getCabudget();
}
}
// Période encour n2
if($n2) {
$start=$n2->getStart()->setTime(0,0,0);;
$end=$n2->getEnd()->add(new \DateInterval('P1D'))->setTime(0,0,0);
$events = $em
if ($n2) {
$start = $n2->getStart()->setTime(0, 0, 0);
$end = $n2->getEnd()->add(new \DateInterval('P1D'))->setTime(0, 0, 0);
$events = $em
->createQueryBuilder('event')
->select('SUM(event.duration) as somme')
->from('App:Task','task')
->from('App:Event','event')
->from('App:Task', 'task')
->from('App:Event', 'event')
->andWhere('task.project=:project')
->andWhere('event.task=task')
->andWhere('event.start >=:start')
->andWhere('event.end <=:end')
->andWhere('event.validate=:validate')
->setParameter('project',$project)
->setParameter('start',$startn2)
->setParameter('end',$endn2)
->setParameter('validate',true)
->setParameter('project', $project)
->setParameter('start', $startn2)
->setParameter('end', $endn2)
->setParameter('validate', true)
->getQuery()->getResult();
$nbdayrealn2=($events[0]["somme"]?$events[0]["somme"]:0);
$tbdomaines[$domaine->getId()]["projects"][$project->getId()]["nbdayrealn2"]=$nbdayrealn2;
$tbdomaines[$domaine->getId()]["projects"][$project->getId()]["nbetprealn2"]=$nbdayrealn2/$n2->getNbday();
$nbdayrealn2 = ($events[0]['somme'] ? $events[0]['somme'] : 0);
$tbdomaines[$domaine->getId()]['projects'][$project->getId()]['nbdayrealn2'] = $nbdayrealn2;
$tbdomaines[$domaine->getId()]['projects'][$project->getId()]['nbetprealn2'] = $nbdayrealn2 / $n2->getNbday();
// Yearproject
$yearproject=$em->getRepository("App:Yearproject")->findOneBy(["project"=>$project,"year"=>$n2]);
if($yearproject) {
$tbdomaines[$domaine->getId()]["projects"][$project->getId()]["nbcaarealn2"]=$yearproject->getCareal();
$yearproject = $em->getRepository('App:Yearproject')->findOneBy(['project' => $project, 'year' => $n2]);
if ($yearproject) {
$tbdomaines[$domaine->getId()]['projects'][$project->getId()]['nbcaarealn2'] = $yearproject->getCareal();
$tbdomaines[$domaine->getId()]["projects"][$project->getId()]["nbdaybudgn2"]=$yearproject->getNbdaybudget();
$tbdomaines[$domaine->getId()]["projects"][$project->getId()]["nbetpbudgn2"]=$yearproject->getNbdaybudget()/$n2->getNbday();
$tbdomaines[$domaine->getId()]["projects"][$project->getId()]["nbcaabudgn2"]=$yearproject->getCabudget();
$tbdomaines[$domaine->getId()]['projects'][$project->getId()]['nbdaybudgn2'] = $yearproject->getNbdaybudget();
$tbdomaines[$domaine->getId()]['projects'][$project->getId()]['nbetpbudgn2'] = $yearproject->getNbdaybudget() / $n2->getNbday();
$tbdomaines[$domaine->getId()]['projects'][$project->getId()]['nbcaabudgn2'] = $yearproject->getCabudget();
}
}
if(!$project->getActive()&&$nbdayrealn1==0&&$nbdayrealn2==0)
unset($tbdomaines[$domaine->getId()]["projects"][$project->getId()]);
if (!$project->getActive() && 0 == $nbdayrealn1 && 0 == $nbdayrealn2) {
unset($tbdomaines[$domaine->getId()]['projects'][$project->getId()]);
}
}
}
if($request->query->get('fgprint')) {
$render = $this->renderView('Budget/list.html.twig',[
"useheader" => true,
"usesidebar" => true,
"domaines" => $tbdomaines,
"n1" => $n1,
"n2" => $n2,
"years" => $years,
"fgprint" => true,
if ($request->query->get('fgprint')) {
$render = $this->renderView('Budget/list.html.twig', [
'useheader' => true,
'usesidebar' => true,
'domaines' => $tbdomaines,
'n1' => $n1,
'n2' => $n2,
'years' => $years,
'fgprint' => true,
]);
return new PdfResponse(
$this->knpSnappy->getOutputFromHtml($render),
'domaines.pdf'
);
}
else {
return $this->render('Budget/list.html.twig',[
"useheader" => true,
"usesidebar" => true,
"domaines" => $tbdomaines,
"n1" => $n1,
"n2" => $n2,
"years" => $years,
} else {
return $this->render('Budget/list.html.twig', [
'useheader' => true,
'usesidebar' => true,
'domaines' => $tbdomaines,
'n1' => $n1,
'n2' => $n2,
'years' => $years,
]);
}
}
public function update($type,$id,$year,Request $request)
public function update($type, $id, $year, Request $request)
{
// Initialisation de l'enregistrement
$em = $this->getDoctrine()->getManager();
// Returnto
$returnto=$request->get("returnto");
$returnto = $request->get('returnto');
// Recherche de l'exercice
$year=$em->getRepository("App:Year")->find($year);
$year = $em->getRepository('App:Year')->find($year);
// Recherche de la ligne projet/domaine associée à l'exercice
if($type=="project") {
$project=$em->getRepository("App:Project")->find($id);
$data=$em->getRepository("App:Yearproject")->findOneBy(["year"=>$year,"project"=>$project]);
if(!$data) {
$data=new Yearproject;
if ('project' == $type) {
$project = $em->getRepository('App:Project')->find($id);
$data = $em->getRepository('App:Yearproject')->findOneBy(['year' => $year, 'project' => $project]);
if (!$data) {
$data = new Yearproject();
$data->setYear($year);
$data->setProject($project);
$em->persist($data);
@@ -316,13 +319,12 @@ class BudgetController extends AbstractController
}
// Création du formulaire
$form = $this->createForm(YearprojectType::class,$data,array("mode"=>"update"));
}
else {
$domaine=$em->getRepository("App:Domaine")->find($id);
$data=$em->getRepository("App:Yeardomaine")->findOneBy(["year"=>$year,"domaine"=>$domaine]);
if(!$data) {
$data=new Yeardomaine;
$form = $this->createForm(YearprojectType::class, $data, ['mode' => 'update']);
} else {
$domaine = $em->getRepository('App:Domaine')->find($id);
$data = $em->getRepository('App:Yeardomaine')->findOneBy(['year' => $year, 'domaine' => $domaine]);
if (!$data) {
$data = new Yeardomaine();
$data->setYear($year);
$data->setDomaine($domaine);
$em->persist($data);
@@ -330,15 +332,14 @@ class BudgetController extends AbstractController
}
// Création du formulaire
$form = $this->createForm(YeardomaineType::class,$data,array("mode"=>"update"));
$form = $this->createForm(YeardomaineType::class, $data, ['mode' => 'update']);
}
// Récupération des data du formulaire
$form->handleRequest($request);
// Sur erreur
$this->getErrorForm(null,$form,$request,$data,"update");
$this->getErrorForm(null, $form, $request, $data, 'update');
// Sur validation
if ($form->get('submit')->isClicked() && $form->isValid()) {
@@ -347,60 +348,61 @@ class BudgetController extends AbstractController
$em->flush();
// Retour à la liste
if($returnto)
return $this->redirectToRoute("app_budget",["id"=>$returnto]);
else
return $this->redirectToRoute("app_budget",["id"=>$year->getId()]);
if ($returnto) {
return $this->redirectToRoute('app_budget', ['id' => $returnto]);
} else {
return $this->redirectToRoute('app_budget', ['id' => $year->getId()]);
}
}
// Affichage du formulaire
if($request->query->get('fgprint')) {
if ($request->query->get('fgprint')) {
$render = $this->renderView('Budget/edit.html.twig', [
'useheader' => true,
'usesidebar' => true,
'budget' => $data,
'type' => $type,
'id' => $id,
'year' => $year,
'mode' => 'update',
'form' => $form->createView(),
"fgprint" => true,
"returnto" => $returnto,
'useheader' => true,
'usesidebar' => true,
'budget' => $data,
'type' => $type,
'id' => $id,
'year' => $year,
'mode' => 'update',
'form' => $form->createView(),
'fgprint' => true,
'returnto' => $returnto,
]);
return new PdfResponse(
$this->knpSnappy->getOutputFromHtml($render),
'budget.pdf'
);
}
else {
} else {
return $this->render('Budget/edit.html.twig', [
'useheader' => true,
'usesidebar' => true,
'budget' => $data,
'type' => $type,
'id' => $id,
'year' => $year,
'mode' => 'update',
'form' => $form->createView(),
"returnto" => $returnto,
'useheader' => true,
'usesidebar' => true,
'budget' => $data,
'type' => $type,
'id' => $id,
'year' => $year,
'mode' => 'update',
'form' => $form->createView(),
'returnto' => $returnto,
]);
}
}
protected function getErrorForm($id,$form,$request,$data,$mode) {
if ($form->get('submit')->isClicked()&&$mode=="delete") {
protected function getErrorForm($id, $form, $request, $data, $mode)
{
if ($form->get('submit')->isClicked() && 'delete' == $mode) {
}
if ($form->get('submit')->isClicked() && $mode=="submit") {
if ($form->get('submit')->isClicked() && 'submit' == $mode) {
}
if ($form->get('submit')->isClicked() && !$form->isValid()) {
$this->get('session')->getFlashBag()->clear();
$errors = $form->getErrors();
foreach( $errors as $error ) {
$request->getSession()->getFlashBag()->add("error", $error->getMessage());
foreach ($errors as $error) {
$request->getSession()->getFlashBag()->add('error', $error->getMessage());
}
}
}

View File

@@ -2,113 +2,82 @@
namespace App\Controller;
use App\Form\CronType;
use App\Repository\CronRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Form\FormError;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use App\Entity\Cron as Entity;
use App\Form\CronType as Form;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class CronController extends AbstractController
{
private $data = "cron";
private $route = "app_cron";
private $render = "Cron/";
private $entity = "App:Cron";
private EntityManagerInterface $em;
private CronRepository $cronRepository;
public function __construct(EntityManagerInterface $em, CronRepository $cronRepository)
{
$this->em = $em;
$this->cronRepository = $cronRepository;
}
public function list()
{
$em = $this->getDoctrine()->getManager();
$datas = $em->getRepository($this->entity)->findAll();
$crons = $this->cronRepository->findAll();
return $this->render($this->render.'list.html.twig',[
$this->data."s" => $datas,
"useheader" => true,
"usesidebar" => true,
return $this->render('Cron/list.html.twig', [
'crons' => $crons,
'useheader' => true,
'usesidebar' => true,
]);
}
public function update($id,Request $request)
public function update($id, Request $request)
{
// Initialisation de l'enregistrement
$em = $this->getDoctrine()->getManager();
$data=$em->getRepository($this->entity)->find($id);
// Création du formulaire
$form = $this->createForm(Form::class,$data,array("mode"=>"update"));
// Récupération des data du formulaire
$form->handleRequest($request);
// Sur erreur
$this->getErrorForm(null,$form,$request,$data,"update");
// Sur validation
if ($form->get('submit')->isClicked() && $form->isValid()) {
$data = $form->getData();
$em->persist($data);
$em->flush();
// Retour à la liste
return $this->redirectToRoute($this->route);
$cron = $this->cronRepository->find($id);
if (!$cron) {
throw new NotFoundHttpException('La ressource demandée est introuvable.');
}
// Affichage du formulaire
return $this->render($this->render.'edit.html.twig', [
'useheader' => true,
'usesidebar' => true,
$this->data => $data,
'mode' => 'update',
'form' => $form->createView()
$form = $this->createForm(CronType::class, $cron, ['mode' => 'update']);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->em->persist($cron);
$this->em->flush();
return $this->redirectToRoute('app_cron');
}
return $this->render('Cron/edit.html.twig', [
'useheader' => true,
'usesidebar' => true,
'cron' => $cron,
'mode' => 'update',
'form' => $form->createView(),
]);
}
public function log()
{
return $this->render($this->render.'logs.html.twig', [
'useheader' => true,
'usesidebar' => true,
return $this->render('Cron/logs.html.twig', [
'useheader' => true,
'usesidebar' => true,
]);
}
public function getlog(Request $request, $id)
public function getlog($id)
{
$path = $this->getParameter('kernel.project_dir');
if($id=="dump")
$file = $path . '/var/log/' . $this->getParameter("appAlias") . '.sql';
else
$file = $path . '/var/log/'.$id.'.log';
if ('dump' == $id) {
$file = $path.'/var/log/'.$this->getParameter('appAlias').'.sql';
} else {
$file = $path.'/var/log/'.$id.'.log';
}
$response = new BinaryFileResponse($file);
$response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT);
return $response;
}
protected function getErrorForm($id,$form,$request,$data,$mode) {
if ($form->get('submit')->isClicked()&&$mode=="delete") {
}
if ($form->get('submit')->isClicked() && $mode=="submit") {
}
if ($form->get('submit')->isClicked() && !$form->isValid()) {
$this->get('session')->getFlashBag()->clear();
$errors = $form->getErrors();
foreach( $errors as $error ) {
$request->getSession()->getFlashBag()->add("error", $error->getMessage());
}
}
}
}

View File

@@ -2,51 +2,53 @@
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Form\FormError;
use Knp\Bundle\SnappyBundle\Snappy\Response\PdfResponse;
use App\Entity\Domaine;
use App\Entity\Service;
use App\Entity\Task as Entity;
use App\Form\TaskType as Form;
use Knp\Bundle\SnappyBundle\Snappy\Response\PdfResponse;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
class TaskController extends AbstractController
{
private $data = "task";
private $route = "app_task";
private $render = "Task/";
private $entity = "App:Task";
private $data = 'task';
private $route = 'app_task';
private $render = 'Task/';
private $entity = 'App:Task';
private $knpSnappy;
public function __construct(\Knp\Snappy\Pdf $knpSnappy) { $this->knpSnappy = $knpSnappy; }
public function __construct(\Knp\Snappy\Pdf $knpSnappy)
{
$this->knpSnappy = $knpSnappy;
}
public function list(Request $request)
{
$em = $this->getDoctrine()->getManager();
$services=$em->getRepository("App:Service")->findAllTaskActive($this->get('session')->get('activeproject'),$this->get('session')->get('idservice'));
$domaines=$em->getRepository("App:Domaine")->findAllTaskActive($this->get('session')->get('activeproject'),$this->get('session')->get('iddomaine'));
$services = $em->getRepository(Service::class)->findAllTaskActive($this->get('session')->get('activeproject'), $this->get('session')->get('idservice'));
$domaines = $em->getRepository(Domaine::class)->findAllTaskActive($this->get('session')->get('activeproject'), $this->get('session')->get('iddomaine'));
if($request->query->get('fgprint')) {
$render = $this->renderView($this->render.'list.html.twig',[
"services" => $services,
"domaines" => $domaines,
"useheader" => true,
"usesidebar" => true,
"fgprint" => true,
if ($request->query->get('fgprint')) {
$render = $this->renderView($this->render.'list.html.twig', [
'services' => $services,
'domaines' => $domaines,
'useheader' => true,
'usesidebar' => true,
'fgprint' => true,
]);
return new PdfResponse(
$this->knpSnappy->getOutputFromHtml($render,["orientation"=>"Landscape"]),
$this->knpSnappy->getOutputFromHtml($render, ['orientation' => 'Landscape']),
'taches.pdf'
);
}
else {
return $this->render($this->render.'list.html.twig',[
"services" => $services,
"domaines" => $domaines,
"useheader" => true,
"usesidebar" => true,
} else {
return $this->render($this->render.'list.html.twig', [
'services' => $services,
'domaines' => $domaines,
'useheader' => true,
'usesidebar' => true,
]);
}
}
@@ -56,17 +58,17 @@ class TaskController extends AbstractController
// Initialisation de l'enregistrement
$em = $this->getDoctrine()->getManager();
$data = new Entity();
$defaultnature = $em->getRepository("App:Nature")->findOneBy(['name' => 'Prestation']);
$defaultnature = $em->getRepository('App:Nature')->findOneBy(['name' => 'Prestation']);
$data->setNature($defaultnature);
$data->setActive(true);
// Création du formulaire
$form = $this->createForm(Form::class,$data,array("mode"=>"submit"));
$form = $this->createForm(Form::class, $data, ['mode' => 'submit']);
// Récupération des data du formulaire
$form->handleRequest($request);
// Sur erreur
$this->getErrorForm(null,$form,$request,$data,"submit");
$this->getErrorForm(null, $form, $request, $data, 'submit');
// Sur validation
if ($form->get('submit')->isClicked() && $form->isValid()) {
@@ -80,28 +82,28 @@ class TaskController extends AbstractController
// Affichage du formulaire
return $this->render($this->render.'edit.html.twig', [
'useheader' => true,
'usesidebar' => true,
$this->data => $data,
'mode' => 'submit',
'form' => $form->createView()
'useheader' => true,
'usesidebar' => true,
$this->data => $data,
'mode' => 'submit',
'form' => $form->createView(),
]);
}
public function update($id,Request $request)
public function update($id, Request $request)
{
// Initialisation de l'enregistrement
$em = $this->getDoctrine()->getManager();
$data=$em->getRepository($this->entity)->find($id);
$data = $em->getRepository($this->entity)->find($id);
// Création du formulaire
$form = $this->createForm(Form::class,$data,array("mode"=>"update"));
$form = $this->createForm(Form::class, $data, ['mode' => 'update']);
// Récupération des data du formulaire
$form->handleRequest($request);
// Sur erreur
$this->getErrorForm(null,$form,$request,$data,"update");
$this->getErrorForm(null, $form, $request, $data, 'update');
// Sur validation
if ($form->get('submit')->isClicked() && $form->isValid()) {
@@ -114,51 +116,50 @@ class TaskController extends AbstractController
}
// Affichage du formulaire
if($request->query->get('fgprint')) {
if ($request->query->get('fgprint')) {
$render = $this->renderView($this->render.'edit.html.twig', [
'useheader' => true,
'usesidebar' => true,
$this->data => $data,
'mode' => 'update',
'form' => $form->createView(),
"fgprint" => true,
'useheader' => true,
'usesidebar' => true,
$this->data => $data,
'mode' => 'update',
'form' => $form->createView(),
'fgprint' => true,
]);
return new PdfResponse(
$this->knpSnappy->getOutputFromHtml($render),
'tache.pdf'
);
}
else {
} else {
return $this->render($this->render.'edit.html.twig', [
'useheader' => true,
'usesidebar' => true,
$this->data => $data,
'mode' => 'update',
'form' => $form->createView()
'useheader' => true,
'usesidebar' => true,
$this->data => $data,
'mode' => 'update',
'form' => $form->createView(),
]);
}
}
}
public function delete($id,Request $request)
public function delete($id, Request $request)
{
// Initialisation de l'enregistrement
$em = $this->getDoctrine()->getManager();
$data=$em->getRepository($this->entity)->find($id);
$data = $em->getRepository($this->entity)->find($id);
// Controle avant suppression
$error=false;
if($error)
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
else {
$error = false;
if ($error) {
return $this->redirectToRoute($this->route.'_update', ['id' => $id]);
} else {
try {
$em->remove($data);
$em->flush();
}
catch(\Doctrine\DBAL\DBALException $e) {
} catch (\Doctrine\DBAL\DBALException $e) {
// Création du formulaire
$this->get('session')->getFlashBag()->add('error', 'Impossible de supprimer cet enregistrement');
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
return $this->redirectToRoute($this->route.'_update', ['id' => $id]);
}
// Retour à la liste
@@ -166,34 +167,41 @@ class TaskController extends AbstractController
}
}
public function activeproject() {
$this->get('session')->set('activeproject',!$this->get('session')->get('activeproject'));
public function activeproject()
{
$this->get('session')->set('activeproject', !$this->get('session')->get('activeproject'));
return $this->redirectToRoute($this->route);
}
public function activetask() {
$this->get('session')->set('activetask',!$this->get('session')->get('activetask'));
return $this->redirectToRoute($this->route);
}
public function activetask()
{
$this->get('session')->set('activetask', !$this->get('session')->get('activetask'));
public function viewservice() {
$this->get('session')->set('viewservice',!$this->get('session')->get('viewservice'));
return $this->redirectToRoute($this->route);
}
protected function getErrorForm($id,$form,$request,$data,$mode) {
if ($form->get('submit')->isClicked()&&$mode=="delete") {
public function viewservice()
{
$this->get('session')->set('viewservice', !$this->get('session')->get('viewservice'));
return $this->redirectToRoute($this->route);
}
protected function getErrorForm($id, $form, $request, $data, $mode)
{
if ($form->get('submit')->isClicked() && 'delete' == $mode) {
}
if ($form->get('submit')->isClicked() && $mode=="submit") {
if ($form->get('submit')->isClicked() && 'submit' == $mode) {
}
if ($form->get('submit')->isClicked() && !$form->isValid()) {
$this->get('session')->getFlashBag()->clear();
$errors = $form->getErrors();
foreach( $errors as $error ) {
$request->getSession()->getFlashBag()->add("error", $error->getMessage());
foreach ($errors as $error) {
$request->getSession()->getFlashBag()->add('error', $error->getMessage());
}
}
}

View File

@@ -2,12 +2,8 @@
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Event
@@ -30,13 +26,11 @@ class Breakday
/**
* @ORM\Column(name="start", type="datetime", unique=true)
*
*/
private $start;
/**
* @ORM\Column(name="end", type="datetime")
*
*/
private $end;
@@ -45,24 +39,24 @@ class Breakday
return $this->id;
}
public function getStart(): ?\DateTimeInterface
public function getStart(): ?\DateTime
{
return $this->start;
}
public function setStart(\DateTimeInterface $start): self
public function setStart(\DateTime $start): self
{
$this->start = $start;
return $this;
}
public function getEnd(): ?\DateTimeInterface
public function getEnd(): ?\DateTime
{
return $this->end;
}
public function setEnd(\DateTimeInterface $end): self
public function setEnd(\DateTime $end): self
{
$this->end = $end;