[closing motive] add an hierarchy + admin section for closing motives

This commit is contained in:
Julien Fastré 2020-03-12 12:19:15 +01:00
parent ceb3b5e955
commit e59f58f461
26 changed files with 712 additions and 41 deletions

View File

@ -77,3 +77,5 @@ CRUD-init branch
- create CRUD
- add the ability to add alt names to persons
- [UI] set action button bottom of edit form according to crud template
- [closing motive] add an hierarchy for closing motives ;
- [closing motive] Add an admin section for closing motives ;

View File

@ -0,0 +1,34 @@
<?php
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\CRUD\Controller\CRUDController;
use Symfony\Component\HttpFoundation\Request;
/**
* Controller for closing motives
*
*/
class AdminClosingMotiveController extends CRUDController
{
protected function createEntity($action, Request $request): object
{
$entity = parent::createEntity($action, $request);
if ($request->query->has('parent_id')) {
$parentId = $request->query->getInt('parent_id');
$parent = $this->getDoctrine()->getManager()
->getRepository($this->getEntityClass())
->find($parentId);
if (NULL === $parent) {
throw $this->createNotFoundException('parent id not found');
}
$entity->setParent($parent);
}
return $entity;
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace Chill\PersonBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
class AdminController extends Controller
{
/**
*
*/
public function indexAction($_locale)
{
return $this->render('ChillPersonBundle:Admin:index.html.twig', array(
// ...
));
}
}

View File

@ -135,6 +135,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
$this->prependRoleHierarchy($container);
$this->prependHomepageWidget($container);
$this->prependDoctrineDQL($container);
$this->prependCruds($container);
$bundles = $container->getParameter('kernel.bundles');
//add ChillMain to assetic-enabled bundles
@ -240,4 +241,33 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
)
));
}
protected function prependCruds(ContainerBuilder $container)
{
$container->prependExtensionConfig('chill_main', [
'cruds' => [
[
'class' => \Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive::class,
'name' => 'closing_motive',
'base_path' => '/admin/closing-motive',
'form_class' => \Chill\PersonBundle\Form\ClosingMotiveType::class,
'controller' => \Chill\PersonBundle\Controller\AdminClosingMotiveController::class,
'actions' => [
'index' => [
'template' => '@ChillPerson/ClosingMotive/index.html.twig',
'role' => 'ROLE_ADMIN'
],
'new' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillPerson/ClosingMotive/new.html.twig',
],
'edit' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillPerson/ClosingMotive/edit.html.twig',
]
]
]
]
]);
}
}

View File

@ -2,7 +2,7 @@
/*
*
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
* Copyright (C) 2014-2020, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@ -20,6 +20,8 @@
namespace Chill\PersonBundle\Entity\AccompanyingPeriod;
use Doctrine\Common\Collections\Collection;
/**
* ClosingMotive give an explanation why we closed the Accompanying period
*/
@ -39,9 +41,32 @@ class ClosingMotive
*
* @var boolean
*/
private $active;
private $active = true;
/**
*
* @var self
*/
private $parent = null;
/**
* child Accompanying periods
*
* @var Collection
*/
private $children;
/**
*
* @var float
*/
private $ordering = 0.0;
public function __construct()
{
$this->children = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
@ -76,17 +101,104 @@ class ClosingMotive
return $this->name;
}
public function isActive()
public function isActive(): bool
{
return $this->active;
}
public function setActive($active)
public function setActive(bool $active)
{
$this->active = $active;
if ($this->active === FALSE) {
foreach ($this->getChildren() as $child) {
$child->setActive(FALSE);
}
}
return $this;
}
public function getParent()
{
return $this->parent;
}
public function getChildren(): Collection
{
return $this->children;
}
public function setParent(?ClosingMotive $parent): ClosingMotive
{
$this->parent = $parent;
if (NULL !== $parent) {
//$parent->addChildren($this);
}
return $this;
}
public function setChildren(Collection $children): ClosingMotive
{
$this->children = $children;
return $this;
}
public function addChildren(ClosingMotive $child): ClosingMotive
{
if ($this->children->contains($child)) {
return $this;
}
$this->children->add($child);
$child->setParent($this);
return $this;
}
public function removeChildren(ClosingMotive $child): ClosingMotive
{
if ($this->children->removeElement($child)) {
$child->setParent(null);
}
return $this;
}
public function getOrdering(): float
{
return $this->ordering;
}
public function setOrdering(float $ordering)
{
$this->ordering = $ordering;
return $this;
}
public function isChild(): bool
{
return $this->parent !== null;
}
public function isParent(): bool
{
return $this->children->count() > 0;
}
public function isLeaf(): bool
{
return $this->children->count() === 0;
}
public function hasParent(): bool
{
return $this->parent !== null;
}
}

