2020-05-23 19:06:46 +02:00
< ? php
2023-06-11 18:59:07 +02:00
declare ( strict_types = 1 );
2020-05-23 19:06:46 +02: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-05-23 19:06:46 +02: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 />.
*/
namespace App\Services\Parts ;
2023-06-11 14:55:06 +02:00
use Symfony\Bundle\SecurityBundle\Security ;
2020-05-24 18:26:10 +02:00
use App\Entity\Parts\Category ;
use App\Entity\Parts\Footprint ;
use App\Entity\Parts\Manufacturer ;
use App\Entity\Parts\MeasurementUnit ;
2020-05-23 19:06:46 +02:00
use App\Entity\Parts\Part ;
2023-01-15 23:36:22 +01:00
use App\Entity\Parts\PartLot ;
2020-10-02 12:42:15 +02:00
use App\Repository\PartRepository ;
2020-05-23 19:06:46 +02:00
use Doctrine\ORM\EntityManagerInterface ;
2022-08-14 19:32:53 +02:00
use InvalidArgumentException ;
2022-12-28 23:32:46 +01:00
use Symfony\Component\HttpFoundation\RedirectResponse ;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface ;
2020-05-23 19:06:46 +02:00
use Symfony\Component\Security\Core\Exception\AccessDeniedException ;
final class PartsTableActionHandler
{
2023-06-11 14:55:06 +02:00
public function __construct ( private readonly EntityManagerInterface $entityManager , private readonly Security $security , private readonly UrlGeneratorInterface $urlGenerator )
2020-05-23 19:06:46 +02:00
{
}
/**
2020-08-21 21:36:22 +02:00
* Converts the given array to an array of Parts .
*
* @ param string $ids a comma separated list of Part IDs
*
2020-05-23 19:06:46 +02:00
* @ return Part []
*/
public function idStringToArray ( string $ids ) : array
{
$id_array = explode ( ',' , $ids );
$repo = $this -> entityManager -> getRepository ( Part :: class );
2020-08-21 21:36:22 +02:00
2020-05-23 19:06:46 +02:00
return $repo -> getElementsFromIDArray ( $id_array );
}
/**
2020-08-21 21:36:22 +02:00
* @ param Part [] $selected_parts
2022-12-28 23:32:46 +01:00
* @ return RedirectResponse | null Returns a redirect response if the user should be redirected to another page , otherwise null
2020-05-23 19:06:46 +02:00
*/
2022-12-28 23:32:46 +01:00
public function handleAction ( string $action , array $selected_parts , ? int $target_id , ? string $redirect_url = null ) : ? RedirectResponse
2020-05-23 19:06:46 +02:00
{
2022-12-28 23:32:46 +01:00
if ( $action === 'add_to_project' ) {
return new RedirectResponse (
$this -> urlGenerator -> generate ( 'project_add_parts' , [
'id' => $target_id ,
'parts' => implode ( ',' , array_map ( static fn ( Part $part ) => $part -> getID (), $selected_parts )),
'_redirect' => $redirect_url
])
);
}
2023-01-15 23:36:22 +01:00
if ( $action === 'generate_label' || $action === 'generate_label_lot' ) {
//For parts we can just use the comma separated part IDs
if ( $action === 'generate_label' ) {
$targets = implode ( ',' , array_map ( static fn ( Part $part ) => $part -> getID (), $selected_parts ));
} else { //For lots we have to extract the part lots
2023-06-11 14:15:46 +02:00
$targets = implode ( ',' , array_map ( static fn ( Part $part ) : string => //We concat the lot IDs of every part with a comma (which are later concated with a comma too per part)
implode ( ',' , array_map ( static fn ( PartLot $lot ) => $lot -> getID (), $part -> getPartLots () -> toArray ())), $selected_parts ));
2023-01-15 23:36:22 +01:00
}
return new RedirectResponse (
$this -> urlGenerator -> generate ( $target_id !== 0 && $target_id !== null ? 'label_dialog_profile' : 'label_dialog' , [
'profile' => $target_id ,
'target_id' => $targets ,
'generate' => '1' ,
'target_type' => $action === 'generate_label_lot' ? 'part_lot' : 'part' ,
])
);
}
2023-03-12 00:27:04 +01:00
//When action starts with "export_" we have to redirect to the export controller
$matches = [];
if ( preg_match ( '/^export_(json|yaml|xml|csv)$/' , $action , $matches )) {
$ids = implode ( ',' , array_map ( static fn ( Part $part ) => $part -> getID (), $selected_parts ));
2023-06-11 14:15:46 +02:00
$level = match ( $target_id ) {
2 => 'extended' ,
3 => 'full' ,
default => 'simple' ,
};
2023-03-12 00:27:04 +01:00
return new RedirectResponse (
$this -> urlGenerator -> generate ( 'parts_export' , [
'format' => $matches [ 1 ],
'level' => $level ,
'ids' => $ids ,
'_redirect' => $redirect_url
])
);
}
2022-12-28 23:32:46 +01:00
2020-05-23 19:06:46 +02:00
//Iterate over the parts and apply the action to it:
foreach ( $selected_parts as $part ) {
if ( ! $part instanceof Part ) {
2022-08-14 19:32:53 +02:00
throw new InvalidArgumentException ( '$selected_parts must be an array of Part elements!' );
2020-05-23 19:06:46 +02:00
}
//We modify parts, so you have to have the permission to modify it
$this -> denyAccessUnlessGranted ( 'edit' , $part );
switch ( $action ) {
case 'favorite' :
2022-10-31 23:10:21 +01:00
$this -> denyAccessUnlessGranted ( 'change_favorite' , $part );
2020-05-23 19:06:46 +02:00
$part -> setFavorite ( true );
break ;
case 'unfavorite' :
2022-10-31 23:10:21 +01:00
$this -> denyAccessUnlessGranted ( 'change_favorite' , $part );
2020-05-23 19:06:46 +02:00
$part -> setFavorite ( false );
break ;
2022-11-29 00:18:11 +01:00
case 'set_needs_review' :
$this -> denyAccessUnlessGranted ( 'edit' , $part );
$part -> setNeedsReview ( true );
break ;
case 'unset_needs_review' :
$this -> denyAccessUnlessGranted ( 'edit' , $part );
$part -> setNeedsReview ( false );
break ;
2020-05-23 19:06:46 +02:00
case 'delete' :
$this -> denyAccessUnlessGranted ( 'delete' , $part );
$this -> entityManager -> remove ( $part );
break ;
2020-05-24 18:26:10 +02:00
case 'change_category' :
2022-10-31 23:10:21 +01:00
$this -> denyAccessUnlessGranted ( '@categories.read' );
2020-05-24 18:26:10 +02:00
$part -> setCategory ( $this -> entityManager -> find ( Category :: class , $target_id ));
break ;
case 'change_footprint' :
2022-10-31 23:10:21 +01:00
$this -> denyAccessUnlessGranted ( '@footprints.read' );
2020-08-21 21:36:22 +02:00
$part -> setFootprint ( null === $target_id ? null : $this -> entityManager -> find ( Footprint :: class , $target_id ));
2020-05-24 18:26:10 +02:00
break ;
case 'change_manufacturer' :
2022-10-31 23:10:21 +01:00
$this -> denyAccessUnlessGranted ( '@manufacturers.read' );
2020-08-21 21:36:22 +02:00
$part -> setManufacturer ( null === $target_id ? null : $this -> entityManager -> find ( Manufacturer :: class , $target_id ));
2020-05-24 18:26:10 +02:00
break ;
case 'change_unit' :
2022-10-31 23:10:21 +01:00
$this -> denyAccessUnlessGranted ( '@measurement_units.read' );
2020-08-21 21:36:22 +02:00
$part -> setPartUnit ( null === $target_id ? null : $this -> entityManager -> find ( MeasurementUnit :: class , $target_id ));
2020-05-24 18:26:10 +02:00
break ;
2020-05-23 19:06:46 +02:00
default :
2022-08-14 19:32:53 +02:00
throw new InvalidArgumentException ( 'The given action is unknown! (' . $action . ')' );
2020-05-23 19:06:46 +02:00
}
}
2023-01-08 18:30:41 +01:00
return null ;
2020-05-23 19:06:46 +02:00
}
/**
* Throws an exception unless the attributes are granted against the current authentication token and optionally
* supplied subject .
*
* @ throws AccessDeniedException
*/
2023-06-18 15:37:42 +02:00
private function denyAccessUnlessGranted ( mixed $attributes , mixed $subject = null , string $message = 'Access Denied.' ) : void
2020-05-23 19:06:46 +02:00
{
if ( ! $this -> security -> isGranted ( $attributes , $subject )) {
$exception = new AccessDeniedException ( $message );
$exception -> setAttributes ( $attributes );
$exception -> setSubject ( $subject );
throw $exception ;
}
}
2020-08-21 21:36:22 +02:00
}