added database driven system configurations with admin screen (#647)
This commit is contained in:
177
src/Form/Model/Configuration.php
Normal file
177
src/Form/Model/Configuration.php
Normal file
@@ -0,0 +1,177 @@
|
||||
<?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\Model;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
|
||||
class Configuration
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $label;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $translationDomain = 'messages';
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private $value;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $type;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $enabled = true;
|
||||
/**
|
||||
* @var Constraint[]
|
||||
*/
|
||||
protected $constraints = [];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return Configuration
|
||||
*/
|
||||
public function setName(string $name)
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
* @return Configuration
|
||||
*/
|
||||
public function setValue($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @return Configuration
|
||||
*/
|
||||
public function setType(string $type)
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return $this->enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $enabled
|
||||
* @return Configuration
|
||||
*/
|
||||
public function setEnabled(bool $enabled)
|
||||
{
|
||||
$this->enabled = $enabled;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLabel()
|
||||
{
|
||||
return $this->label;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $label
|
||||
* @return Configuration
|
||||
*/
|
||||
public function setLabel(string $label)
|
||||
{
|
||||
$this->label = $label;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Constraint[]
|
||||
*/
|
||||
public function getConstraints(): array
|
||||
{
|
||||
return $this->constraints;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Constraint[] $constraints
|
||||
* @return Configuration
|
||||
*/
|
||||
public function setConstraints(array $constraints)
|
||||
{
|
||||
$this->constraints = $constraints;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTranslationDomain()
|
||||
{
|
||||
return $this->translationDomain;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $translationDomain
|
||||
* @return Configuration
|
||||
*/
|
||||
public function setTranslationDomain(string $translationDomain)
|
||||
{
|
||||
$this->translationDomain = $translationDomain;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
63
src/Form/Model/SystemConfiguration.php
Normal file
63
src/Form/Model/SystemConfiguration.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?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\Model;
|
||||
|
||||
class SystemConfiguration
|
||||
{
|
||||
public const SECTION_TIMESHEET = 'timesheet';
|
||||
public const SECTION_FORM_CUSTOMER = 'form_customer';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $section;
|
||||
/**
|
||||
* @var Configuration[]
|
||||
*/
|
||||
private $configuration;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSection(): string
|
||||
{
|
||||
return $this->section;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $section
|
||||
* @return SystemConfiguration
|
||||
*/
|
||||
public function setSection(string $section)
|
||||
{
|
||||
$this->section = $section;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Configuration[]
|
||||
*/
|
||||
public function getConfiguration(): array
|
||||
{
|
||||
return $this->configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Configuration[] $configuration
|
||||
* @return SystemConfiguration
|
||||
*/
|
||||
public function setConfiguration(array $configuration)
|
||||
{
|
||||
$this->configuration = $configuration;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
50
src/Form/SystemConfigurationForm.php
Normal file
50
src/Form/SystemConfigurationForm.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?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\Form\Model\SystemConfiguration;
|
||||
use App\Form\Type\SystemConfigurationType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/**
|
||||
* Defines the form used to edit one section within the system configuration.
|
||||
*/
|
||||
class SystemConfigurationForm extends AbstractType
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder->add('configuration', CollectionType::class, [
|
||||
'entry_type' => SystemConfigurationType::class,
|
||||
'entry_options' => ['label' => false],
|
||||
'allow_add' => false,
|
||||
'allow_delete' => false,
|
||||
'label' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => SystemConfiguration::class,
|
||||
'csrf_protection' => true,
|
||||
'csrf_field_name' => '_token',
|
||||
'csrf_token_id' => 'edit_user_preferences',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
namespace App\Form;
|
||||
|
||||
use App\Configuration\TimesheetConfiguration;
|
||||
use App\Entity\Timesheet;
|
||||
use App\Form\Type\ActivityType;
|
||||
use App\Form\Type\CustomerType;
|
||||
@@ -38,34 +39,31 @@ class TimesheetEditForm extends AbstractType
|
||||
* @var CustomerRepository
|
||||
*/
|
||||
private $customers;
|
||||
|
||||
/**
|
||||
* @var ProjectRepository
|
||||
*/
|
||||
private $projects;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $durationOnly = false;
|
||||
|
||||
/**
|
||||
* @var UserDateTimeFactory
|
||||
*/
|
||||
protected $dateTime;
|
||||
/**
|
||||
* @var TimesheetConfiguration
|
||||
*/
|
||||
private $configuration;
|
||||
|
||||
/**
|
||||
* @param CustomerRepository $customer
|
||||
* @param ProjectRepository $project
|
||||
* @param UserDateTimeFactory $dateTime
|
||||
* @param bool $durationOnly
|
||||
* @param TimesheetConfiguration $config
|
||||
*/
|
||||
public function __construct(CustomerRepository $customer, ProjectRepository $project, UserDateTimeFactory $dateTime, bool $durationOnly)
|
||||
public function __construct(CustomerRepository $customer, ProjectRepository $project, UserDateTimeFactory $dateTime, TimesheetConfiguration $config)
|
||||
{
|
||||
$this->customers = $customer;
|
||||
$this->projects = $project;
|
||||
$this->dateTime = $dateTime;
|
||||
$this->durationOnly = $durationOnly;
|
||||
$this->configuration = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,7 +104,7 @@ class TimesheetEditForm extends AbstractType
|
||||
$timezone = $begin->getTimezone()->getName();
|
||||
}
|
||||
|
||||
if (null === $end || !$options['duration_only']) {
|
||||
if (null === $end || !$this->configuration->isDurationOnly()) {
|
||||
$builder->add('begin', DateTimePickerType::class, [
|
||||
'label' => 'label.begin',
|
||||
'model_timezone' => $timezone,
|
||||
@@ -114,7 +112,7 @@ class TimesheetEditForm extends AbstractType
|
||||
]);
|
||||
}
|
||||
|
||||
if ($options['duration_only']) {
|
||||
if ($this->configuration->isDurationOnly()) {
|
||||
$builder->add('duration', DurationType::class, [
|
||||
'required' => false,
|
||||
'docu_chapter' => 'timesheet.html#duration-format',
|
||||
@@ -303,7 +301,6 @@ class TimesheetEditForm extends AbstractType
|
||||
'csrf_protection' => true,
|
||||
'csrf_field_name' => '_token',
|
||||
'csrf_token_id' => 'timesheet_edit',
|
||||
'duration_only' => $this->durationOnly,
|
||||
'include_user' => false,
|
||||
'include_exported' => false,
|
||||
'include_rate' => true,
|
||||
|
||||
@@ -71,6 +71,7 @@ class DateTimePickerType extends AbstractType
|
||||
if ($options['autofocus']) {
|
||||
$values['autofocus'] = 'autofocus';
|
||||
}
|
||||
|
||||
return $values;
|
||||
});
|
||||
}
|
||||
|
||||
75
src/Form/Type/SystemConfigurationType.php
Normal file
75
src/Form/Type/SystemConfigurationType.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?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\Type;
|
||||
|
||||
use App\Form\Model\Configuration;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Form\FormEvent;
|
||||
use Symfony\Component\Form\FormEvents;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/**
|
||||
* Custom form field type to edit a system configuration.
|
||||
*/
|
||||
class SystemConfigurationType extends AbstractType
|
||||
{
|
||||
/**
|
||||
* @param FormBuilderInterface $builder
|
||||
* @param array $options
|
||||
*/
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder->addEventListener(
|
||||
FormEvents::PRE_SET_DATA,
|
||||
function (FormEvent $event) {
|
||||
/** @var Configuration $preference */
|
||||
$preference = $event->getData();
|
||||
|
||||
if (!($preference instanceof Configuration)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// prevents unconfigured values from showing up in the form
|
||||
if ($preference->getType() === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$required = true;
|
||||
if (CheckboxType::class == $preference->getType()) {
|
||||
$required = false;
|
||||
}
|
||||
|
||||
$type = $preference->getType();
|
||||
if (!$preference->isEnabled()) {
|
||||
$type = HiddenType::class;
|
||||
}
|
||||
|
||||
$event->getForm()->add('value', $type, [
|
||||
'label' => 'label.' . ($preference->getLabel() ?? $preference->getName()),
|
||||
'constraints' => $preference->getConstraints(),
|
||||
'required' => $required,
|
||||
'disabled' => !$preference->isEnabled(),
|
||||
'translation_domain' => $preference->getTranslationDomain(),
|
||||
]);
|
||||
}
|
||||
);
|
||||
$builder->add('name', HiddenType::class);
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => Configuration::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user