Added UserSelectType and allow to set owner of a storage location

This commit is contained in:
Jan Böhmer 2023-04-02 21:50:22 +02:00
parent f101e1b184
commit 5f5541ca12
8 changed files with 142 additions and 36 deletions

View file

@ -24,7 +24,9 @@ namespace App\Form\AdminPages;
use App\Entity\Base\AbstractNamedDBElement; use App\Entity\Base\AbstractNamedDBElement;
use App\Entity\Parts\MeasurementUnit; use App\Entity\Parts\MeasurementUnit;
use App\Entity\UserSystem\User;
use App\Form\Type\StructuralEntityType; use App\Form\Type\StructuralEntityType;
use App\Form\Type\UserSelectType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
@ -63,5 +65,16 @@ class StorelocationAdminForm extends BaseEntityAdminForm
'disable_not_selectable' => true, 'disable_not_selectable' => true,
'disabled' => !$this->security->isGranted($is_new ? 'create' : 'edit', $entity), 'disabled' => !$this->security->isGranted($is_new ? 'create' : 'edit', $entity),
]); ]);
$builder->add('owner', UserSelectType::class, [
'required' => false,
'label' => 'storelocation.owner.label',
'disabled' => !$this->security->isGranted($is_new ? 'create' : 'edit', $entity),
]);
$builder->add('part_owner_must_match', CheckboxType::class, [
'required' => false,
'label' => 'storelocation.part_owner_must_match.label',
'disabled' => !$this->security->isGranted($is_new ? 'create' : 'edit', $entity),
]);
} }
} }

View file