View File

@ -14,8 +14,7 @@ use Symfony\Component\Form\Extension\Core\Type\DateType;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Chill\MainBundle\Form\Type\UserPickerType;
use Symfony\Component\Security\Core\Role\Role;
use Chill\PersonBundle\Form\Type\ClosingMotiveType;
use Chill\PersonBundle\Form\Type\ClosingMotivePickerType;
class AccompanyingPeriodType extends AbstractType
{
@ -72,7 +71,7 @@ class AccompanyingPeriodType extends AbstractType
) {
$form->add('closingDate', DateType::class, array('required' => true,
'widget' => 'single_text', 'format' => 'dd-MM-yyyy'));
$form->add('closingMotive', ClosingMotiveType::class);
$form->add('closingMotive', ClosingMotivePickerType::class);
}
});

View File

@ -0,0 +1,67 @@
<?php
/*
*
* Copyright (C) 2014-2020, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\PersonBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Chill\PersonBundle\Form\Type\ClosingMotivePickerType;
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
/**
*
*
*/
class ClosingMotiveType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TranslatableStringFormType::class, [
'label' => 'Nom'
])
->add('active', CheckboxType::class, [
'label' => 'Actif ?',
'required' => false
])
->add('ordering', NumberType::class, [
'label' => 'Ordre d\'apparition',
'required' => true,
'scale' => 5
])
->add('parent', ClosingMotivePickerType::class, [
'label' => 'Parent',
'required' => false,
'placeholder' => 'closing_motive.any parent',
'multiple' => false,
'only_leaf' => false
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefault('class', \Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive::class)
;
}
}

View File

@ -9,13 +9,15 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive;
use Chill\MainBundle\Templating\Entity\ChillEntityRenderExtension;
use Symfony\Component\OptionsResolver\Options;
use Chill\PersonBundle\Repository\ClosingMotiveRepository;
/**
* A type to add a closing motive
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ClosingMotiveType extends AbstractType
class ClosingMotivePickerType extends AbstractType
{
/**
@ -24,9 +26,26 @@ class ClosingMotiveType extends AbstractType
*/
protected $translatableStringHelper;
public function __construct(TranslatableStringHelper $translatableStringHelper)
{
/**
*
* @var ChillEntityRenderExtension
*/
protected $entityRenderExtension;
/**
*
* @var ClosingMotiveRepository
*/
protected $repository;
public function __construct(
TranslatableStringHelper $translatableStringHelper,
ChillEntityRenderExtension $chillEntityRenderExtension,
ClosingMotiveRepository $closingMotiveRepository
) {
$this->translatableStringHelper = $translatableStringHelper;
$this->entityRenderExtension = $chillEntityRenderExtension;
$this->repository = $closingMotiveRepository;
}
public function getBlockPrefix()
@ -46,11 +65,17 @@ class ClosingMotiveType extends AbstractType
'empty_data' => null,
'placeholder' => 'Choose a motive',
'choice_label' => function(ClosingMotive $cm) {
return $this->translatableStringHelper
->localize($cm->getName());
}
return $this->entityRenderExtension->renderString($cm);
},
'only_leaf' => true
)
);
$resolver
->setAllowedTypes('only_leaf', 'bool')
->setNormalizer('choices', function (Options $options) {
return $this->repository->getActiveClosingMotive($options['only_leaf']);
});
}
}

