Next major version 2 with PHP 8.1, Symfony 6, Tabler UI, 2FA ... (#2902)

This commit is contained in:
Kevin Papst
2022-12-31 21:19:55 +01:00
committed by GitHub
parent 95e06746bd
commit 90a0fd8a22
2164 changed files with 83700 additions and 86426 deletions

View File

@@ -9,8 +9,20 @@
namespace App\Reporting\CustomerMonthlyProjects;
use App\Entity\Customer;
use App\Reporting\AbstractUserList;
final class CustomerMonthlyProjects extends AbstractUserList
{
private ?Customer $customer = null;
public function getCustomer(): ?Customer
{
return $this->customer;
}
public function setCustomer(?Customer $customer): void
{
$this->customer = $customer;
}
}

View File

@@ -9,31 +9,32 @@
namespace App\Reporting\CustomerMonthlyProjects;
use App\Form\Type\CustomerType;
use App\Form\Type\MonthPickerType;
use App\Form\Type\ReportSumType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class CustomerMonthlyProjectsForm extends AbstractType
final class CustomerMonthlyProjectsForm extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('customer', CustomerType::class, [
'required' => false,
'width' => false,
]);
$builder->add('date', MonthPickerType::class, [
'model_timezone' => $options['timezone'],
'view_timezone' => $options['timezone'],
'start_date' => $options['start_date'],
]);
$builder->add('sumType', ReportSumType::class);
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => CustomerMonthlyProjects::class,

View File

@@ -0,0 +1,185 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Reporting\CustomerMonthlyProjects;
use App\Entity\Activity;
use App\Entity\Customer;
use App\Entity\Project;
use App\Entity\User;
use App\Repository\TimesheetRepository;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query\Expr\Join;
final class CustomerMonthlyProjectsRepository
{
public function __construct(private TimesheetRepository $repository, private EntityManagerInterface $entityManager)
{
}
/**
* @param DateTime $begin
* @param DateTime $end
* @param User[] $users
* @param Customer|null $customer
* @return array
* @internal
*/
public function getGroupedByCustomerProjectActivityUser(DateTime $begin, DateTime $end, array $users, ?Customer $customer): array
{
$stats = [];
$qb = $this->repository->createQueryBuilder('t');
$qb
->select('COALESCE(SUM(t.rate), 0) as rate')
->addSelect('COALESCE(SUM(t.duration), 0) as duration')
->addSelect('COALESCE(SUM(t.internalRate), 0) as internalRate')
->addSelect('IDENTITY(t.user) as user')
->addSelect('IDENTITY(t.activity) as activity')
->addSelect('IDENTITY(t.project) as project')
->where($qb->expr()->isNotNull('t.end'))
->andWhere($qb->expr()->between('t.begin', ':begin', ':end'))
->andWhere($qb->expr()->in('t.user', ':user'))
->setParameter('begin', $begin)
->setParameter('end', $end)
->setParameter('user', $users)
->groupBy('project')
->addGroupBy('activity')
->addGroupBy('user')
;
if ($customer !== null) {
$qb2 = $this->entityManager->createQueryBuilder();
$qb2->select('p.id')
->from(Project::class, 'p')
->andWhere($qb2->expr()->eq('p.customer', ':customer'))
->setParameter('customer', $customer->getId())
;
$projectIds = $qb2->getQuery()->getSingleColumnResult();
$qb
->andWhere($qb->expr()->in('t.project', ':project'))
->setParameter('project', array_values($projectIds))
;
}
$results = $qb->getQuery()->getResult();
$projectIds = [];
$activityIds = [];
$userIds = [];
foreach ($results as $row) {
$projectId = $row['project'];
$activityId = $row['activity'];
$userId = $row['user'];
$projectIds[$projectId] = $projectId;
$activityIds[$activityId] = $activityId;
$userIds[$userId] = $userId;
if (!isset($stats[$projectId])) {
$stats[$projectId] = [
'id' => $projectId,
'customer' => '',
'customer_id' => null,
'name' => null,
'activities' => [],
'duration' => 0,
'rate' => 0,
'internalRate' => 0,
'max_users' => 0,
];
}
$stats[$projectId]['duration'] += (int) $row['duration'];
$stats[$projectId]['rate'] += (int) $row['rate'];
$stats[$projectId]['internalRate'] += (int) $row['internalRate'];
if (!isset($stats[$projectId]['activities'][$activityId])) {
$stats[$projectId]['activities'][$activityId] = [
'id' => $activityId,
'name' => null,
'users' => [],
'duration' => 0,
'rate' => 0,
'internalRate' => 0,
];
}
$stats[$projectId]['activities'][$activityId]['duration'] += (int) $row['duration'];
$stats[$projectId]['activities'][$activityId]['rate'] += (int) $row['rate'];
$stats[$projectId]['activities'][$activityId]['internalRate'] += (int) $row['internalRate'];
if (!isset($stats[$projectId]['activities'][$activityId]['users'][$userId])) {
$stats[$projectId]['activities'][$activityId]['users'][$userId] = [
'id' => $userId,
'name' => null,
'duration' => 0,
'rate' => 0,
'internalRate' => 0,
];
}
$stats[$projectId]['activities'][$activityId]['users'][$userId]['duration'] += (int) $row['duration'];
$stats[$projectId]['activities'][$activityId]['users'][$userId]['rate'] += (int) $row['rate'];
$stats[$projectId]['activities'][$activityId]['users'][$userId]['internalRate'] += (int) $row['internalRate'];
}
$qb = $this->entityManager->createQueryBuilder();
$qb
->select('a.id, a.name')
->from(Activity::class, 'a', 'a.id')
->where($qb->expr()->in('a.id', ':id'))
->setParameter('id', array_values($activityIds))
;
$activities = $qb->getQuery()->getResult();
$qb = $this->entityManager->createQueryBuilder();
$qb
->select('p.id, p.name, c.id as customer_id, c.name as customer, c.currency')
->from(Project::class, 'p', 'p.id')
->leftJoin(Customer::class, 'c', Join::WITH, 'c.id = p.customer')
->where($qb->expr()->in('p.id', ':id'))
->setParameter('id', array_values($projectIds))
;
$projects = $qb->getQuery()->getResult();
$qb = $this->entityManager->createQueryBuilder();
$qb
->select('u')
->from(User::class, 'u', 'u.id')
->where($qb->expr()->in('u.id', ':id'))
->setParameter('id', array_values($userIds))
;
$users = $qb->getQuery()->getResult();
foreach (array_keys($stats) as $pid) {
$stats[$pid]['name'] = $projects[$pid]['name'];
$stats[$pid]['customer'] = $projects[$pid]['customer'];
$stats[$pid]['customer_id'] = $projects[$pid]['customer_id'];
foreach (array_keys($stats[$pid]['activities']) as $aid) {
$stats[$pid]['activities'][$aid]['name'] = $activities[$aid]['name'];
foreach (array_keys($stats[$pid]['activities'][$aid]['users']) as $uid) {
$stats[$pid]['activities'][$aid]['users'][$uid]['name'] = $users[$uid]->getDisplayName();
}
$stats[$pid]['max_users'] = max($stats[$pid]['max_users'], \count($stats[$pid]['activities'][$aid]['users']));
}
}
return [
'stats' => $stats,
'projects' => $projects,
'activities' => $activities,
'users' => $users,
];
}
}

View File

@@ -13,14 +13,14 @@ use App\Entity\User;
abstract class DateByUser extends AbstractUserList
{
private $user;
private ?User $user = null;
public function getUser(): ?User
{
return $this->user;
}
public function setUser(User $user): void
public function setUser(?User $user): void
{
$this->user = $user;
}

View File

@@ -7,7 +7,9 @@
* file that was distributed with this source code.
*/
namespace App\Reporting;
namespace App\Reporting\MonthByUser;
use App\Reporting\DateByUser;
final class MonthByUser extends DateByUser
{

View File

@@ -7,7 +7,7 @@
* file that was distributed with this source code.
*/
namespace App\Reporting;
namespace App\Reporting\MonthByUser;
use App\Form\Type\MonthPickerType;
use App\Form\Type\ReportSumType;
@@ -16,22 +16,9 @@ use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class MonthByUserForm extends AbstractType
final class MonthByUserForm extends AbstractType
{
/**
* Simplify cross linking between pages by removing the block prefix.
*
* @return null|string
*/
public function getBlockPrefix()
{
return null;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('date', MonthPickerType::class, [
'model_timezone' => $options['timezone'],
@@ -45,10 +32,7 @@ class MonthByUserForm extends AbstractType
$builder->add('sumType', ReportSumType::class);
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => MonthByUser::class,

View File

@@ -7,7 +7,9 @@
* file that was distributed with this source code.
*/
namespace App\Reporting;
namespace App\Reporting\MonthlyUserList;
use App\Reporting\AbstractUserList;
final class MonthlyUserList extends AbstractUserList
{

View File

@@ -7,7 +7,7 @@
* file that was distributed with this source code.
*/
namespace App\Reporting;
namespace App\Reporting\MonthlyUserList;
use App\Form\Type\MonthPickerType;
use App\Form\Type\ReportSumType;
@@ -16,22 +16,9 @@ use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class MonthlyUserListForm extends AbstractType
final class MonthlyUserListForm extends AbstractType
{
/**
* Simplify cross linking between pages by removing the block prefix.
*
* @return null|string
*/
public function getBlockPrefix()
{
return null;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('date', MonthPickerType::class, [
'model_timezone' => $options['timezone'],
@@ -46,10 +33,7 @@ class MonthlyUserListForm extends AbstractType
$builder->add('sumType', ReportSumType::class);
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => MonthlyUserList::class,

View File

@@ -17,26 +17,12 @@ use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ProjectDateRangeForm extends AbstractType
final class ProjectDateRangeForm extends AbstractType
{
/**
* Simplify cross linking between pages by removing the block prefix.
*
* @return null|string
*/
public function getBlockPrefix()
{
return null;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('customer', CustomerType::class, [
'required' => false,
'label' => false,
'width' => false,
]);
@@ -48,26 +34,24 @@ class ProjectDateRangeForm extends AbstractType
$builder->add('includeNoWork', CheckboxType::class, [
'required' => false,
'label' => 'label.includeNoWork',
'label' => 'includeNoWork',
]);
$builder->add('budgetType', ChoiceType::class, [
'required' => true,
'placeholder' => null,
'required' => false,
'multiple' => false,
'expanded' => true,
'choices' => [
'label.budgetIndependent' => null,
'label.includeNoBudget' => 'none',
'label.includeBudgetType_full' => 'full',
'label.includeBudgetType_month' => 'month',
'all' => null,
'includeNoBudget' => 'none',
'includeBudgetType_full' => 'full',
'includeBudgetType_month' => 'month',
],
]);
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => ProjectDateRangeQuery::class,

View File

@@ -14,26 +14,11 @@ use App\Entity\User;
final class ProjectDateRangeQuery
{
/**
* @var \DateTime
*/
private $month;
/**
* @var User|null
*/
private $user;
/**
* @var Customer|null
*/
private $customer;
/**
* @var bool
*/
private $includeNoWork = false;
/**
* @var string|null
*/
private $budgetType = null;
private \DateTime $month;
private ?User $user;
private ?Customer $customer = null;
private bool $includeNoWork = false;
private ?string $budgetType = null;
public function __construct(\DateTime $month, User $user)
{

View File

@@ -12,38 +12,43 @@ namespace App\Reporting\ProjectDetails;
use App\Form\Type\ProjectType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ProjectDetailsForm extends AbstractType
final class ProjectDetailsForm extends AbstractType
{
/**
* Simplify cross linking between pages by removing the block prefix.
*
* @return null|string
*/
public function getBlockPrefix()
public function buildForm(FormBuilderInterface $builder, array $options): void
{
return null;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('project', ProjectType::class, [
$projectOptions = [
'ignore_date' => true,
'required' => false,
'label' => false,
'width' => false,
'join_customer' => true,
]);
];
$builder->add('project', ProjectType::class, $projectOptions);
$builder->addEventListener(
FormEvents::PRE_SUBMIT,
function (FormEvent $event) use ($projectOptions) {
$data = $event->getData();
if (isset($data['project']) && !empty($data['project'])) {
$projectId = $data['project'];
$projects = [];
if (\is_int($projectId) || \is_string($projectId)) {
$projects = [$projectId];
}
$event->getForm()->add('project', ProjectType::class, array_merge($projectOptions, [
'projects' => $projects
]));
}
}
);
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => ProjectDetailsQuery::class,

View File

@@ -19,34 +19,29 @@ use App\Model\UserStatistic;
final class ProjectDetailsModel
{
/**
* @var Project
*/
private $project;
/**
* @var Year[]
*/
private $years = [];
private array $years = [];
/**
* @var array<string, array<ActivityStatistic>>
*/
private $yearlyActivities = [];
private array $yearlyActivities = [];
/**
* @var array<string, array<int, UserYear>>
*/
private $usersMonthly = [];
private array $usersMonthly = [];
/**
* @var ActivityStatistic[]
*/
private $activities = [];
private array $activities = [];
/**
* @var BudgetStatisticModel
*/
private $budgetStatisticModel;
private ?BudgetStatisticModel $budgetStatisticModel = null;
public function __construct(Project $project)
public function __construct(private Project $project)
{
$this->project = $project;
}
public function getProject(): Project
@@ -76,7 +71,7 @@ final class ProjectDetailsModel
* @param string $year
* @return ActivityStatistic[]
*/
public function getYearActivities(string $year): ?array
public function getYearActivities(string $year): array
{
if (!\array_key_exists($year, $this->yearlyActivities)) {
return [];
@@ -99,8 +94,8 @@ final class ProjectDetailsModel
$userStat = new UserStatistic($userYear->getUser());
$users[$id] = $userStat;
}
$userStat->setRecordDuration($userStat->getRecordDuration() + $userYear->getDuration());
$userStat->setRecordRate($userStat->getRecordRate() + $userYear->getRate());
$userStat->setDuration($userStat->getDuration() + $userYear->getDuration());
$userStat->setRate($userStat->getRate() + $userYear->getRate());
}
}

View File

@@ -15,23 +15,10 @@ use DateTime;
final class ProjectDetailsQuery
{
/**
* @var Project|null
*/
private $project;
/**
* @var DateTime
*/
private $today;
/**
* @var User
*/
private $user;
private ?Project $project = null;
public function __construct(DateTime $today, User $user)
public function __construct(private DateTime $today, private User $user)
{
$this->today = $today;
$this->user = $user;
}
public function getToday(): DateTime

View File

@@ -9,39 +9,23 @@
namespace App\Reporting\ProjectInactive;
use App\Form\Type\DateTimePickerType;
use App\Form\Type\DatePickerType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ProjectInactiveForm extends AbstractType
final class ProjectInactiveForm extends AbstractType
{
/**
* Simplify cross linking between pages by removing the block prefix.
*
* @return null|string
*/
public function getBlockPrefix()
public function buildForm(FormBuilderInterface $builder, array $options): void
{
return null;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('lastChange', DateTimePickerType::class, [
'label' => 'label.last_record_before',
$builder->add('lastChange', DatePickerType::class, [
'label' => 'last_record_before',
'model_timezone' => $options['timezone'],
'view_timezone' => $options['timezone'],
]);
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => ProjectInactiveQuery::class,

View File

@@ -14,14 +14,8 @@ use DateTime;
final class ProjectInactiveQuery
{
/**
* @var DateTime
*/
private $lastChange;
/**
* @var User|null
*/
private $user;
private DateTime $lastChange;
private User $user;
public function __construct(DateTime $lastChange, User $user)
{

View File

@@ -12,45 +12,36 @@ namespace App\Reporting\ProjectView;
use App\Form\Type\CustomerType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ProjectViewForm extends AbstractType
final class ProjectViewForm extends AbstractType
{
/**
* Simplify cross linking between pages by removing the block prefix.
*
* @return null|string
*/
public function getBlockPrefix()
{
return null;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('customer', CustomerType::class, [
'required' => false,
'label' => false,
'width' => false,
]);
$builder->add('includeNoBudget', CheckboxType::class, [
$builder->add('budgetType', ChoiceType::class, [
'label' => false,
'required' => false,
'label' => 'label.includeNoBudget',
'placeholder' => null,
'expanded' => true,
'choices' => [
'all' => null,
'includeWithBudget' => true,
'includeNoBudget' => false
]
]);
$builder->add('includeNoWork', CheckboxType::class, [
'required' => false,
'label' => 'label.includeNoWork',
'label' => 'includeNoWork',
]);
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => ProjectViewQuery::class,

View File

@@ -15,31 +15,23 @@ use DateTime;
final class ProjectViewModel
{
private $project;
private $timesheetCounter = 0;
private $durationDay = 0;
private $durationWeek = 0;
private $durationMonth = 0;
private $durationTotal = 0;
private $rateTotal = 0.00;
private $notExportedDuration = 0;
private $notExportedRate = 0.00;
private $notBilledDuration = 0;
private $notBilledRate = 0.00;
private $billableDuration = 0;
private $billableRate = 0.00;
/**
* @var \DateTime|null
*/
private $lastRecord;
/**
* @var BudgetStatisticModelInterface
*/
private $budgetStatisticModel;
private int $timesheetCounter = 0;
private int $durationDay = 0;
private int $durationWeek = 0;
private int $durationMonth = 0;
private int $durationTotal = 0;
private float $rateTotal = 0.00;
private int $notExportedDuration = 0;
private float $notExportedRate = 0.00;
private int $notBilledDuration = 0;
private float $notBilledRate = 0.00;
private int $billableDuration = 0;
private float $billableRate = 0.00;
private ?DateTime $lastRecord = null;
private ?BudgetStatisticModelInterface $budgetStatisticModel = null;
public function __construct(Project $project)
public function __construct(private Project $project)
{
$this->project = $project;
}
public function getProject(): Project

View File

@@ -15,31 +15,12 @@ use DateTime;
final class ProjectViewQuery
{
/**
* @var Customer|null
*/
private $customer;
/**
* @var DateTime
*/
private $today;
/**
* @var User|null
*/
private $user;
/**
* @var bool
*/
private $includeNoBudget = false;
/**
* @var bool
*/
private $includeNoWork = false;
private ?Customer $customer = null;
private bool $includeNoWork = false;
private ?bool $budgetType = true;
public function __construct(DateTime $today, User $user)
public function __construct(private DateTime $today, private User $user)
{
$this->today = $today;
$this->user = $user;
}
public function getUser(): ?User
@@ -47,14 +28,27 @@ final class ProjectViewQuery
return $this->user;
}
public function isIncludeNoBudget(): bool
public function getBudgetType(): ?bool
{
return $this->includeNoBudget;
return $this->budgetType;
}
public function setIncludeNoBudget(bool $includeNoBudget): void
/**
* @internal
*/
public function setBudgetType(?bool $budgetType): void
{
$this->includeNoBudget = $includeNoBudget;
$this->budgetType = $budgetType;
}
public function isIncludeWithoutBudget(): bool
{
return $this->budgetType === false;
}
public function isIncludeWithBudget(): bool
{
return $this->budgetType === true;
}
public function isIncludeNoWork(): bool

View File

@@ -11,19 +11,8 @@ namespace App\Reporting;
final class Report implements ReportInterface
{
private $id;
private $label;
private $route;
private $reportIcon = 'reporting';
public function __construct(string $id, string $route, string $label, ?string $reportIcon = null)
public function __construct(private string $id, private string $route, private string $label, private string $reportIcon)
{
$this->id = $id;
$this->route = $route;
$this->label = $label;
if (null !== $reportIcon) {
$this->reportIcon = $reportIcon;
}
}
public function getRoute(): string

View File

@@ -16,21 +16,8 @@ use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
final class ReportingService
{
public const DEFAULT_VIEW = 'week_by_user';
/**
* @var EventDispatcherInterface
*/
private $dispatcher;
/**
* @var AuthorizationCheckerInterface
*/
private $security;
public function __construct(EventDispatcherInterface $dispatcher, AuthorizationCheckerInterface $security)
public function __construct(private EventDispatcherInterface $dispatcher, private AuthorizationCheckerInterface $security)
{
$this->dispatcher = $dispatcher;
$this->security = $security;
}
/**
@@ -42,29 +29,33 @@ final class ReportingService
$event = new ReportingEvent($user);
if ($this->security->isGranted('view_reporting')) {
$showBudget = $this->security->isGranted('budget_any', 'project');
$details = $this->security->isGranted('details', 'project');
$viewOther = $this->security->isGranted('view_other_reporting') && $this->security->isGranted('view_other_timesheet');
$event->addReport(new Report('week_by_user', 'report_user_week', 'report_user_week', 'user'));
$event->addReport(new Report('month_by_user', 'report_user_month', 'report_user_month', 'user'));
$event->addReport(new Report('year_by_user', 'report_user_year', 'report_user_year', 'user'));
if ($viewOther) {
if ($this->security->isGranted('report:user')) {
$event->addReport(new Report('week_by_user', 'report_user_week', 'report_user_week', 'user'));
$event->addReport(new Report('month_by_user', 'report_user_month', 'report_user_month', 'user'));
$event->addReport(new Report('year_by_user', 'report_user_year', 'report_user_year', 'user'));
}
if ($viewOther = $this->security->isGranted('report:other')) {
$event->addReport(new Report('weekly_users_list', 'report_weekly_users', 'report_weekly_users', 'users'));
$event->addReport(new Report('monthly_users_list', 'report_monthly_users', 'report_monthly_users', 'users'));
$event->addReport(new Report('yearly_users_list', 'report_yearly_users', 'report_yearly_users', 'users'));
}
if ($showBudget) {
$event->addReport(new Report('project_view', 'report_project_view', 'report_project_view', 'project'));
if ($this->security->isGranted('report:project')) {
if ($this->security->isGranted('details', 'project')) {
$event->addReport(new Report('project_details', 'report_project_details', 'report_project_details', 'project'));
}
if ($this->security->isGranted('budget_any', 'project')) {
$event->addReport(new Report('project_view', 'report_project_view', 'report_project_view', 'project'));
$event->addReport(new Report('daterange_projects', 'report_project_daterange', 'report_project_daterange', 'project'));
$event->addReport(new Report('inactive_projects', 'report_project_inactive', 'report_inactive_project', 'project'));
}
}
if ($details) {
$event->addReport(new Report('project_details', 'report_project_details', 'report_project_details', 'project'));
}
if ($showBudget) {
$event->addReport(new Report('daterange_projects', 'report_project_daterange', 'report_project_daterange', 'project'));
$event->addReport(new Report('inactive_projects', 'report_project_inactive', 'report_inactive_project', 'project'));
}
if ($viewOther) {
$event->addReport(new Report('report_customer_monthly_projects', 'report_customer_monthly_projects', 'report_customer_monthly_projects', 'customer'));
if ($this->security->isGranted('report:customer')) {
if ($viewOther) {
$event->addReport(new Report('report_customer_monthly_projects', 'report_customer_monthly_projects', 'report_customer_monthly_projects', 'customer'));
}
}
$this->dispatcher->dispatch($event);

View File

@@ -7,7 +7,9 @@
* file that was distributed with this source code.
*/
namespace App\Reporting;
namespace App\Reporting\WeekByUser;
use App\Reporting\DateByUser;
final class WeekByUser extends DateByUser
{

View File

@@ -7,7 +7,7 @@
* file that was distributed with this source code.
*/
namespace App\Reporting;
namespace App\Reporting\WeekByUser;
use App\Form\Type\ReportSumType;
use App\Form\Type\UserType;
@@ -16,22 +16,9 @@ use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class WeekByUserForm extends AbstractType
final class WeekByUserForm extends AbstractType
{
/**
* Simplify cross linking between pages by removing the block prefix.
*
* @return null|string
*/
public function getBlockPrefix()
{
return null;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('date', WeekPickerType::class, [
'model_timezone' => $options['timezone'],
@@ -45,10 +32,7 @@ class WeekByUserForm extends AbstractType
$builder->add('sumType', ReportSumType::class);
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => WeekByUser::class,

View File

@@ -7,7 +7,9 @@
* file that was distributed with this source code.
*/
namespace App\Reporting;
namespace App\Reporting\WeeklyUserList;
use App\Reporting\AbstractUserList;
final class WeeklyUserList extends AbstractUserList
{

View File

@@ -7,7 +7,7 @@
* file that was distributed with this source code.
*/
namespace App\Reporting;
namespace App\Reporting\WeeklyUserList;
use App\Form\Type\ReportSumType;
use App\Form\Type\TeamType;
@@ -16,22 +16,9 @@ use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class WeeklyUserListForm extends AbstractType
final class WeeklyUserListForm extends AbstractType
{
/**
* Simplify cross linking between pages by removing the block prefix.
*
* @return null|string
*/
public function getBlockPrefix()
{
return null;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('date', WeekPickerType::class, [
'model_timezone' => $options['timezone'],
@@ -46,10 +33,7 @@ class WeeklyUserListForm extends AbstractType
$builder->add('sumType', ReportSumType::class);
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => WeeklyUserList::class,

View File

@@ -7,7 +7,9 @@
* file that was distributed with this source code.
*/
namespace App\Reporting;
namespace App\Reporting\YearByUser;
use App\Reporting\DateByUser;
final class YearByUser extends DateByUser
{

View File

@@ -7,7 +7,7 @@
* file that was distributed with this source code.
*/
namespace App\Reporting;
namespace App\Reporting\YearByUser;
use App\Form\Type\ReportSumType;
use App\Form\Type\UserType;
@@ -16,22 +16,9 @@ use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class YearByUserForm extends AbstractType
final class YearByUserForm extends AbstractType
{
/**
* Simplify cross-linking between pages by removing the block prefix.
*
* @return null|string
*/
public function getBlockPrefix()
{
return null;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('date', YearPickerType::class, [
'model_timezone' => $options['timezone'],
@@ -45,10 +32,7 @@ class YearByUserForm extends AbstractType
$builder->add('sumType', ReportSumType::class);
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => YearByUser::class,

View File

@@ -7,7 +7,9 @@
* file that was distributed with this source code.
*/
namespace App\Reporting;
namespace App\Reporting\YearlyUserList;
use App\Reporting\AbstractUserList;
final class YearlyUserList extends AbstractUserList
{

View File

@@ -7,7 +7,7 @@
* file that was distributed with this source code.
*/
namespace App\Reporting;
namespace App\Reporting\YearlyUserList;
use App\Form\Type\ReportSumType;
use App\Form\Type\TeamType;
@@ -16,22 +16,9 @@ use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class YearlyUserListForm extends AbstractType
final class YearlyUserListForm extends AbstractType
{
/**
* Simplify cross linking between pages by removing the block prefix.
*
* @return null|string
*/
public function getBlockPrefix()
{
return null;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('date', YearPickerType::class, [
'model_timezone' => $options['timezone'],
@@ -47,10 +34,7 @@ class YearlyUserListForm extends AbstractType
$builder->add('sumType', ReportSumType::class);
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => YearlyUserList::class,