@ -21,8 +21,13 @@
namespace App\Form\Type\Helper; namespace App\Form\Type\Helper;
use App\Entity\Attachments\AttachmentType; use App\Entity\Attachments\AttachmentType;
use App\Entity\Base\AbstractDBElement;
use App\Entity\Base\AbstractNamedDBElement;
use App\Entity\Base\AbstractStructuralDBElement; use App\Entity\Base\AbstractStructuralDBElement;
use App\Entity\Contracts\HasMasterAttachmentInterface;
use App\Entity\PriceInformations\Currency; use App\Entity\PriceInformations\Currency;
use App\Entity\UserSystem\User;
use App\Form\Type\MasterPictureAttachmentType;
use App\Services\Attachments\AttachmentURLGenerator; use App\Services\Attachments\AttachmentURLGenerator;
use RuntimeException; use RuntimeException;
use Symfony\Component\Intl\Currencies; use Symfony\Component\Intl\Currencies;
@ -43,37 +48,49 @@ class StructuralEntityChoiceHelper
/** /**
* Generates the choice attributes for the given AbstractStructuralDBElement. * Generates the choice attributes for the given AbstractStructuralDBElement.
* @param AbstractStructuralDBElement $choice * @param AbstractNamedDBElement $choice
* @param Options|array $options * @param Options|array $options
* @return array|string[] * @return array|string[]
*/ */
public function generateChoiceAttr(AbstractStructuralDBElement $choice, $options): array public function generateChoiceAttr(AbstractNamedDBElement $choice, $options): array
{ {
$tmp = []; $tmp = [
'data-level' => 0,
//Disable attribute if the choice is marked as not selectable 'data-path' => $choice->getName(),
if (($options['disable_not_selectable'] ?? false) && $choice->isNotSelectable()) {
$tmp += ['disabled' => 'disabled'];
}
if ($choice instanceof AttachmentType) {
$tmp += ['data-filetype_filter' => $choice->getFiletypeFilter()];
}
$level = $choice->getLevel();
/** @var AbstractStructuralDBElement|null $parent */
$parent = $options['subentities_of'] ?? null;
if (null !== $parent) {
$level -= $parent->getLevel() - 1;
}
$tmp += [
'data-level' => $level,
'data-parent' => $choice->getParent() ? $choice->getParent()->getFullPath() : null,
'data-path' => $choice->getFullPath('->'),
'data-image' => $choice->getMasterPictureAttachment() ? $this->attachmentURLGenerator->getThumbnailURL($choice->getMasterPictureAttachment(), 'thumbnail_xs') : null,
]; ];
if ($choice instanceof AbstractStructuralDBElement) {
//Disable attribute if the choice is marked as not selectable
if (($options['disable_not_selectable'] ?? false) && $choice->isNotSelectable()) {
$tmp += ['disabled' => 'disabled'];
}
if ($choice instanceof AttachmentType) {
$tmp += ['data-filetype_filter' => $choice->getFiletypeFilter()];
}
$level = $choice->getLevel();
/** @var AbstractStructuralDBElement|null $parent */
$parent = $options['subentities_of'] ?? null;
if (null !== $parent) {
$level -= $parent->getLevel() - 1;
}
$tmp += [
'data-level' => $level,
'data-parent' => $choice->getParent() ? $choice->getParent()->getFullPath() : null,
'data-path' => $choice->getFullPath('->'),
];
}
if ($choice instanceof HasMasterAttachmentInterface) {
$tmp['data-image'] = $choice->getMasterPictureAttachment() ?
$this->attachmentURLGenerator->getThumbnailURL($choice->getMasterPictureAttachment(),
'thumbnail_xs')
: null
;
}
if ($choice instanceof AttachmentType && !empty($choice->getFiletypeFilter())) { if ($choice instanceof AttachmentType && !empty($choice->getFiletypeFilter())) {
$tmp += ['data-filetype_filter' => $choice->getFiletypeFilter()]; $tmp += ['data-filetype_filter' => $choice->getFiletypeFilter()];
} }
@ -112,20 +129,20 @@ class StructuralEntityChoiceHelper
/** /**
* Returns the choice label for the given AbstractStructuralDBElement. * Returns the choice label for the given AbstractStructuralDBElement.
* @param AbstractStructuralDBElement $choice * @param AbstractNamedDBElement $choice
* @return string * @return string
*/ */
public function generateChoiceLabel(AbstractStructuralDBElement $choice): string public function generateChoiceLabel(AbstractNamedDBElement $choice): string
{ {
return $choice->getName(); return $choice->getName();
} }
/** /**
* Returns the choice value for the given AbstractStructuralDBElement. * Returns the choice value for the given AbstractStructuralDBElement.
* @param AbstractStructuralDBElement|null $element * @param AbstractNamedDBElement|null $element
* @return string|int|null * @return string|int|null
*/ */
public function generateChoiceValue(?AbstractStructuralDBElement $element) public function generateChoiceValue(?AbstractNamedDBElement $element)
{ {
if ($element === null) { if ($element === null) {
return null; return null;
@ -138,18 +155,21 @@ class StructuralEntityChoiceHelper
* So please do not change this! * So please do not change this!
*/ */
if ($element->getID() === null) { if ($element->getID() === null) {
//Must be the same as the separator in the choice_loader, otherwise this will not work! if ($element instanceof AbstractStructuralDBElement) {
return $element->getFullPath('->'); //Must be the same as the separator in the choice_loader, otherwise this will not work!
return $element->getFullPath('->');
}
return $element->getName();
} }
return $element->getID(); return $element->getID();
} }
/** /**
* @param AbstractStructuralDBElement $element * @param AbstractDBElement $element
* @return string|null * @return string|null
*/ */
public function generateGroupBy(AbstractStructuralDBElement $element): ?string public function generateGroupBy(AbstractDBElement $element): ?string
{ {
//Show entities that are not added to DB yet separately from other entities //Show entities that are not added to DB yet separately from other entities
if ($element->getID() === null) { if ($element->getID() === null) {

View file

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace App\Form\Type; namespace App\Form\Type;
use App\Entity\Attachments\AttachmentType; use App\Entity\Attachments\AttachmentType;
use App\Entity\Base\AbstractNamedDBElement;
use App\Entity\Base\AbstractStructuralDBElement; use App\Entity\Base\AbstractStructuralDBElement;
use App\Form\Type\Helper\StructuralEntityChoiceHelper; use App\Form\Type\Helper\StructuralEntityChoiceHelper;
use App\Form\Type\Helper\StructuralEntityChoiceLoader; use App\Form\Type\Helper\StructuralEntityChoiceLoader;
@ -105,7 +106,7 @@ class StructuralEntityType extends AbstractType
'show_fullpath_in_subtext' => true, //When this is enabled, the full path will be shown in subtext 'show_fullpath_in_subtext' => true, //When this is enabled, the full path will be shown in subtext
'subentities_of' => null, //Only show entities with the given parent class 'subentities_of' => null, //Only show entities with the given parent class
'disable_not_selectable' => false, //Disable entries with not selectable property 'disable_not_selectable' => false, //Disable entries with not selectable property
'choice_value' => function (?AbstractStructuralDBElement $element) { 'choice_value' => function (?AbstractNamedDBElement $element) {
return $this->choice_helper->generateChoiceValue($element); return $this->choice_helper->generateChoiceValue($element);
}, //Use the element id as option value and for comparing items }, //Use the element id as option value and for comparing items
'choice_loader' => function (Options $options) { 'choice_loader' => function (Options $options) {
@ -121,7 +122,7 @@ class StructuralEntityType extends AbstractType
return $this->choice_helper->generateChoiceAttr($choice, $options); return $this->choice_helper->generateChoiceAttr($choice, $options);
}; };
}, },
'group_by' => function (AbstractStructuralDBElement $element) { 'group_by' => function (AbstractNamedDBElement $element) {
return $this->choice_helper->generateGroupBy($element); return $this->choice_helper->generateGroupBy($element);
}, },
'choice_translation_domain' => false, //Don't translate the entity names 'choice_translation_domain' => false, //Don't translate the entity names

View file

@ -0,0 +1,47 @@
<?php
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
*
* 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 <https://www.gnu.org/licenses/>.
*/
namespace App\Form\Type;
use App\Entity\UserSystem\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
class UserSelectType extends AbstractType
{
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'class' => User::class,
'choice_label' => function (Options $options) {
return function (User $choice, $key, $value) {
return $choice->getFullName(true);
};
},
]);
}
public function getParent()
{
return StructuralEntityType::class;
}
}

View file

@ -59,4 +59,14 @@ class NamedDBElementRepository extends DBElementRepository
return $result; return $result;
} }
/**
* Returns the list of all nodes to use in a select box.
* @return AbstractNamedDBElement[]
*/
public function toNodesList(): array
{
//All nodes are sorted by name
return $this->findBy([], ['name' => 'ASC']);
}
} }

