2019-04-20 20:39:06 +02:00
< ? php
2020-02-22 18:14:36 +01:00
/**
* This file is part of Part - DB ( https :// github . com / Part - DB / Part - DB - symfony ) .
*
2022-11-29 22:28:53 +01:00
* Copyright ( C ) 2019 - 2022 Jan Böhmer ( https :// github . com / jbtronics )
2020-02-22 18:14:36 +01:00
*
* 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 />.
*/
2020-01-05 15:46:58 +01:00
declare ( strict_types = 1 );
2019-04-28 13:10:11 +02:00
namespace App\Controller\AdminPages ;
2019-04-20 20:39:06 +02:00
2020-03-04 21:09:01 +01:00
use App\DataTables\LogDataTable ;
2020-10-03 13:31:05 +02:00
use App\Entity\Attachments\Attachment ;
2024-03-10 01:19:52 +01:00
use App\Entity\Attachments\AttachmentContainingDBElement ;
2024-03-03 18:52:06 +01:00
use App\Entity\Attachments\AttachmentUpload ;
2020-06-07 21:11:09 +02:00
use App\Entity\Base\AbstractDBElement ;
2020-02-01 19:48:07 +01:00
use App\Entity\Base\AbstractNamedDBElement ;
2020-05-17 21:52:47 +02:00
use App\Entity\Base\AbstractPartsContainingDBElement ;
2020-02-01 19:48:07 +01:00
use App\Entity\Base\AbstractStructuralDBElement ;
2020-05-16 20:53:35 +02:00
use App\Entity\Base\PartsContainingRepositoryInterface ;
2023-06-13 20:24:54 +02:00
use App\Entity\LabelSystem\LabelProcessMode ;
2020-05-01 21:19:13 +02:00
use App\Entity\LabelSystem\LabelProfile ;
2020-10-03 13:31:05 +02:00
use App\Entity\Parameters\AbstractParameter ;
2019-10-19 18:50:17 +02:00
use App\Exceptions\AttachmentDownloadException ;
2024-08-23 22:15:29 +02:00
use App\Exceptions\TwigModeException ;
2019-08-12 22:41:58 +02:00
use App\Form\AdminPages\ImportType ;
use App\Form\AdminPages\MassCreationForm ;
2020-05-16 20:53:35 +02:00
use App\Repository\AbstractPartsContainingRepository ;
2019-10-19 17:13:13 +02:00
use App\Services\Attachments\AttachmentSubmitHandler ;
2022-12-18 17:28:42 +01:00
use App\Services\ImportExportSystem\EntityExporter ;
use App\Services\ImportExportSystem\EntityImporter ;
2023-04-03 22:48:52 +02:00
use App\Services\LabelSystem\LabelExampleElementsGenerator ;
2020-05-01 21:19:13 +02:00
use App\Services\LabelSystem\LabelGenerator ;
2020-02-23 00:44:52 +01:00
use App\Services\LogSystem\EventCommentHelper ;
2020-03-04 21:09:01 +01:00
use App\Services\LogSystem\HistoryHelper ;
use App\Services\LogSystem\TimeTravel ;
2022-12-18 17:28:42 +01:00
use App\Services\Trees\StructuralElementRecursionHelper ;
2022-08-14 19:32:53 +02:00
use DateTime ;
2019-04-20 20:39:06 +02:00
use Doctrine\ORM\EntityManagerInterface ;
2020-01-05 22:49:00 +01:00
use InvalidArgumentException ;
2020-03-04 21:09:01 +01:00
use Omines\DataTablesBundle\DataTableFactory ;
2019-04-20 20:39:06 +02:00
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController ;
2020-04-03 18:27:47 +02:00
use Symfony\Component\EventDispatcher\EventDispatcherInterface ;
2024-08-23 22:15:29 +02:00
use Symfony\Component\Form\FormError ;
2019-09-24 18:28:35 +02:00
use Symfony\Component\Form\FormInterface ;
2019-04-20 20:39:06 +02:00
use Symfony\Component\HttpFoundation\File\UploadedFile ;
2020-02-02 14:05:36 +01:00
use Symfony\Component\HttpFoundation\RedirectResponse ;
2019-04-20 20:39:06 +02:00
use Symfony\Component\HttpFoundation\Request ;
2020-02-02 14:05:36 +01:00
use Symfony\Component\HttpFoundation\Response ;
2021-10-02 20:41:14 +02:00
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface ;
2023-03-12 21:43:40 +01:00
use Symfony\Component\Serializer\Exception\UnexpectedValueException ;
2024-06-22 22:55:15 +02:00
use Symfony\Component\Validator\ConstraintViolationInterface ;
use Symfony\Component\Validator\ConstraintViolationListInterface ;
2019-08-25 18:15:58 +02:00
use Symfony\Contracts\Translation\TranslatorInterface ;
2019-04-20 20:39:06 +02:00
2022-09-21 13:05:52 +02:00
use function Symfony\Component\Translation\t ;
2019-04-20 20:39:06 +02:00
abstract class BaseAdminController extends AbstractController
{
2023-02-03 23:43:44 +01:00
protected string $entity_class = '' ;
protected string $form_class = '' ;
protected string $twig_template = '' ;
protected string $route_base = '' ;
protected string $attachment_class = '' ;
protected ? string $parameter_class = '' ;
2024-03-03 20:33:24 +01:00
2023-06-11 14:15:46 +02:00
public function __construct ( protected TranslatorInterface $translator , protected UserPasswordHasherInterface $passwordEncoder ,
protected AttachmentSubmitHandler $attachmentSubmitHandler ,
protected EventCommentHelper $commentHelper , protected HistoryHelper $historyHelper , protected TimeTravel $timeTravel ,
2024-06-22 00:44:59 +02:00
protected DataTableFactory $dataTableFactory , protected EventDispatcherInterface $eventDispatcher , protected LabelExampleElementsGenerator $barcodeExampleGenerator ,
2023-06-11 14:15:46 +02:00
protected LabelGenerator $labelGenerator , protected EntityManagerInterface $entityManager )
2019-04-20 20:39:06 +02:00
{
2019-11-09 00:47:20 +01:00
if ( '' === $this -> entity_class || '' === $this -> form_class || '' === $this -> twig_template || '' === $this -> route_base ) {
2020-01-05 22:49:00 +01:00
throw new InvalidArgumentException ( 'You have to override the $entity_class, $form_class, $route_base and $twig_template value in your subclasss!' );
2019-04-20 20:39:06 +02:00
}
2019-08-25 18:15:58 +02:00
2020-10-03 13:31:05 +02:00
if ( '' === $this -> attachment_class || ! is_a ( $this -> attachment_class , Attachment :: class , true )) {
throw new InvalidArgumentException ( 'You have to override the $attachment_class value with a valid Attachment class in your subclass!' );
2019-09-24 18:28:35 +02:00
}
2023-02-03 23:43:44 +01:00
if ( '' === $this -> parameter_class || ( $this -> parameter_class && ! is_a ( $this -> parameter_class , AbstractParameter :: class , true ))) {
2020-10-03 13:31:05 +02:00
throw new InvalidArgumentException ( 'You have to override the $parameter_class value with a valid Parameter class in your subclass!' );
2020-03-24 21:49:09 +01:00
}
2019-04-20 20:39:06 +02:00
}
2022-08-14 19:32:53 +02:00
protected function revertElementIfNeeded ( AbstractDBElement $entity , ? string $timestamp ) : ? DateTime
2019-04-20 20:39:06 +02:00
{
2020-03-15 13:56:31 +01:00
if ( null !== $timestamp ) {
2020-03-07 21:36:33 +01:00
$this -> denyAccessUnlessGranted ( 'show_history' , $entity );
2020-03-04 21:54:03 +01:00
//If the timestamp only contains numbers interpret it as unix timestamp
if ( ctype_digit ( $timestamp )) {
2022-08-14 19:32:53 +02:00
$timeTravel_timestamp = new DateTime ();
2020-03-04 21:54:03 +01:00
$timeTravel_timestamp -> setTimestamp (( int ) $timestamp );
} else { //Try to parse it via DateTime
2022-08-14 19:32:53 +02:00
$timeTravel_timestamp = new DateTime ( $timestamp );
2020-03-04 21:54:03 +01:00
}
$this -> timeTravel -> revertEntityToTimestamp ( $entity , $timeTravel_timestamp );
2020-06-07 21:11:09 +02:00
return $timeTravel_timestamp ;
2020-03-04 21:54:03 +01:00
}
2020-08-21 21:36:22 +02:00
2020-06-07 21:11:09 +02:00
return null ;
}
/**
* Perform some additional actions , when the form was valid , but before the entity is saved .
2020-08-21 21:36:22 +02:00
*
* @ return bool return true , to save entity normally , return false , to abort saving
2020-06-07 21:11:09 +02:00
*/
protected function additionalActionEdit ( FormInterface $form , AbstractNamedDBElement $entity ) : bool
{
return true ;
}
protected function _edit ( AbstractNamedDBElement $entity , Request $request , EntityManagerInterface $em , ? string $timestamp = null ) : Response
{
$this -> denyAccessUnlessGranted ( 'read' , $entity );
$timeTravel_timestamp = $this -> revertElementIfNeeded ( $entity , $timestamp );
2020-03-15 13:56:31 +01:00
if ( $this -> isGranted ( 'show_history' , $entity )) {
2020-03-07 20:49:52 +01:00
$table = $this -> dataTableFactory -> createFromType (
LogDataTable :: class ,
[
'filter_elements' => $this -> historyHelper -> getAssociatedElements ( $entity ),
2020-03-15 13:56:31 +01:00
'mode' => 'element_history' ,
2020-03-07 20:49:52 +01:00
],
[ 'pageLength' => 10 ]
)
-> handleRequest ( $request );
if ( $table -> isCallback ()) {
return $table -> getResponse ();
}
} else {
$table = null ;
2020-03-04 21:09:01 +01:00
}
2020-05-10 21:39:31 +02:00
$form_options = [
2020-03-04 21:54:03 +01:00
'attachment_class' => $this -> attachment_class ,
2020-03-24 21:49:09 +01:00
'parameter_class' => $this -> parameter_class ,
2023-06-11 14:15:46 +02:00
'disabled' => $timeTravel_timestamp instanceof \DateTime ,
2020-05-07 22:29:45 +02:00
];
//Disable editing of options, if user is not allowed to use twig...
if (
$entity instanceof LabelProfile
2023-06-13 20:24:54 +02:00
&& LabelProcessMode :: TWIG === $entity -> getOptions () -> getProcessMode ()
2020-08-21 21:36:22 +02:00
&& ! $this -> isGranted ( '@labels.use_twig' )
2020-05-07 22:29:45 +02:00
) {
$form_options [ 'disable_options' ] = true ;
}
$form = $this -> createForm ( $this -> form_class , $entity , $form_options );
2019-04-20 20:39:06 +02:00
$form -> handleRequest ( $request );
if ( $form -> isSubmitted () && $form -> isValid ()) {
2020-06-07 21:11:09 +02:00
if ( $this -> additionalActionEdit ( $form , $entity )) {
//Upload passed files
$attachments = $form [ 'attachments' ];
foreach ( $attachments as $attachment ) {
/** @var FormInterface $attachment */
try {
2024-03-03 18:52:06 +01:00
$this -> attachmentSubmitHandler -> handleUpload (
2020-06-07 21:11:09 +02:00
$attachment -> getData (),
2024-03-03 18:52:06 +01:00
AttachmentUpload :: fromAttachmentForm ( $attachment )
2020-06-07 21:11:09 +02:00
);
} catch ( AttachmentDownloadException $attachmentDownloadException ) {
$this -> addFlash (
'error' ,
$this -> translator -> trans (
'attachment.download_failed'
) . ' ' . $attachmentDownloadException -> getMessage ()
);
}
2019-10-19 18:50:17 +02:00
}
2019-09-24 18:28:35 +02:00
2024-03-10 01:19:52 +01:00
//Ensure that the master picture is still part of the attachments
2024-06-22 00:31:43 +02:00
if ( $entity instanceof AttachmentContainingDBElement && ( $entity -> getMasterPictureAttachment () !== null && ! $entity -> getAttachments () -> contains ( $entity -> getMasterPictureAttachment ()))) {
$entity -> setMasterPictureAttachment ( null );
2024-03-10 01:19:52 +01:00
}
2020-06-07 21:11:09 +02:00
$this -> commentHelper -> setMessage ( $form [ 'log_comment' ] -> getData ());
2020-02-23 00:44:52 +01:00
2026-03-04 23:05:21 +01:00
//In principle, the form should be disabled, if the edit permission is not granted, but for good measure, we also check it here, before saving changes.
$this -> denyAccessUnlessGranted ( 'edit' , $entity );
2020-06-07 21:11:09 +02:00
$em -> persist ( $entity );
$em -> flush ();
$this -> addFlash ( 'success' , 'entity.edit_flash' );
}
2019-08-26 11:41:39 +02:00
//Rebuild form, so it is based on the updated data. Important for the parent field!
//We can not use dynamic form events here, because the parent entity list is build from database!
2020-03-24 21:49:09 +01:00
$form = $this -> createForm ( $this -> form_class , $entity , [
'attachment_class' => $this -> attachment_class ,
2020-03-29 22:16:06 +02:00
'parameter_class' => $this -> parameter_class ,
2020-03-24 21:49:09 +01:00
]);
2020-08-21 21:36:22 +02:00
} elseif ( $form -> isSubmitted () && ! $form -> isValid ()) {
2019-12-26 14:53:13 +01:00
$this -> addFlash ( 'error' , 'entity.edit_flash.invalid' );
2019-04-20 20:39:06 +02:00
}
2020-05-01 21:19:13 +02:00
//Show preview for LabelProfile if needed.
if ( $entity instanceof LabelProfile ) {
$example = $this -> barcodeExampleGenerator -> getElement ( $entity -> getOptions () -> getSupportedElement ());
2024-08-23 22:15:29 +02:00
$pdf_data = null ;
try {
$pdf_data = $this -> labelGenerator -> generateLabel ( $entity -> getOptions (), $example );
} catch ( TwigModeException $exception ) {
2024-08-23 22:28:29 +02:00
$form -> get ( 'options' ) -> get ( 'lines' ) -> addError ( new FormError ( $exception -> getSafeMessage ()));
2024-08-23 22:15:29 +02:00
}
2020-05-01 21:19:13 +02:00
}
2020-05-16 20:53:35 +02:00
$repo = $this -> entityManager -> getRepository ( $this -> entity_class );
2023-05-28 01:21:05 +02:00
return $this -> render ( $this -> twig_template , [
2019-04-20 20:39:06 +02:00
'entity' => $entity ,
2022-03-04 21:20:18 +01:00
'form' => $form ,
2020-02-23 19:45:06 +01:00
'route_base' => $this -> route_base ,
2020-03-04 21:54:03 +01:00
'datatable' => $table ,
2020-05-01 21:19:13 +02:00
'pdf_data' => $pdf_data ? ? null ,
2020-03-15 13:56:31 +01:00
'timeTravel' => $timeTravel_timestamp ,
2020-05-16 20:53:35 +02:00
'repo' => $repo ,
2020-05-16 21:14:05 +02:00
'partsContainingElement' => $repo instanceof PartsContainingRepositoryInterface ,
2025-10-27 21:58:16 +01:00
'showParameters' => ! ( $this instanceof PartCustomStateController ),
2019-04-20 20:39:06 +02:00
]);
}
2020-06-07 21:11:09 +02:00
/**
* Perform some additional actions , when the form was valid , but before the entity is saved .
2020-08-21 21:36:22 +02:00
*
* @ return bool return true , to save entity normally , return false , to abort saving
2020-06-07 21:11:09 +02:00
*/
protected function additionalActionNew ( FormInterface $form , AbstractNamedDBElement $entity ) : bool
{
return true ;
}
2023-06-18 15:37:42 +02:00
protected function _new ( Request $request , EntityManagerInterface $em , EntityImporter $importer , ? AbstractNamedDBElement $entity = null ) : Response
2019-04-20 20:39:06 +02:00
{
2023-06-11 14:55:06 +02:00
$new_entity = $entity instanceof AbstractNamedDBElement ? clone $entity : new $this -> entity_class ();
2019-04-20 20:39:06 +02:00
$this -> denyAccessUnlessGranted ( 'read' , $new_entity );
//Basic edit form
2020-03-24 21:49:09 +01:00
$form = $this -> createForm ( $this -> form_class , $new_entity , [
'attachment_class' => $this -> attachment_class ,
'parameter_class' => $this -> parameter_class ,
]);
2019-04-20 20:39:06 +02:00
$form -> handleRequest ( $request );
2023-06-11 14:15:46 +02:00
//Perform additional actions
if ( $form -> isSubmitted () && $form -> isValid () && $this -> additionalActionNew ( $form , $new_entity )) {
//Upload passed files
$attachments = $form [ 'attachments' ];
foreach ( $attachments as $attachment ) {
/** @var FormInterface $attachment */
try {
2024-03-03 18:52:06 +01:00
$this -> attachmentSubmitHandler -> handleUpload (
2023-06-11 14:15:46 +02:00
$attachment -> getData (),
2024-03-03 18:52:06 +01:00
AttachmentUpload :: fromAttachmentForm ( $attachment )
2023-06-11 14:15:46 +02:00
);
} catch ( AttachmentDownloadException $attachmentDownloadException ) {
$this -> addFlash (
'error' ,
$this -> translator -> trans (
'attachment.download_failed'
) . ' ' . $attachmentDownloadException -> getMessage ()
);
2019-10-19 18:50:17 +02:00
}
2020-06-07 21:11:09 +02:00
}
2024-03-10 01:19:52 +01:00
//Ensure that the master picture is still part of the attachments
2024-06-22 00:31:43 +02:00
if ( $new_entity instanceof AttachmentContainingDBElement && ( $new_entity -> getMasterPictureAttachment () !== null && ! $new_entity -> getAttachments () -> contains ( $new_entity -> getMasterPictureAttachment ()))) {
$new_entity -> setMasterPictureAttachment ( null );
2024-03-10 01:19:52 +01:00
}
2023-06-11 14:15:46 +02:00
$this -> commentHelper -> setMessage ( $form [ 'log_comment' ] -> getData ());
$em -> persist ( $new_entity );
$em -> flush ();
$this -> addFlash ( 'success' , 'entity.created_flash' );
return $this -> redirectToRoute ( $this -> route_base . '_edit' , [ 'id' => $new_entity -> getID ()]);
2019-09-16 22:04:59 +02:00
}
2020-08-21 21:36:22 +02:00
if ( $form -> isSubmitted () && ! $form -> isValid ()) {
2019-12-26 14:53:13 +01:00
$this -> addFlash ( 'error' , 'entity.created_flash.invalid' );
2019-04-20 20:39:06 +02:00
}
//Import form
$import_form = $this -> createForm ( ImportType :: class , [ 'entity_class' => $this -> entity_class ]);
$import_form -> handleRequest ( $request );
if ( $import_form -> isSubmitted () && $import_form -> isValid ()) {
/** @var UploadedFile $file */
$file = $import_form [ 'file' ] -> getData ();
$data = $import_form -> getData ();
2023-03-12 21:43:40 +01:00
if ( $data [ 'format' ] === 'auto' ) {
$format = $importer -> determineFormat ( $file -> getClientOriginalExtension ());
if ( null === $format ) {
$this -> addFlash ( 'error' , 'parts.import.flash.error.unknown_format' );
goto ret ;
}
} else {
$format = $data [ 'format' ];
}
2020-01-05 22:49:00 +01:00
$options = [
2023-03-13 22:43:26 +01:00
'parent' => $data [ 'parent' ] ? ? null ,
'preserve_children' => $data [ 'preserve_children' ] ? ? false ,
2023-03-12 21:43:40 +01:00
'format' => $format ,
2023-03-12 19:16:49 +01:00
'class' => $this -> entity_class ,
2023-03-12 19:53:55 +01:00
'csv_delimiter' => $data [ 'csv_delimiter' ],
2023-03-15 21:46:14 +01:00
'abort_on_validation_error' => $data [ 'abort_on_validation_error' ],
2020-01-05 22:49:00 +01:00
];
2019-04-20 20:39:06 +02:00
2020-03-15 13:56:31 +01:00
$this -> commentHelper -> setMessage ( 'Import ' . $file -> getClientOriginalName ());
2020-02-23 00:44:52 +01:00
2023-03-12 21:43:40 +01:00
try {
$errors = $importer -> importFileAndPersistToDB ( $file , $options );
2023-03-13 22:43:26 +01:00
2024-06-22 22:55:15 +02:00
foreach ( $errors as $name => [ 'violations' => $violations ]) {
foreach ( $violations as $violation ) {
2023-03-14 00:19:10 +01:00
$this -> addFlash ( 'error' , $name . ': ' . $violation -> getMessage ());
}
2023-03-13 22:43:26 +01:00
}
2023-03-12 21:43:40 +01:00
}
2023-06-11 14:15:46 +02:00
catch ( UnexpectedValueException ) {
2023-03-12 21:43:40 +01:00
$this -> addFlash ( 'error' , 'parts.import.flash.error.invalid_file' );
2019-04-20 20:39:06 +02:00
}
}
2024-06-22 22:55:15 +02:00
ret :
2019-08-12 22:41:58 +02:00
//Mass creation form
$mass_creation_form = $this -> createForm ( MassCreationForm :: class , [ 'entity_class' => $this -> entity_class ]);
$mass_creation_form -> handleRequest ( $request );
if ( $mass_creation_form -> isSubmitted () && $mass_creation_form -> isValid ()) {
$data = $mass_creation_form -> getData ();
//Create entries based on input
2019-11-09 16:14:57 +01:00
$errors = [];
2023-01-28 23:24:45 +01:00
$results = $importer -> massCreation ( $data [ 'lines' ], $this -> entity_class , $data [ 'parent' ] ? ? null , $errors );
2019-08-12 22:41:58 +02:00
//Show errors to user:
2024-06-22 22:55:15 +02:00
foreach ( $errors as [ 'entity' => $new_entity , 'violations' => $violations ]) {
/** @var ConstraintViolationInterface $violation */
foreach ( $violations as $violation ) {
if ( $new_entity instanceof AbstractStructuralDBElement ) {
$this -> addFlash ( 'error' , $new_entity -> getFullPath () . ':' . $violation -> getMessage ());
} else { //When we don't have a structural element, we can only show the name
$this -> addFlash ( 'error' , $new_entity -> getName () . ':' . $violation -> getMessage ());
}
2023-02-03 23:27:49 +01:00
}
2019-08-12 22:41:58 +02:00
}
2019-11-09 16:14:57 +01:00
2025-12-07 20:44:32 +01:00
//Count how many actual new entities were created (id is null until persisted)
$created_count = 0 ;
foreach ( $results as $result ) {
if ( null === $result -> getID ()) {
$created_count ++ ;
}
}
2019-11-09 16:14:57 +01:00
//Persist valid entities to DB
foreach ( $results as $result ) {
$em -> persist ( $result );
}
$em -> flush ();
2024-03-10 00:55:22 +01:00
2025-12-07 21:40:57 +01:00
if ( count ( $results ) > 0 ) {
2025-12-07 20:44:32 +01:00
$this -> addFlash ( 'success' , t ( 'entity.mass_creation_flash' , [ '%COUNT%' => $created_count ]));
2024-03-10 00:55:22 +01:00
}
2025-12-07 20:50:09 +01:00
2025-12-07 21:33:41 +01:00
if ( count ( $errors )) {
//Recreate mass creation form, so we get the updated parent list and empty lines
$mass_creation_form = $this -> createForm ( MassCreationForm :: class , [ 'entity_class' => $this -> entity_class ]);
}
2019-08-12 22:41:58 +02:00
}
2023-05-28 01:21:05 +02:00
return $this -> render ( $this -> twig_template , [
2019-04-20 20:39:06 +02:00
'entity' => $new_entity ,
2022-03-04 21:20:18 +01:00
'form' => $form ,
2022-03-07 00:47:41 +01:00
'import_form' => $import_form ,
'mass_creation_form' => $mass_creation_form ,
2020-02-23 19:45:06 +01:00
'route_base' => $this -> route_base ,
2025-10-27 21:58:16 +01:00
'showParameters' => ! ( $this instanceof PartCustomStateController ),
2019-04-20 20:39:06 +02:00
]);
}
2020-06-07 21:11:09 +02:00
/**
2023-04-15 23:14:53 +02:00
* Performs checks if the element can be deleted safely . Otherwise , a flash message is added .
2020-08-21 21:36:22 +02:00
*
* @ param AbstractNamedDBElement $entity the element that should be checked
*
2023-04-15 23:14:53 +02:00
* @ return bool True if the element can be deleted , false if not
2020-06-07 21:11:09 +02:00
*/
protected function deleteCheck ( AbstractNamedDBElement $entity ) : bool
{
if ( $entity instanceof AbstractPartsContainingDBElement ) {
/** @var AbstractPartsContainingRepository $repo */
2024-12-28 22:31:04 +01:00
$repo = $this -> entityManager -> getRepository ( $this -> entity_class ); //@phpstan-ignore-line
2020-06-07 21:11:09 +02:00
if ( $repo -> getPartsCount ( $entity ) > 0 ) {
2022-09-21 13:05:52 +02:00
$this -> addFlash ( 'error' , t ( 'entity.delete.must_not_contain_parts' , [ '%PATH%' => $entity -> getFullPath ()]));
2020-08-21 21:36:22 +02:00
2020-06-07 21:11:09 +02:00
return false ;
}
}
2020-08-21 21:36:22 +02:00
2020-06-07 21:11:09 +02:00
return true ;
}
2020-03-15 13:56:31 +01:00
protected function _delete ( Request $request , AbstractNamedDBElement $entity , StructuralElementRecursionHelper $recursionHelper ) : RedirectResponse
2019-04-20 20:39:06 +02:00
{
$this -> denyAccessUnlessGranted ( 'delete' , $entity );
2023-06-18 00:00:58 +02:00
if ( $this -> isCsrfTokenValid ( 'delete' . $entity -> getID (), $request -> request -> get ( '_token' ))) {
2022-08-14 19:32:53 +02:00
$entityManager = $this -> entityManager ;
2019-04-20 20:39:06 +02:00
2020-06-07 21:11:09 +02:00
if ( ! $this -> deleteCheck ( $entity )) {
return $this -> redirectToRoute ( $this -> route_base . '_edit' , [ 'id' => $entity -> getID ()]);
2020-05-17 21:52:47 +02:00
}
2019-04-20 20:39:06 +02:00
//Check if we need to remove recursively
2020-02-01 19:48:07 +01:00
if ( $entity instanceof AbstractStructuralDBElement && $request -> get ( 'delete_recursive' , false )) {
2022-09-21 13:05:52 +02:00
$can_delete = true ;
//Check if any of the children can not be deleted, cause it contains parts
$recursionHelper -> execute ( $entity , function ( AbstractStructuralDBElement $element ) use ( & $can_delete ) {
if ( ! $this -> deleteCheck ( $element )) {
$can_delete = false ;
}
});
if ( $can_delete ) {
$recursionHelper -> delete ( $entity , false );
} else {
return $this -> redirectToRoute ( $this -> route_base . '_edit' , [ 'id' => $entity -> getID ()]);
}
2019-04-20 20:39:06 +02:00
} else {
2020-02-01 19:48:07 +01:00
if ( $entity instanceof AbstractStructuralDBElement ) {
2019-09-19 12:35:28 +02:00
$parent = $entity -> getParent ();
//Move all sub entities to the current parent
foreach ( $entity -> getSubelements () as $subelement ) {
$subelement -> setParent ( $parent );
$entityManager -> persist ( $subelement );
}
2019-04-20 20:39:06 +02:00
}
//Remove current element
$entityManager -> remove ( $entity );
}
2020-02-23 00:44:52 +01:00
$this -> commentHelper -> setMessage ( $request -> request -> get ( 'log_comment' , null ));
2019-04-20 20:39:06 +02:00
//Flush changes
$entityManager -> flush ();
$this -> addFlash ( 'success' , 'attachment_type.deleted' );
2019-10-26 22:27:04 +02:00
} else {
$this -> addFlash ( 'error' , 'csfr_invalid' );
2019-04-20 20:39:06 +02:00
}
2019-11-09 00:47:20 +01:00
return $this -> redirectToRoute ( $this -> route_base . '_new' );
2019-04-20 20:39:06 +02:00
}
2020-02-02 14:05:36 +01:00
protected function _exportAll ( EntityManagerInterface $em , EntityExporter $exporter , Request $request ) : Response
2019-04-20 20:39:06 +02:00
{
$entity = new $this -> entity_class ();
$this -> denyAccessUnlessGranted ( 'read' , $entity );
$entities = $em -> getRepository ( $this -> entity_class ) -> findAll ();
2020-08-21 21:36:22 +02:00
2025-02-01 20:57:27 +01:00
if ( count ( $entities ) === 0 ) {
$this -> addFlash ( 'error' , 'entity.export.flash.error.no_entities' );
return $this -> redirectToRoute ( $this -> route_base . '_new' );
}
2019-11-09 00:47:20 +01:00
return $exporter -> exportEntityFromRequest ( $entities , $request );
2019-04-20 20:39:06 +02:00
}
2020-08-21 22:43:37 +02:00
protected function _exportEntity ( AbstractNamedDBElement $entity , EntityExporter $exporter , Request $request ) : Response
2019-04-20 20:39:06 +02:00
{
$this -> denyAccessUnlessGranted ( 'read' , $entity );
2020-08-21 21:36:22 +02:00
2019-04-20 20:39:06 +02:00
return $exporter -> exportEntityFromRequest ( $entity , $request );
}
2019-11-09 00:47:20 +01:00
}