61
Menu/AdminMenuBuilder.php Normal file
View File

@ -0,0 +1,61 @@
<?php
/*
* Copyright (C) 2018 Champs-Libres <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\PersonBundle\Menu;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Knp\Menu\MenuItem;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
/**
*
*
*/
class AdminMenuBuilder implements LocalMenuBuilderInterface
{
/**
*
* @var AuthorizationCheckerInterface
*/
protected $authorizationChecker;
public function __construct(AuthorizationCheckerInterface $authorizationChecker)
{
$this->authorizationChecker = $authorizationChecker;
}
public function buildMenu($menuId, MenuItem $menu, array $parameters)
{
if (!$this->authorizationChecker->isGranted('ROLE_ADMIN')) {
return;
}
$menu->addChild('Person', [
'route' => 'chill_person_admin'
])
->setExtras([
'order' => 20
]);
}
public static function getMenuIds(): array
{
return [ 'admin_section' ];
}
}

View File

@ -0,0 +1,52 @@
<?php
/*
* Copyright (C) 2020 Champs-Libres <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\PersonBundle\Repository;
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\Query\ResultSetMappingBuilder;
/**
* Entity repository for closing motives
*
*/
class ClosingMotiveRepository extends \Doctrine\ORM\EntityRepository
{
public function getActiveClosingMotive(bool $onlyLeaf = true)
{
$rsm = new ResultSetMappingBuilder($this->getEntityManager());
$rsm->addRootEntityFromClassMetadata($this->getClassName(), 'cm');
$sql = "SELECT ".(string) $rsm."
FROM chill_person_closingmotive AS cm
WHERE
active IS TRUE ";
if ($onlyLeaf) {
$sql .= "AND cm.id NOT IN (
SELECT DISTINCT parent_id FROM chill_person_closingmotive WHERE parent_id IS NOT NULL
)";
}
$sql .= " ORDER BY cm.ordering ASC";
return $this->_em
->createNativeQuery($sql, $rsm)
->getResult()
;
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace Chill\PersonBundle\Repository;
/**
* PersonAltNameRepository
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class PersonAltNameRepository extends \Doctrine\ORM\EntityRepository
{
}

View File

@ -1,6 +1,7 @@
Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive:
table: chill_person_closingmotive
type: entity
repositoryClass: Chill\PersonBundle\Repository\ClosingMotiveRepository
id:
id:
type: integer
@ -11,3 +12,15 @@ Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive:
type: json_array
active:
type: boolean
ordering:
type: float
options:
default: 0.0
oneToMany:
children:
targetEntity: Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive
mappedBy: parent
manyToOne:
parent:
targetEntity: Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive
inversedBy: children

View File

@ -83,4 +83,8 @@ chill_person_timeline:
menus:
person:
order: 60
label: Timeline
label: Timeline
chill_person_admin:
path: "/{_locale}/admin/person"
defaults: { _controller: ChillPersonBundle:Admin:index }

View File

@ -15,3 +15,5 @@ services:
Chill\PersonBundle\Controller\AccompanyingPeriodController:
arguments:
$eventDispatcher: '@Symfony\Component\EventDispatcher\EventDispatcherInterface'
Chill\PersonBundle\Controller\AdminController: ~

View File

@ -22,9 +22,12 @@ services:
deprecated: true
chill.person.accompanying_period_closing_motive:
class: Chill\PersonBundle\Form\Type\ClosingMotiveType
class: Chill\PersonBundle\Form\Type\ClosingMotivePickerType
arguments:
- "@chill.main.helper.translatable_string"
$translatableStringHelper: '@Chill\MainBundle\Templating\TranslatableStringHelper'
$chillEntityRenderExtension: '@Chill\MainBundle\Templating\Entity\ChillEntityRenderExtension'
$closingMotiveRepository: '@Chill\PersonBundle\Repository\ClosingMotiveRepository'
tags:
- { name: form.type, alias: closing_motive }

View File

@ -5,6 +5,12 @@ services:
tags:
- { name: 'chill.menu_builder' }
Chill\PersonBundle\Menu\AdminMenuBuilder:
arguments:
$authorizationChecker: '@Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface'
tags:
- { name: 'chill.menu_builder' }
Chill\PersonBundle\Menu\PersonMenuBuilder:
arguments:
$showAccompanyingPeriod: '%chill_person.accompanying_period%'

View File

@ -11,3 +11,11 @@ services:
factory: ['@doctrine.orm.entity_manager', getRepository]
arguments:
- 'Chill\PersonBundle\Entity\Person'
Chill\PersonBundle\Repository\ClosingMotiveRepository:
class: Chill\PersonBundle\Repository\ClosingMotiveRepository
factory: ['@doctrine.orm.entity_manager', getRepository]
arguments:
- 'Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive'
tag:
- { name: doctrine.repository_service }

View File

@ -4,3 +4,9 @@ services:
$configAltNamesHelper: '@Chill\PersonBundle\Config\ConfigPersonAltNamesHelper'
tags:
- 'chill.render_entity'
Chill\PersonBundle\Templating\Entity\ClosingMotiveRender:
arguments:
$translatableStringHelper: '@Chill\MainBundle\Templating\TranslatableStringHelper'
tags:
- 'chill.render_entity'

View File

@ -125,8 +125,8 @@ Any accompanying periods are open: Aucune période d'accompagnement ouverte
An accompanying period is open: Une période d'accompagnement est ouverte
Accompanying period list: Périodes d'accompagnement
Choose a motive: Motif de fermeture
Re-open accompanying period: Ré-ouvrir la période d'accompagnement
Re-Open a period: Ré-ouvrir une période d'accompagnement
Re-open accompanying period: Ré-ouvrir
Re-Open a period: Ré-ouvrir
Are you sure you want to re-open this period ?: Êtes-vous sûr de vouloir ré-ouvrir cette période d'accompagnement ?
'The period has been re-opened': La période d'accompagnement a été ré-ouverte.
Pediod closing form is not valid: Le formulaire n'est pas valide
@ -221,3 +221,31 @@ Calculate age in relation to this date: Calculer l'âge par rapport à cette dat
Group people by country of birth: Aggréger les personnes par pays de naissance
Similar persons: Personnes similaires
crud:
closing_motive:
index:
title: Liste des motifs de clotûre
add_new: Ajouter un nouveau
title_new: Nouveau motif de clotûre
title_edit: Modifier le motif de clotûre
# specific to closing motive
closing_motive:
any parent: Aucun parent
new child: Nouvel enfant
Configuration of person bundle: Configuration du module "Personnes"
person_admin:
What would you like to configure ?: Que souhaitez-vous configurer ?
closing motives list: Liste des motifs de clotûre
closing motive explanation: >
Les motifs de clotûre donnent des indications sur la fermeture
d'une période d'accompagnement.
accompanying_period:
dates: Période
dates_from_%opening_date%: Ouvert depuis le %opening_date%
dates_from_%opening_date%_to_%closing_date%: Ouvert du %opening_date% au %closing_date%

View File

@ -8,10 +8,9 @@
<table class="rounded">
<thead>
<tr>
<th class="chill-red">{{ 'Opening date'|trans }}</th>
<th class="chill-green">{{ 'Closing date'|trans }}</th>
<th class="chill-red">{{ 'accompanying_period.dates'|trans }}</th>
{% if chill_accompanying_periods.fields.user == 'visible' %}
<th class="chill-green">{{ 'Accompanying user'|trans }}</th>
<th class="chill-blue">{{ 'Accompanying user'|trans }}</th>
{% endif %}
<th class="chill-orange">{{ 'Remark'|trans }}</th>
<th>&nbsp;</th>
@ -21,14 +20,17 @@
<tbody>
{% for accompanying_period in accompanying_periods %}
<tr>
<td>{{ accompanying_period.openingDate|localizeddate('long', 'none', app.request.locale) }}</td>
<td>{% spaceless %}
{% if accompanying_period.isOpen %}
{{ 'Period opened'|trans }}
<td>
{% if accompanying_period.isOpen == false %}
{{ 'accompanying_period.dates_from_%opening_date%'|trans({ '%opening_date%': accompanying_period.openingDate|localizeddate('long', 'none') } ) }}
{% else %}
{{ accompanying_period.closingDate|localizeddate('long', 'none', app.request.locale) }}
{{ 'accompanying_period.dates_from_%opening_date%_to_%closing_date%'|trans({
'%opening_date%': accompanying_period.openingDate|localizeddate('long', 'none'),
'%closing_date%': accompanying_period.closingDate|localizeddate('long', 'none')}
) }}
<div>{{ accompanying_period.closingMotive|chill_entity_render_box }}</div>
{% endif %}
{% endspaceless %}</td>
</td>
{% if chill_accompanying_periods.fields.user == 'visible' %}
<td>
{% if accompanying_period.user %}
@ -39,13 +41,7 @@
</td>
{% endif %}
<td>
{% if accompanying_period.remark is empty %}
<p class="chill-no-data-statement">{{ 'No remark'|trans }}</p>
{% else %}
<blockquote class="chill-user-quote">
{{ accompanying_period.remark|nl2br }}
</blockquote>
{% endif %}
{{ accompanying_period.remark|chill_print_or_message('No remark', 'blockquote') }}
</td>
<td>
<ul class="record_actions">
@ -82,14 +78,15 @@
</a>
</li>
<li>
<a href="{{ path ('chill_person_accompanying_period_create', {'person_id' : person.id } ) }}" class="sc-button bt-create">
{{ 'Add an accompanying period in the past'|trans }}
<a href="{{ path ('chill_person_accompanying_period_create', {'person_id' : person.id } ) }}" class="sc-button bt-create has-hidden">
<span class="show-on-hover">{{ 'Add an accompanying period in the past'|trans }}</span>
</a>
</li>
{% if person.isOpen == false %}
<li>
<a href="{{ path('chill_person_accompanying_period_open', {'person_id' : person.id} ) }}" class="sc-button bt-create change-icon">
<i class="fa fa-unlock" aria-hidden="true"></i>{{'Begin a new accompanying period'|trans }}
<a href="{{ path('chill_person_accompanying_period_open', {'person_id' : person.id} ) }}" class="sc-button bt-create change-icon has-hidden">
<i class="fa fa-unlock" aria-hidden="true"></i>
<span class="show-on-hover">{{'Begin a new accompanying period'|trans }}</span>
</a>
</li>
{% endif %}

View File

@ -0,0 +1,44 @@
{#
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
<info@champs-libres.coop> / <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
#}
{% extends "ChillMainBundle::Admin/layoutWithVerticalMenu.html.twig" %}
{% block vertical_menu_content %}
{{ chill_menu('admin_person') }}
{% endblock %}
{% block admin_content %}
<div class="grid-12 centered">
<h1>{{ 'Configuration of person bundle' |trans }}</h1>
<p>{{ 'person_admin.What would you like to configure ?'|trans }}</p>
<ul>
<li>
<p>
<a href="{{ path('chill_crud_closing_motive_index') }}">
<strong>{{ 'person_admin.closing motives list'|trans }}</strong>
</a>
</p>
<p>{{ 'person_admin.closing motive explanation'|trans }}</p>
</li>
</ul>
</div>
{% endblock %}

View File

@ -0,0 +1,11 @@
{% extends '@ChillMain/Admin/layout.html.twig' %}
{% block title %}
{% include('@ChillMain/CRUD/_edit_title.html.twig') %}
{% endblock %}
{% block admin_content %}
{% embed '@ChillMain/CRUD/_edit_content.html.twig' %}
{% block content_form_actions_view %}{% endblock %}
{% endembed %}
{% endblock %}

View File

@ -0,0 +1,32 @@
{% extends '@ChillMain/Admin/layout.html.twig' %}
{% block admin_content %}
{% embed '@ChillMain/CRUD/_index.html.twig' %}
{% block table_entities_thead_tr %}
<th>{{ 'Ordering'|trans }}</th>
<th>{{ 'Label'|trans }}</th>
<th>{{ 'Active'|trans }}</th>
<th>&nbsp;</th>
{% endblock %}
{% block table_entities_tbody %}
{% for entity in entities %}
<tr>
<td>{{ entity.ordering }}</td>
<td>{{ entity|chill_entity_render_box }}</td>
<td>{{ entity.active }}</td>
<td>
<ul class="record_actions">
<li>
<a href="{{ chill_path_add_return_path('chill_crud_closing_motive_edit', { 'id': entity.id }) }}" class="sc-button bt-edit"></a>
</li>
<li>
<a href="{{ chill_path_add_return_path('chill_crud_closing_motive_new', { 'parent_id': entity.id } ) }}" class="sc-button bt-new">{{ 'closing_motive.new child'|trans }}</a>
</li>
</ul>
</td>
</tr>
{% endfor %}
{% endblock %}
{% endembed %}
{% endblock %}

View File

@ -0,0 +1,11 @@
{% extends '@ChillMain/Admin/layout.html.twig' %}
{% block title %}
{% include('@ChillMain/CRUD/_new_title.html.twig') %}
{% endblock %}
{% block admin_content %}
{% embed '@ChillMain/CRUD/_new_content.html.twig' %}
{% block content_form_actions_save_and_show %}{% endblock %}
{% endembed %}
{% endblock %}

View File

@ -0,0 +1,75 @@
<?php
namespace Chill\PersonBundle\Templating\Entity;
use Chill\MainBundle\Templating\Entity\AbstractChillEntityRender;
use Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive;
use Chill\MainBundle\Templating\TranslatableStringHelper;
/**
* Render closing motive
*
*/
class ClosingMotiveRender extends AbstractChillEntityRender
{
private CONST SEPARATOR = ' > ';
/**
*
* @var TranslatableStringHelper
*/
private $translatableStringHelper;
public function __construct(TranslatableStringHelper $translatableStringHelper)
{
$this->translatableStringHelper = $translatableStringHelper;
}
public function renderBox($entity, array $options): string
{
return
$this->getDefaultOpeningBox('closing-motive').
$this->renderString($entity, $options).
$this->getDefaultClosingBox()
;
}
/**
*
* @param ClosingMotive $entity
* @param array $options
* @return string
*/
public function renderString($entity, array $options): string
{
return $this->renderStringRecursive($entity,
'', //$this->translatableStringHelper->localize($entity->getName()),
$options);
}
protected function renderStringRecursive(ClosingMotive $motive, $existing, array $options)
{
$newExisting = $this->translatableStringHelper->localize($motive->getName());
if ($motive->hasParent()) {
if (!empty($existing)) {
$newExisting = $newExisting.self::SEPARATOR.$existing;
}
return $this->renderStringRecursive($motive->getParent(), $newExisting,
$options);
} else {
if (!empty($existing)) {
return $newExisting.self::SEPARATOR.$existing;
} else {
return $newExisting;
}
}
}
public function supports($entity, array $options): bool
{
return $entity instanceof ClosingMotive;
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace Chill\PersonBundle\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class AdminControllerTest extends WebTestCase
{
public function testIndex()
{
$client = static::createClient();
$crawler = $client->request('GET', '/{_locale}/admin/person');
}
}