View file

@ -46,7 +46,7 @@ class NodesListBuilder
} }
/** /**
* Gets a flattened hierachical tree. Useful for generating option lists. * Gets a flattened hierarchical tree. Useful for generating option lists.
* In difference to the Repository Function, the results here are cached. * In difference to the Repository Function, the results here are cached.
* *
* @param string $class_name the class name of the entity you want to retrieve * @param string $class_name the class name of the entity you want to retrieve
@ -66,6 +66,7 @@ class NodesListBuilder
$item->tag(['groups', 'tree_list', $this->keyGenerator->generateKey(), $secure_class_name]); $item->tag(['groups', 'tree_list', $this->keyGenerator->generateKey(), $secure_class_name]);
/** @var StructuralDBElementRepository $repo */ /** @var StructuralDBElementRepository $repo */
$repo = $this->em->getRepository($class_name); $repo = $this->em->getRepository($class_name);
return $repo->toNodesList($parent); return $repo->toNodesList($parent);
}); });
} }

View file

@ -25,6 +25,8 @@
{{ form_row(form.is_full) }} {{ form_row(form.is_full) }}
{{ form_row(form.limit_to_existing_parts) }} {{ form_row(form.limit_to_existing_parts) }}
{{ form_row(form.only_single_part) }} {{ form_row(form.only_single_part) }}
{{ form_row(form.owner) }}
{{ form_row(form.part_owner_must_match) }}
</div> </div>
{% endblock %} {% endblock %}

View file

@ -11205,5 +11205,17 @@ Element 3</target>
<target>About Me</target> <target>About Me</target>
</segment> </segment>
</unit> </unit>
<unit id="WsHXARp" name="storelocation.owner.label">
<segment>
<source>storelocation.owner.label</source>
<target>Owner</target>
</segment>
</unit>
<unit id="VQ97Dh0" name="storelocation.part_owner_must_match.label">
<segment>
<source>storelocation.part_owner_must_match.label</source>
<target>Part Lot owner must match storage location owner</target>
</segment>
</unit>
</file> </file>
</xliff> </xliff>