added database driven system configurations with admin screen (#647)

This commit is contained in:
Kevin Papst
2019-03-22 20:58:38 +01:00
committed by GitHub
parent e990ae4800
commit 13d9f8f3f7
142 changed files with 2262 additions and 64727 deletions

View 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;
}
}

View 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;
}
}

View 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',
]);
}
}

View File

@@ -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,

View File

@@ -71,6 +71,7 @@ class DateTimePickerType extends AbstractType
if ($options['autofocus']) {
$values['autofocus'] = 'autofocus';
}
return $values;
});
}

View 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,
]);
}
}