added project start and end date (#1303)
* added sortable js library * activity in invoice is optional * added javascript widget for paginated boxes * fix activity dropdown for globals only * added timesheet service to reduce code duplication * use repository to query for teams in dropdowns * added project validator * validate project start and end against timesheet * include begin and end in dynamic form requests for projects * added timezone and language option to import flag, improve timesheet import speed * deactivate cross-timezone filter * add virtual fields to field order list * composer update * added param to ignore dates * position loader icon fixed - fixes #1330 * permission problem when creating a new project - fixes #1340 * remove dev dependencies webserver and thanks bundle * stop information leak (begin and end date) in duration mode - fixes #1307 * unify timesheet edit dialog for user and admins * fix security issue, own rates exposed to unauthorized users in multi-update dialog
This commit is contained in:
160
src/Form/FormTrait.php
Normal file
160
src/Form/FormTrait.php
Normal file
@@ -0,0 +1,160 @@
|
||||
<?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\Form;
|
||||
|
||||
use App\Entity\Activity;
|
||||
use App\Entity\Customer;
|
||||
use App\Entity\Project;
|
||||
use App\Form\Type\ActivityType;
|
||||
use App\Form\Type\CustomerType;
|
||||
use App\Form\Type\ProjectType;
|
||||
use App\Form\Type\TagsInputType;
|
||||
use App\Repository\ActivityRepository;
|
||||
use App\Repository\CustomerRepository;
|
||||
use App\Repository\ProjectRepository;
|
||||
use App\Repository\Query\ActivityFormTypeQuery;
|
||||
use App\Repository\Query\CustomerFormTypeQuery;
|
||||
use App\Repository\Query\ProjectFormTypeQuery;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Form\FormEvent;
|
||||
use Symfony\Component\Form\FormEvents;
|
||||
|
||||
/**
|
||||
* Defines the form used to manipulate Timesheet entries.
|
||||
*/
|
||||
trait FormTrait
|
||||
{
|
||||
protected function addCustomer(FormBuilderInterface $builder, ?Customer $customer = null)
|
||||
{
|
||||
$builder
|
||||
->add('customer', CustomerType::class, [
|
||||
'query_builder' => function (CustomerRepository $repo) use ($builder, $customer) {
|
||||
$query = new CustomerFormTypeQuery($customer);
|
||||
$query->setUser($builder->getOption('user'));
|
||||
|
||||
return $repo->getQueryBuilderForFormType($query);
|
||||
},
|
||||
'data' => $customer ? $customer : '',
|
||||
'required' => false,
|
||||
'placeholder' => '',
|
||||
'mapped' => false,
|
||||
'project_enabled' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function addProject(FormBuilderInterface $builder, bool $isNew, ?Project $project = null, ?Customer $customer = null)
|
||||
{
|
||||
$builder->add('project', ProjectType::class, [
|
||||
'placeholder' => '',
|
||||
'activity_enabled' => true,
|
||||
'query_builder' => function (ProjectRepository $repo) use ($builder, $project, $customer) {
|
||||
$query = new ProjectFormTypeQuery($project, $customer);
|
||||
$query->setUser($builder->getOption('user'));
|
||||
|
||||
return $repo->getQueryBuilderForFormType($query);
|
||||
},
|
||||
]);
|
||||
|
||||
// replaces the project select after submission, to make sure only projects for the selected customer are displayed
|
||||
$builder->addEventListener(
|
||||
FormEvents::PRE_SUBMIT,
|
||||
function (FormEvent $event) use ($builder, $project, $customer, $isNew) {
|
||||
$data = $event->getData();
|
||||
$customer = isset($data['customer']) && !empty($data['customer']) ? $data['customer'] : null;
|
||||
$project = isset($data['project']) && !empty($data['project']) ? $data['project'] : $project;
|
||||
|
||||
$event->getForm()->add('project', ProjectType::class, [
|
||||
'placeholder' => '',
|
||||
'activity_enabled' => true,
|
||||
'group_by' => null,
|
||||
'query_builder' => function (ProjectRepository $repo) use ($builder, $project, $customer, $isNew) {
|
||||
// is there a better wa to prevent starting a record with a hidden project ?
|
||||
if ($isNew && !empty($project) && (is_int($project) || is_string($project))) {
|
||||
/** @var Project $project */
|
||||
$project = $repo->find($project);
|
||||
if (null !== $project) {
|
||||
if (!$project->getCustomer()->isVisible()) {
|
||||
$customer = null;
|
||||
$project = null;
|
||||
} elseif (!$project->isVisible()) {
|
||||
$project = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
$query = new ProjectFormTypeQuery($project, $customer);
|
||||
$query->setUser($builder->getOption('user'));
|
||||
|
||||
return $repo->getQueryBuilderForFormType($query);
|
||||
},
|
||||
]);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
protected function addActivity(FormBuilderInterface $builder, ?Activity $activity = null, ?Project $project = null)
|
||||
{
|
||||
$builder
|
||||
->add('activity', ActivityType::class, [
|
||||
'placeholder' => '',
|
||||
'query_builder' => function (ActivityRepository $repo) use ($activity, $project) {
|
||||
return $repo->getQueryBuilderForFormType(new ActivityFormTypeQuery($activity, $project));
|
||||
},
|
||||
])
|
||||
;
|
||||
|
||||
// replaces the activity select after submission, to make sure only activities for the selected project are displayed
|
||||
$builder->addEventListener(
|
||||
FormEvents::PRE_SUBMIT,
|
||||
function (FormEvent $event) use ($activity) {
|
||||
$data = $event->getData();
|
||||
if (!isset($data['project']) || empty($data['project'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$event->getForm()->add('activity', ActivityType::class, [
|
||||
'placeholder' => '',
|
||||
'query_builder' => function (ActivityRepository $repo) use ($data, $activity) {
|
||||
if (!empty($activity) && is_string($activity)) {
|
||||
$activity = $repo->find($activity);
|
||||
}
|
||||
|
||||
return $repo->getQueryBuilderForFormType(new ActivityFormTypeQuery($activity, $data['project']));
|
||||
},
|
||||
]);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
protected function addDescription(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder
|
||||
->add('description', TextareaType::class, [
|
||||
'label' => 'label.description',
|
||||
'required' => false,
|
||||
'attr' => [
|
||||
'autofocus' => 'autofocus'
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
protected function addTags(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder
|
||||
->add('tags', TagsInputType::class, [
|
||||
// documentation is for NelmioApiDocBundle
|
||||
'documentation' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Comma separated list of tags',
|
||||
],
|
||||
'required' => false,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -196,13 +196,15 @@ class TimesheetMultiUpdate extends AbstractType
|
||||
]);
|
||||
}
|
||||
|
||||
$builder
|
||||
->add('fixedRate', FixedRateType::class, [
|
||||
'currency' => $currency,
|
||||
])
|
||||
->add('hourlyRate', HourlyRateType::class, [
|
||||
'currency' => $currency,
|
||||
]);
|
||||
if ($options['include_rate']) {
|
||||
$builder
|
||||
->add('fixedRate', FixedRateType::class, [
|
||||
'currency' => $currency,
|
||||
])
|
||||
->add('hourlyRate', HourlyRateType::class, [
|
||||
'currency' => $currency,
|
||||
]);
|
||||
}
|
||||
|
||||
$builder->add('entities', HiddenType::class, [
|
||||
'required' => false,
|
||||
@@ -241,6 +243,7 @@ class TimesheetMultiUpdate extends AbstractType
|
||||
'csrf_field_name' => '_token',
|
||||
'csrf_token_id' => 'timesheet_multiupdate',
|
||||
'include_user' => false,
|
||||
'include_rate' => false,
|
||||
'include_exported' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -63,6 +63,14 @@ class ProjectEditForm extends AbstractType
|
||||
'label' => 'label.orderDate',
|
||||
'required' => false,
|
||||
])
|
||||
->add('start', DateTimePickerType::class, [
|
||||
'label' => 'label.project_start',
|
||||
'required' => false,
|
||||
])
|
||||
->add('end', DateTimePickerType::class, [
|
||||
'label' => 'label.project_end',
|
||||
'required' => false,
|
||||
])
|
||||
->add('customer', CustomerType::class, [
|
||||
'query_builder' => function (CustomerRepository $repo) use ($builder, $customer) {
|
||||
$query = new CustomerFormTypeQuery($customer);
|
||||
|
||||
@@ -9,30 +9,20 @@
|
||||
|
||||
namespace App\Form;
|
||||
|
||||
use App\Entity\Activity;
|
||||
use App\Entity\Customer;
|
||||
use App\Entity\Project;
|
||||
use App\Entity\Timesheet;
|
||||
use App\Form\Type\ActivityType;
|
||||
use App\Form\Type\CustomerType;
|
||||
use App\Form\Type\DateTimePickerType;
|
||||
use App\Form\Type\DurationType;
|
||||
use App\Form\Type\FixedRateType;
|
||||
use App\Form\Type\HourlyRateType;
|
||||
use App\Form\Type\MetaFieldsCollectionType;
|
||||
use App\Form\Type\ProjectType;
|
||||
use App\Form\Type\TagsInputType;
|
||||
use App\Form\Type\UserType;
|
||||
use App\Form\Type\YesNoType;
|
||||
use App\Repository\ActivityRepository;
|
||||
use App\Repository\CustomerRepository;
|
||||
use App\Repository\ProjectRepository;
|
||||
use App\Repository\Query\ActivityFormTypeQuery;
|
||||
use App\Repository\Query\CustomerFormTypeQuery;
|
||||
use App\Repository\Query\ProjectFormTypeQuery;
|
||||
use App\Timesheet\UserDateTimeFactory;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Form\FormEvent;
|
||||
use Symfony\Component\Form\FormEvents;
|
||||
@@ -43,6 +33,8 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
*/
|
||||
class TimesheetEditForm extends AbstractType
|
||||
{
|
||||
use FormTrait;
|
||||
|
||||
/**
|
||||
* @var CustomerRepository
|
||||
*/
|
||||
@@ -141,7 +133,7 @@ class TimesheetEditForm extends AbstractType
|
||||
$this->addCustomer($builder, $customer);
|
||||
}
|
||||
|
||||
$this->addProject($builder, $customerCount, $isNew, $project, $customer);
|
||||
$this->addProject($builder, $isNew, $project, $customer);
|
||||
$this->addActivity($builder, $activity, $project);
|
||||
$this->addDescription($builder);
|
||||
$this->addTags($builder);
|
||||
@@ -169,114 +161,6 @@ class TimesheetEditForm extends AbstractType
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function addCustomer(FormBuilderInterface $builder, ?Customer $customer = null)
|
||||
{
|
||||
$builder
|
||||
->add('customer', CustomerType::class, [
|
||||
'query_builder' => function (CustomerRepository $repo) use ($builder, $customer) {
|
||||
$query = new CustomerFormTypeQuery($customer);
|
||||
$query->setUser($builder->getOption('user'));
|
||||
|
||||
return $repo->getQueryBuilderForFormType($query);
|
||||
},
|
||||
'data' => $customer ? $customer : '',
|
||||
'required' => false,
|
||||
'placeholder' => '',
|
||||
'mapped' => false,
|
||||
'project_enabled' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function addProject(FormBuilderInterface $builder, int $customerCount, bool $isNew, ?Project $project = null, ?Customer $customer = null)
|
||||
{
|
||||
$projectOptions = [];
|
||||
|
||||
if ($customerCount < 2) {
|
||||
$projectOptions['group_by'] = null;
|
||||
}
|
||||
|
||||
$builder
|
||||
->add(
|
||||
'project',
|
||||
ProjectType::class,
|
||||
array_merge($projectOptions, [
|
||||
'placeholder' => '',
|
||||
'activity_enabled' => true,
|
||||
'query_builder' => function (ProjectRepository $repo) use ($builder, $project, $customer) {
|
||||
$query = new ProjectFormTypeQuery($project, $customer);
|
||||
$query->setUser($builder->getOption('user'));
|
||||
|
||||
return $repo->getQueryBuilderForFormType($query);
|
||||
},
|
||||
])
|
||||
);
|
||||
|
||||
// replaces the project select after submission, to make sure only projects for the selected customer are displayed
|
||||
$builder->addEventListener(
|
||||
FormEvents::PRE_SUBMIT,
|
||||
function (FormEvent $event) use ($builder, $project, $customer, $isNew) {
|
||||
$data = $event->getData();
|
||||
$customer = isset($data['customer']) && !empty($data['customer']) ? $data['customer'] : null;
|
||||
$project = isset($data['project']) && !empty($data['project']) ? $data['project'] : $project;
|
||||
|
||||
$event->getForm()->add('project', ProjectType::class, [
|
||||
'placeholder' => '',
|
||||
'activity_enabled' => true,
|
||||
'group_by' => null,
|
||||
'query_builder' => function (ProjectRepository $repo) use ($builder, $project, $customer, $isNew) {
|
||||
// is there a better wa to prevent starting a record with a hidden project ?
|
||||
if ($isNew && !empty($project) && (is_int($project) || is_string($project))) {
|
||||
/** @var Project $project */
|
||||
$project = $repo->find($project);
|
||||
if (null !== $project) {
|
||||
if (!$project->getCustomer()->isVisible()) {
|
||||
$customer = null;
|
||||
$project = null;
|
||||
} elseif (!$project->isVisible()) {
|
||||
$project = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
$query = new ProjectFormTypeQuery($project, $customer);
|
||||
$query->setUser($builder->getOption('user'));
|
||||
|
||||
return $repo->getQueryBuilderForFormType($query);
|
||||
},
|
||||
]);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
protected function addActivity(FormBuilderInterface $builder, ?Activity $activity = null, ?Project $project = null)
|
||||
{
|
||||
$builder
|
||||
->add('activity', ActivityType::class, [
|
||||
'placeholder' => '',
|
||||
'query_builder' => function (ActivityRepository $repo) use ($activity, $project) {
|
||||
return $repo->getQueryBuilderForFormType(new ActivityFormTypeQuery($activity, $project));
|
||||
},
|
||||
])
|
||||
;
|
||||
|
||||
// replaces the activity select after submission, to make sure only activities for the selected project are displayed
|
||||
$builder->addEventListener(
|
||||
FormEvents::PRE_SUBMIT,
|
||||
function (FormEvent $event) use ($activity) {
|
||||
$data = $event->getData();
|
||||
if (!isset($data['project']) || empty($data['project'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$event->getForm()->add('activity', ActivityType::class, [
|
||||
'placeholder' => '',
|
||||
'query_builder' => function (ActivityRepository $repo) use ($data, $activity) {
|
||||
return $repo->getQueryBuilderForFormType(new ActivityFormTypeQuery($activity, $data['project']));
|
||||
},
|
||||
]);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
protected function addBegin(FormBuilderInterface $builder, array $dateTimeOptions)
|
||||
{
|
||||
$builder->add('begin', DateTimePickerType::class, array_merge($dateTimeOptions, [
|
||||
@@ -330,31 +214,6 @@ class TimesheetEditForm extends AbstractType
|
||||
);
|
||||
}
|
||||
|
||||
protected function addDescription(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder
|
||||
->add('description', TextareaType::class, [
|
||||
'label' => 'label.description',
|
||||
'required' => false,
|
||||
'attr' => [
|
||||
'autofocus' => 'autofocus'
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
protected function addTags(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder
|
||||
->add('tags', TagsInputType::class, [
|
||||
// documentation is for NelmioApiDocBundle
|
||||
'documentation' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Comma separated list of tags for this timesheet record',
|
||||
],
|
||||
'required' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function addRates(FormBuilderInterface $builder, $currency, array $options)
|
||||
{
|
||||
if (!$options['include_rate']) {
|
||||
|
||||
@@ -71,18 +71,20 @@ abstract class AbstractToolbarForm extends AbstractType
|
||||
]);
|
||||
}
|
||||
|
||||
protected function addCustomerChoice(FormBuilderInterface $builder, bool $required = false)
|
||||
protected function addCustomerChoice(FormBuilderInterface $builder, array $options = [])
|
||||
{
|
||||
// just a fake field for having this field at the right position in the frontend
|
||||
$builder->add('customer', HiddenType::class);
|
||||
|
||||
$builder->addEventListener(
|
||||
FormEvents::PRE_SUBMIT,
|
||||
function (FormEvent $event) use ($builder, $required) {
|
||||
function (FormEvent $event) use ($builder, $options) {
|
||||
$data = $event->getData();
|
||||
$event->getForm()->add('customer', CustomerType::class, [
|
||||
'required' => $required,
|
||||
$event->getForm()->add('customer', CustomerType::class, array_merge([
|
||||
'required' => false,
|
||||
'project_enabled' => true,
|
||||
'end_date_param' => '%daterange%',
|
||||
'start_date_param' => '%daterange%',
|
||||
'query_builder' => function (CustomerRepository $repo) use ($builder, $data) {
|
||||
$query = new CustomerFormTypeQuery();
|
||||
$query->setUser($builder->getOption('user'));
|
||||
@@ -92,7 +94,7 @@ abstract class AbstractToolbarForm extends AbstractType
|
||||
|
||||
return $repo->getQueryBuilderForFormType($query);
|
||||
},
|
||||
]);
|
||||
], $options));
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -130,19 +132,19 @@ abstract class AbstractToolbarForm extends AbstractType
|
||||
]);
|
||||
}
|
||||
|
||||
protected function addProjectChoice(FormBuilderInterface $builder)
|
||||
protected function addProjectChoice(FormBuilderInterface $builder, array $options = [])
|
||||
{
|
||||
// just a fake field for having this field at the right position in the frontend
|
||||
$builder->add('project', HiddenType::class);
|
||||
|
||||
$builder->addEventListener(
|
||||
FormEvents::PRE_SUBMIT,
|
||||
function (FormEvent $event) use ($builder) {
|
||||
function (FormEvent $event) use ($builder, $options) {
|
||||
$data = $event->getData();
|
||||
$event->getForm()->add('project', ProjectType::class, [
|
||||
$event->getForm()->add('project', ProjectType::class, array_merge([
|
||||
'required' => false,
|
||||
'activity_enabled' => true,
|
||||
'query_builder' => function (ProjectRepository $repo) use ($builder, $data) {
|
||||
'query_builder' => function (ProjectRepository $repo) use ($builder, $data, $options) {
|
||||
$query = new ProjectFormTypeQuery();
|
||||
$query->setUser($builder->getOption('user'));
|
||||
|
||||
@@ -152,10 +154,13 @@ abstract class AbstractToolbarForm extends AbstractType
|
||||
if (isset($data['project']) && !empty($data['project'])) {
|
||||
$query->setProject($data['project']);
|
||||
}
|
||||
if (isset($options['ignore_date']) && true === $options['ignore_date']) {
|
||||
$query->setIgnoreDate(true);
|
||||
}
|
||||
|
||||
return $repo->getQueryBuilderForFormType($query);
|
||||
},
|
||||
]);
|
||||
], $options));
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -175,7 +180,12 @@ abstract class AbstractToolbarForm extends AbstractType
|
||||
$query = new ActivityFormTypeQuery();
|
||||
|
||||
if (isset($data['activity']) && !empty($data['activity'])) {
|
||||
$query->setActivity($data['activity']);
|
||||
$activity = $data['activity'];
|
||||
if (is_string($data['activity'])) {
|
||||
$activity = $repo->find($data['activity']);
|
||||
}
|
||||
|
||||
$query->setActivity($activity);
|
||||
}
|
||||
if (isset($data['project']) && !empty($data['project'])) {
|
||||
$query->setProject($data['project']);
|
||||
|
||||
@@ -31,8 +31,8 @@ class ExportToolbarForm extends AbstractToolbarForm
|
||||
$this->addTimesheetStateChoice($builder);
|
||||
$this->addUsersChoice($builder);
|
||||
$this->addDateRangeChoice($builder);
|
||||
$this->addCustomerChoice($builder);
|
||||
$this->addProjectChoice($builder);
|
||||
$this->addCustomerChoice($builder, ['start_date_param' => null, 'end_date_param' => null, 'ignore_date' => true]);
|
||||
$this->addProjectChoice($builder, ['ignore_date' => true]);
|
||||
$this->addActivityChoice($builder);
|
||||
$this->addExportType($builder);
|
||||
$this->addTagInputField($builder);
|
||||
|
||||
@@ -32,8 +32,8 @@ class InvoiceToolbarForm extends AbstractToolbarForm
|
||||
$this->addUsersChoice($builder);
|
||||
}
|
||||
$this->addDateRangeChoice($builder);
|
||||
$this->addCustomerChoice($builder, true);
|
||||
$this->addProjectChoice($builder);
|
||||
$this->addCustomerChoice($builder, ['required' => true, 'start_date_param' => null, 'end_date_param' => null, 'ignore_date' => true, 'placeholder' => '']);
|
||||
$this->addProjectChoice($builder, ['ignore_date' => true]);
|
||||
$this->addActivityChoice($builder);
|
||||
$this->addTagInputField($builder);
|
||||
$this->addExportStateChoice($builder);
|
||||
|
||||
@@ -39,6 +39,9 @@ class CustomerType extends AbstractType
|
||||
'choice_label' => 'name',
|
||||
'query_builder_for_user' => true,
|
||||
'project_enabled' => false,
|
||||
'start_date_param' => '%begin%',
|
||||
'end_date_param' => '%end%',
|
||||
'ignore_date' => false,
|
||||
'project_visibility' => ProjectQuery::SHOW_VISIBLE,
|
||||
]);
|
||||
|
||||
@@ -55,11 +58,29 @@ class CustomerType extends AbstractType
|
||||
|
||||
$resolver->setDefault('api_data', function (Options $options) {
|
||||
if (true === $options['project_enabled']) {
|
||||
$routeParams = ['customer' => '%customer%', 'visible' => $options['project_visibility']];
|
||||
$emptyRouteParams = ['visible' => $options['project_visibility']];
|
||||
|
||||
if (!$options['ignore_date']) {
|
||||
if (!empty($options['start_date_param'])) {
|
||||
$routeParams['start'] = $options['start_date_param'];
|
||||
$emptyRouteParams['start'] = $options['start_date_param'];
|
||||
}
|
||||
|
||||
if (!empty($options['end_date_param'])) {
|
||||
$routeParams['end'] = $options['end_date_param'];
|
||||
$emptyRouteParams['end'] = $options['end_date_param'];
|
||||
}
|
||||
} else {
|
||||
$routeParams['ignoreDates'] = 1;
|
||||
$emptyRouteParams['ignoreDates'] = 1;
|
||||
}
|
||||
|
||||
return [
|
||||
'select' => 'project',
|
||||
'route' => 'get_projects',
|
||||
'route_params' => ['customer' => '-s-', 'visible' => $options['project_visibility']],
|
||||
'empty_route_params' => ['visible' => $options['project_visibility']],
|
||||
'route_params' => $routeParams,
|
||||
'empty_route_params' => $emptyRouteParams,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ class ProjectType extends AbstractType
|
||||
'query_builder_for_user' => true,
|
||||
'activity_enabled' => false,
|
||||
'activity_visibility' => ActivityQuery::SHOW_VISIBLE,
|
||||
'ignore_date' => false,
|
||||
]);
|
||||
|
||||
$resolver->setDefault('query_builder', function (Options $options) {
|
||||
@@ -73,6 +74,9 @@ class ProjectType extends AbstractType
|
||||
if (true === $options['query_builder_for_user']) {
|
||||
$query->setUser($options['user']);
|
||||
}
|
||||
if (true === $options['ignore_date']) {
|
||||
$query->setIgnoreDate(true);
|
||||
}
|
||||
|
||||
return $repo->getQueryBuilderForFormType($query);
|
||||
};
|
||||
@@ -83,7 +87,7 @@ class ProjectType extends AbstractType
|
||||
return [
|
||||
'select' => 'activity',
|
||||
'route' => 'get_activities',
|
||||
'route_params' => ['project' => '-s-', 'visible' => $options['activity_visibility']],
|
||||
'route_params' => ['project' => '%project%', 'visible' => $options['activity_visibility']],
|
||||
'empty_route_params' => ['globals' => 'true', 'visible' => $options['activity_visibility']],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -10,9 +10,12 @@
|
||||
namespace App\Form\Type;
|
||||
|
||||
use App\Entity\Team;
|
||||
use App\Entity\User;
|
||||
use App\Repository\Query\TeamQuery;
|
||||
use App\Repository\TeamRepository;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class TeamType extends AbstractType
|
||||
@@ -25,13 +28,26 @@ class TeamType extends AbstractType
|
||||
$resolver->setDefaults([
|
||||
'class' => Team::class,
|
||||
'label' => 'label.team',
|
||||
'query_builder' => function (TeamRepository $repo) {
|
||||
return $repo->createQueryBuilder('t')->orderBy('t.name', 'ASC');
|
||||
},
|
||||
'teamlead_only' => true,
|
||||
'choice_label' => function (Team $team) {
|
||||
return $team->getName();
|
||||
},
|
||||
]);
|
||||
|
||||
$resolver->setDefault('query_builder', function (Options $options) {
|
||||
return function (TeamRepository $repo) use ($options) {
|
||||
/** @var User $user */
|
||||
$user = $options['user'];
|
||||
$query = new TeamQuery();
|
||||
$query->setCurrentUser($user);
|
||||
|
||||
if (!$options['teamlead_only']) {
|
||||
$query->setTeams($user->getTeams()->toArray());
|
||||
}
|
||||
|
||||
return $repo->getQueryBuilderForFormType($query);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
namespace App\Form\Type;
|
||||
|
||||
use App\Repository\Query\VisibilityQuery;
|
||||
use App\Repository\Query\VisibilityInterface;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
@@ -27,9 +27,9 @@ class VisibilityType extends AbstractType
|
||||
$resolver->setDefaults([
|
||||
'label' => 'label.visible',
|
||||
'choices' => [
|
||||
'both' => VisibilityQuery::SHOW_BOTH,
|
||||
'yes' => VisibilityQuery::SHOW_VISIBLE,
|
||||
'no' => VisibilityQuery::SHOW_HIDDEN,
|
||||
'both' => VisibilityInterface::SHOW_BOTH,
|
||||
'yes' => VisibilityInterface::SHOW_VISIBLE,
|
||||
'no' => VisibilityInterface::SHOW_HIDDEN,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user