mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-06-20 17:15:51 +02:00
Applied rector with PHP8.1 migration rules
This commit is contained in:
parent
dc6a67c2f0
commit
7ee01d9a05
303 changed files with 1228 additions and 3465 deletions
|
@ -27,8 +27,8 @@ return static function (RectorConfig $rectorConfig): void {
|
|||
// define sets of rules
|
||||
$rectorConfig->sets([
|
||||
//PHP rules
|
||||
//SetList::CODE_QUALITY,
|
||||
//LevelSetList::UP_TO_PHP_81,
|
||||
SetList::CODE_QUALITY,
|
||||
LevelSetList::UP_TO_PHP_81,
|
||||
|
||||
//Symfony rules
|
||||
SymfonyLevelSetList::UP_TO_SYMFONY_62,
|
||||
|
|
|
@ -43,16 +43,10 @@ use const DIRECTORY_SEPARATOR;
|
|||
#[\Symfony\Component\Console\Attribute\AsCommand('partdb:attachments:clean-unused|app:clean-attachments', 'Lists (and deletes if wanted) attachments files that are not used anymore (abandoned files).')]
|
||||
class CleanAttachmentsCommand extends Command
|
||||
{
|
||||
protected AttachmentManager $attachment_helper;
|
||||
protected AttachmentReverseSearch $reverseSearch;
|
||||
protected MimeTypes $mimeTypeGuesser;
|
||||
protected AttachmentPathResolver $pathResolver;
|
||||
|
||||
public function __construct(AttachmentManager $attachmentHelper, AttachmentReverseSearch $reverseSearch, AttachmentPathResolver $pathResolver)
|
||||
public function __construct(protected AttachmentManager $attachment_helper, protected AttachmentReverseSearch $reverseSearch, protected AttachmentPathResolver $pathResolver)
|
||||
{
|
||||
$this->attachment_helper = $attachmentHelper;
|
||||
$this->pathResolver = $pathResolver;
|
||||
$this->reverseSearch = $reverseSearch;
|
||||
$this->mimeTypeGuesser = new MimeTypes();
|
||||
parent::__construct();
|
||||
}
|
||||
|
@ -88,7 +82,7 @@ class CleanAttachmentsCommand extends Command
|
|||
|
||||
foreach ($finder as $file) {
|
||||
//If not attachment object uses this file, print it
|
||||
if (0 === count($this->reverseSearch->findAttachmentsByFile($file))) {
|
||||
if ([] === $this->reverseSearch->findAttachmentsByFile($file)) {
|
||||
$file_list[] = $file;
|
||||
$table->addRow([
|
||||
$fs->makePathRelative($file->getPathname(), $mediaPath),
|
||||
|
@ -98,7 +92,7 @@ class CleanAttachmentsCommand extends Command
|
|||
}
|
||||
}
|
||||
|
||||
if (count($file_list) > 0) {
|
||||
if ($file_list !== []) {
|
||||
$table->render();
|
||||
|
||||
$continue = $io->confirm(sprintf('Found %d abandoned files. Do you want to delete them? This can not be undone!', count($file_list)), false);
|
||||
|
|
|
@ -19,14 +19,8 @@ use Symfony\Component\Console\Style\SymfonyStyle;
|
|||
#[\Symfony\Component\Console\Attribute\AsCommand('partdb:backup', 'Backup the files and the database of Part-DB')]
|
||||
class BackupCommand extends Command
|
||||
{
|
||||
private string $project_dir;
|
||||
private EntityManagerInterface $entityManager;
|
||||
|
||||
public function __construct(string $project_dir, EntityManagerInterface $entityManager)
|
||||
public function __construct(private readonly string $project_dir, private readonly EntityManagerInterface $entityManager)
|
||||
{
|
||||
$this->project_dir = $project_dir;
|
||||
$this->entityManager = $entityManager;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
|
@ -69,13 +63,10 @@ class BackupCommand extends Command
|
|||
$io->info('Backup Part-DB to '.$output_filepath);
|
||||
|
||||
//Check if the file already exists
|
||||
if (file_exists($output_filepath)) {
|
||||
//Then ask the user, if he wants to overwrite the file
|
||||
if (!$io->confirm('The file '.realpath($output_filepath).' already exists. Do you want to overwrite it?', false)) {
|
||||
$io->error('Backup aborted!');
|
||||
|
||||
return Command::FAILURE;
|
||||
}
|
||||
//Then ask the user, if he wants to overwrite the file
|
||||
if (file_exists($output_filepath) && !$io->confirm('The file '.realpath($output_filepath).' already exists. Do you want to overwrite it?', false)) {
|
||||
$io->error('Backup aborted!');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$io->note('Starting backup...');
|
||||
|
@ -113,8 +104,6 @@ class BackupCommand extends Command
|
|||
/**
|
||||
* Constructs the MySQL PDO DSN.
|
||||
* Taken from https://github.com/doctrine/dbal/blob/3.5.x/src/Driver/PDO/MySQL/Driver.php
|
||||
*
|
||||
* @param array $params
|
||||
*/
|
||||
private function configureDumper(array $params, DbDumper $dumper): void
|
||||
{
|
||||
|
|
|
@ -30,11 +30,8 @@ use Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface;
|
|||
#[\Symfony\Component\Console\Attribute\AsCommand('partdb:check-requirements', 'Checks if the requirements Part-DB needs or recommends are fulfilled.')]
|
||||
class CheckRequirementsCommand extends Command
|
||||
{
|
||||
protected ContainerBagInterface $params;
|
||||
|
||||
public function __construct(ContainerBagInterface $params)
|
||||
public function __construct(protected ContainerBagInterface $params)
|
||||
{
|
||||
$this->params = $params;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
|
@ -66,40 +63,48 @@ class CheckRequirementsCommand extends Command
|
|||
protected function checkPHP(SymfonyStyle $io, $only_issues = false): void
|
||||
{
|
||||
//Check PHP versions
|
||||
$io->isVerbose() && $io->comment('Checking PHP version...');
|
||||
if ($io->isVerbose()) {
|
||||
$io->comment('Checking PHP version...');
|
||||
}
|
||||
//We recommend PHP 8.2, but 8.1 is the minimum
|
||||
if (PHP_VERSION_ID < 80200) {
|
||||
$io->warning('You are using PHP '. PHP_VERSION .'. This will work, but a newer version is recommended.');
|
||||
} else {
|
||||
!$only_issues && $io->success('PHP version is sufficient.');
|
||||
} elseif (!$only_issues) {
|
||||
$io->success('PHP version is sufficient.');
|
||||
}
|
||||
|
||||
//Check if opcache is enabled
|
||||
$io->isVerbose() && $io->comment('Checking Opcache...');
|
||||
if ($io->isVerbose()) {
|
||||
$io->comment('Checking Opcache...');
|
||||
}
|
||||
$opcache_enabled = ini_get('opcache.enable') === '1';
|
||||
if (!$opcache_enabled) {
|
||||
$io->warning('Opcache is not enabled. This will work, but performance will be better with opcache enabled. Set opcache.enable=1 in your php.ini to enable it');
|
||||
} else {
|
||||
!$only_issues && $io->success('Opcache is enabled.');
|
||||
} elseif (!$only_issues) {
|
||||
$io->success('Opcache is enabled.');
|
||||
}
|
||||
|
||||
//Check if opcache is configured correctly
|
||||
$io->isVerbose() && $io->comment('Checking Opcache configuration...');
|
||||
if ($io->isVerbose()) {
|
||||
$io->comment('Checking Opcache configuration...');
|
||||
}
|
||||
if ($opcache_enabled && (ini_get('opcache.memory_consumption') < 256 || ini_get('opcache.max_accelerated_files') < 20000)) {
|
||||
$io->warning('Opcache configuration can be improved. See https://symfony.com/doc/current/performance.html for more info.');
|
||||
} else {
|
||||
!$only_issues && $io->success('Opcache configuration is already performance optimized.');
|
||||
} elseif (!$only_issues) {
|
||||
$io->success('Opcache configuration is already performance optimized.');
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkPartDBConfig(SymfonyStyle $io, $only_issues = false): void
|
||||
{
|
||||
//Check if APP_ENV is set to prod
|
||||
$io->isVerbose() && $io->comment('Checking debug mode...');
|
||||
if($this->params->get('kernel.debug')) {
|
||||
if ($io->isVerbose()) {
|
||||
$io->comment('Checking debug mode...');
|
||||
}
|
||||
if ($this->params->get('kernel.debug')) {
|
||||
$io->warning('You have activated debug mode, this is will leak informations in a production environment.');
|
||||
} else {
|
||||
!$only_issues && $io->success('Debug mode disabled.');
|
||||
} elseif (!$only_issues) {
|
||||
$io->success('Debug mode disabled.');
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -108,61 +113,71 @@ class CheckRequirementsCommand extends Command
|
|||
{
|
||||
//Get all installed PHP extensions
|
||||
$extensions = get_loaded_extensions();
|
||||
$io->isVerbose() && $io->comment('Your PHP installation has '. count($extensions) .' extensions installed: '. implode(', ', $extensions));
|
||||
if ($io->isVerbose()) {
|
||||
$io->comment('Your PHP installation has '. count($extensions) .' extensions installed: '. implode(', ', $extensions));
|
||||
}
|
||||
|
||||
$db_drivers_count = 0;
|
||||
if(!in_array('pdo_mysql', $extensions)) {
|
||||
$io->error('pdo_mysql is not installed. You will not be able to use MySQL databases.');
|
||||
} else {
|
||||
!$only_issues && $io->success('PHP extension pdo_mysql is installed.');
|
||||
if (!$only_issues) {
|
||||
$io->success('PHP extension pdo_mysql is installed.');
|
||||
}
|
||||
$db_drivers_count++;
|
||||
}
|
||||
|
||||
if(!in_array('pdo_sqlite', $extensions)) {
|
||||
$io->error('pdo_sqlite is not installed. You will not be able to use SQLite. databases');
|
||||
} else {
|
||||
!$only_issues && $io->success('PHP extension pdo_sqlite is installed.');
|
||||
if (!$only_issues) {
|
||||
$io->success('PHP extension pdo_sqlite is installed.');
|
||||
}
|
||||
$db_drivers_count++;
|
||||
}
|
||||
|
||||
$io->isVerbose() && $io->comment('You have '. $db_drivers_count .' database drivers installed.');
|
||||
if ($io->isVerbose()) {
|
||||
$io->comment('You have '. $db_drivers_count .' database drivers installed.');
|
||||
}
|
||||
if ($db_drivers_count === 0) {
|
||||
$io->error('You have no database drivers installed. You have to install at least one database driver!');
|
||||
}
|
||||
|
||||
if(!in_array('curl', $extensions)) {
|
||||
if (!in_array('curl', $extensions)) {
|
||||
$io->warning('curl extension is not installed. Install curl extension for better performance');
|
||||
} else {
|
||||
!$only_issues && $io->success('PHP extension curl is installed.');
|
||||
} elseif (!$only_issues) {
|
||||
$io->success('PHP extension curl is installed.');
|
||||
}
|
||||
|
||||
$gd_installed = in_array('gd', $extensions);
|
||||
if(!$gd_installed) {
|
||||
if (!$gd_installed) {
|
||||
$io->error('GD is not installed. GD is required for image processing.');
|
||||
} else {
|
||||
!$only_issues && $io->success('PHP extension GD is installed.');
|
||||
} elseif (!$only_issues) {
|
||||
$io->success('PHP extension GD is installed.');
|
||||
}
|
||||
|
||||
//Check if GD has jpeg support
|
||||
$io->isVerbose() && $io->comment('Checking if GD has jpeg support...');
|
||||
if ($io->isVerbose()) {
|
||||
$io->comment('Checking if GD has jpeg support...');
|
||||
}
|
||||
if ($gd_installed) {
|
||||
$gd_info = gd_info();
|
||||
if($gd_info['JPEG Support'] === false) {
|
||||
if ($gd_info['JPEG Support'] === false) {
|
||||
$io->warning('Your GD does not have jpeg support. You will not be able to generate thumbnails of jpeg images.');
|
||||
} else {
|
||||
!$only_issues && $io->success('GD has jpeg support.');
|
||||
} elseif (!$only_issues) {
|
||||
$io->success('GD has jpeg support.');
|
||||
}
|
||||
|
||||
if($gd_info['PNG Support'] === false) {
|
||||
if ($gd_info['PNG Support'] === false) {
|
||||
$io->warning('Your GD does not have png support. You will not be able to generate thumbnails of png images.');
|
||||
} else {
|
||||
!$only_issues && $io->success('GD has png support.');
|
||||
} elseif (!$only_issues) {
|
||||
$io->success('GD has png support.');
|
||||
}
|
||||
|
||||
if($gd_info['WebP Support'] === false) {
|
||||
if ($gd_info['WebP Support'] === false) {
|
||||
$io->warning('Your GD does not have WebP support. You will not be able to generate thumbnails of WebP images.');
|
||||
} else {
|
||||
!$only_issues && $io->success('GD has WebP support.');
|
||||
} elseif (!$only_issues) {
|
||||
$io->success('GD has WebP support.');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,18 +38,8 @@ use function strlen;
|
|||
#[\Symfony\Component\Console\Attribute\AsCommand('partdb:currencies:update-exchange-rates|partdb:update-exchange-rates|app:update-exchange-rates', 'Updates the currency exchange rates.')]
|
||||
class UpdateExchangeRatesCommand extends Command
|
||||
{
|
||||
protected string $base_current;
|
||||
protected EntityManagerInterface $em;
|
||||
protected ExchangeRateUpdater $exchangeRateUpdater;
|
||||
|
||||
public function __construct(string $base_current, EntityManagerInterface $entityManager, ExchangeRateUpdater $exchangeRateUpdater)
|
||||
public function __construct(protected string $base_current, protected EntityManagerInterface $em, protected ExchangeRateUpdater $exchangeRateUpdater)
|
||||
{
|
||||
//$this->swap = $swap;
|
||||
$this->base_current = $base_current;
|
||||
|
||||
$this->em = $entityManager;
|
||||
$this->exchangeRateUpdater = $exchangeRateUpdater;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
|
@ -75,11 +65,7 @@ class UpdateExchangeRatesCommand extends Command
|
|||
$iso_code = $input->getArgument('iso_code');
|
||||
$repo = $this->em->getRepository(Currency::class);
|
||||
|
||||
if (!empty($iso_code)) {
|
||||
$candidates = $repo->findBy(['iso_code' => $iso_code]);
|
||||
} else {
|
||||
$candidates = $repo->findAll();
|
||||
}
|
||||
$candidates = empty($iso_code) ? $repo->findAll() : $repo->findBy(['iso_code' => $iso_code]);
|
||||
|
||||
$success_counter = 0;
|
||||
|
||||
|
|
|
@ -39,20 +39,11 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
#[\Symfony\Component\Console\Attribute\AsCommand('partdb:logs:show|app:show-logs', 'List the last event log entries.')]
|
||||
class ShowEventLogCommand extends Command
|
||||
{
|
||||
protected EntityManagerInterface $entityManager;
|
||||
protected TranslatorInterface $translator;
|
||||
protected ElementTypeNameGenerator $elementTypeNameGenerator;
|
||||
protected LogEntryRepository $repo;
|
||||
protected LogEntryExtraFormatter $formatter;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager,
|
||||
TranslatorInterface $translator, ElementTypeNameGenerator $elementTypeNameGenerator, LogEntryExtraFormatter $formatter)
|
||||
public function __construct(protected EntityManagerInterface $entityManager,
|
||||
protected TranslatorInterface $translator, protected ElementTypeNameGenerator $elementTypeNameGenerator, protected LogEntryExtraFormatter $formatter)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->translator = $translator;
|
||||
$this->elementTypeNameGenerator = $elementTypeNameGenerator;
|
||||
$this->formatter = $formatter;
|
||||
|
||||
$this->repo = $this->entityManager->getRepository(AbstractLogEntry::class);
|
||||
parent::__construct();
|
||||
}
|
||||
|
@ -145,14 +136,12 @@ class ShowEventLogCommand extends Command
|
|||
$target_class = $this->elementTypeNameGenerator->getLocalizedTypeLabel($entry->getTargetClass());
|
||||
}
|
||||
|
||||
if ($entry->getUser()) {
|
||||
if ($entry->getUser() instanceof \App\Entity\UserSystem\User) {
|
||||
$user = $entry->getUser()->getFullName(true);
|
||||
} elseif ($entry->isCLIEntry()) {
|
||||
$user = $entry->getCLIUsername() . ' [CLI]';
|
||||
} else {
|
||||
if ($entry->isCLIEntry()) {
|
||||
$user = $entry->getCLIUsername() . ' [CLI]';
|
||||
} else {
|
||||
$user = $entry->getUsername() . ' [deleted]';
|
||||
}
|
||||
$user = $entry->getUsername() . ' [deleted]';
|
||||
}
|
||||
|
||||
$row = [
|
||||
|
|
|
@ -58,16 +58,10 @@ class ConvertBBCodeCommand extends Command
|
|||
* @var string The regex (performed in PHP) used to check if a property really contains BBCODE
|
||||
*/
|
||||
protected const BBCODE_REGEX = '/\\[.+\\].*\\[\\/.+\\]/';
|
||||
|
||||
protected EntityManagerInterface $em;
|
||||
protected PropertyAccessorInterface $propertyAccessor;
|
||||
protected BBCodeToMarkdownConverter $converter;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, PropertyAccessorInterface $propertyAccessor)
|
||||
public function __construct(protected EntityManagerInterface $em, protected PropertyAccessorInterface $propertyAccessor)
|
||||
{
|
||||
$this->em = $entityManager;
|
||||
$this->propertyAccessor = $propertyAccessor;
|
||||
|
||||
$this->converter = new BBCodeToMarkdownConverter();
|
||||
|
||||
parent::__construct();
|
||||
|
@ -126,25 +120,25 @@ class ConvertBBCodeCommand extends Command
|
|||
|
||||
//Fetch resulting classes
|
||||
$results = $qb->getQuery()->getResult();
|
||||
$io->note(sprintf('Found %d entities, that need to be converted!', count($results)));
|
||||
$io->note(sprintf('Found %d entities, that need to be converted!', is_countable($results) ? count($results) : 0));
|
||||
|
||||
//In verbose mode print the names of the entities
|
||||
foreach ($results as $result) {
|
||||
/** @var AbstractNamedDBElement $result */
|
||||
$io->writeln(
|
||||
'Convert entity: '.$result->getName().' ('.get_class($result).': '.$result->getID().')',
|
||||
'Convert entity: '.$result->getName().' ('.$result::class.': '.$result->getID().')',
|
||||
OutputInterface::VERBOSITY_VERBOSE
|
||||
);
|
||||
foreach ($properties as $property) {
|
||||
//Retrieve bbcode from entity
|
||||
$bbcode = $this->propertyAccessor->getValue($result, $property);
|
||||
//Check if the current property really contains BBCode
|
||||
if (!preg_match(static::BBCODE_REGEX, $bbcode)) {
|
||||
if (!preg_match(static::BBCODE_REGEX, (string) $bbcode)) {
|
||||
continue;
|
||||
}
|
||||
$io->writeln(
|
||||
'BBCode (old): '
|
||||
.str_replace('\n', ' ', substr($bbcode, 0, 255)),
|
||||
.str_replace('\n', ' ', substr((string) $bbcode, 0, 255)),
|
||||
OutputInterface::VERBOSITY_VERY_VERBOSE
|
||||
);
|
||||
$markdown = $this->converter->convert($bbcode);
|
||||
|
|
|
@ -37,24 +37,11 @@ use Symfony\Component\Console\Style\SymfonyStyle;
|
|||
class ImportPartKeeprCommand extends Command
|
||||
{
|
||||
|
||||
protected EntityManagerInterface $em;
|
||||
protected MySQLDumpXMLConverter $xml_converter;
|
||||
protected PKDatastructureImporter $datastructureImporter;
|
||||
protected PKImportHelper $importHelper;
|
||||
protected PKPartImporter $partImporter;
|
||||
protected PKOptionalImporter $optionalImporter;
|
||||
|
||||
public function __construct(EntityManagerInterface $em, MySQLDumpXMLConverter $xml_converter,
|
||||
PKDatastructureImporter $datastructureImporter, PKPartImporter $partImporter, PKImportHelper $importHelper,
|
||||
PKOptionalImporter $optionalImporter)
|
||||
public function __construct(protected EntityManagerInterface $em, protected MySQLDumpXMLConverter $xml_converter,
|
||||
protected PKDatastructureImporter $datastructureImporter, protected PKPartImporter $partImporter, protected PKImportHelper $importHelper,
|
||||
protected PKOptionalImporter $optionalImporter)
|
||||
{
|
||||
parent::__construct(self::$defaultName);
|
||||
$this->em = $em;
|
||||
$this->datastructureImporter = $datastructureImporter;
|
||||
$this->importHelper = $importHelper;
|
||||
$this->partImporter = $partImporter;
|
||||
$this->xml_converter = $xml_converter;
|
||||
$this->optionalImporter = $optionalImporter;
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
|
|
|
@ -33,14 +33,9 @@ use Symfony\Component\Console\Style\SymfonyStyle;
|
|||
#[\Symfony\Component\Console\Attribute\AsCommand('partdb:user:convert-to-saml-user|partdb:users:convert-to-saml-user', 'Converts a local user to a SAML user (and vice versa)')]
|
||||
class ConvertToSAMLUserCommand extends Command
|
||||
{
|
||||
protected EntityManagerInterface $entityManager;
|
||||
protected bool $saml_enabled;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, bool $saml_enabled)
|
||||
public function __construct(protected EntityManagerInterface $entityManager, protected bool $saml_enabled)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->entityManager = $entityManager;
|
||||
$this->saml_enabled = $saml_enabled;
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
|
|
|
@ -37,16 +37,8 @@ use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
|||
#[\Symfony\Component\Console\Attribute\AsCommand('partdb:users:set-password|app:set-password|users:set-password|partdb:user:set-password', 'Sets the password of a user')]
|
||||
class SetPasswordCommand extends Command
|
||||
{
|
||||
protected EntityManagerInterface $entityManager;
|
||||
protected UserPasswordHasherInterface $encoder;
|
||||
protected EventDispatcherInterface $eventDispatcher;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, UserPasswordHasherInterface $passwordEncoder, EventDispatcherInterface $eventDispatcher)
|
||||
public function __construct(protected EntityManagerInterface $entityManager, protected UserPasswordHasherInterface $encoder, protected EventDispatcherInterface $eventDispatcher)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->encoder = $passwordEncoder;
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
|
@ -64,7 +56,7 @@ class SetPasswordCommand extends Command
|
|||
|
||||
$user = $this->entityManager->getRepository(User::class)->findByEmailOrName($user_name);
|
||||
|
||||
if (!$user) {
|
||||
if (!$user instanceof \App\Entity\UserSystem\User) {
|
||||
$io->error(sprintf('No user with the given username %s found in the database!', $user_name));
|
||||
|
||||
return \Symfony\Component\Console\Command\Command::FAILURE;
|
||||
|
|
|
@ -34,17 +34,9 @@ use Symfony\Component\Console\Style\SymfonyStyle;
|
|||
#[\Symfony\Component\Console\Attribute\AsCommand('partdb:users:upgrade-permissions-schema', '(Manually) upgrades the permissions schema of all users to the latest version.')]
|
||||
final class UpgradePermissionsSchemaCommand extends Command
|
||||
{
|
||||
private PermissionSchemaUpdater $permissionSchemaUpdater;
|
||||
private EntityManagerInterface $em;
|
||||
private EventCommentHelper $eventCommentHelper;
|
||||
|
||||
public function __construct(PermissionSchemaUpdater $permissionSchemaUpdater, EntityManagerInterface $entityManager, EventCommentHelper $eventCommentHelper)
|
||||
public function __construct(private readonly PermissionSchemaUpdater $permissionSchemaUpdater, private readonly EntityManagerInterface $em, private readonly EventCommentHelper $eventCommentHelper)
|
||||
{
|
||||
parent::__construct(self::$defaultName);
|
||||
|
||||
$this->permissionSchemaUpdater = $permissionSchemaUpdater;
|
||||
$this->eventCommentHelper = $eventCommentHelper;
|
||||
$this->em = $entityManager;
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
|
@ -79,7 +71,7 @@ final class UpgradePermissionsSchemaCommand extends Command
|
|||
}
|
||||
|
||||
$io->info('Found '. count($groups_to_upgrade) .' groups and '. count($users_to_upgrade) .' users that need an update.');
|
||||
if (empty($groups_to_upgrade) && empty($users_to_upgrade)) {
|
||||
if ($groups_to_upgrade === [] && $users_to_upgrade === []) {
|
||||
$io->success('All users and group permissions schemas are up-to-date. No update needed.');
|
||||
|
||||
return \Symfony\Component\Console\Command\Command::SUCCESS;
|
||||
|
@ -87,14 +79,10 @@ final class UpgradePermissionsSchemaCommand extends Command
|
|||
|
||||
//List all users and groups that need an update
|
||||
$io->section('Groups that need an update:');
|
||||
$io->listing(array_map(static function (Group $group) {
|
||||
return $group->getName() . ' (ID: '. $group->getID() .', Current version: ' . $group->getPermissions()->getSchemaVersion() . ')';
|
||||
}, $groups_to_upgrade));
|
||||
$io->listing(array_map(static fn(Group $group): string => $group->getName() . ' (ID: '. $group->getID() .', Current version: ' . $group->getPermissions()->getSchemaVersion() . ')', $groups_to_upgrade));
|
||||
|
||||
$io->section('Users that need an update:');
|
||||
$io->listing(array_map(static function (User $user) {
|
||||
return $user->getUsername() . ' (ID: '. $user->getID() .', Current version: ' . $user->getPermissions()->getSchemaVersion() . ')';
|
||||
}, $users_to_upgrade));
|
||||
$io->listing(array_map(static fn(User $user): string => $user->getUsername() . ' (ID: '. $user->getID() .', Current version: ' . $user->getPermissions()->getSchemaVersion() . ')', $users_to_upgrade));
|
||||
|
||||
if(!$io->confirm('Continue with the update?', false)) {
|
||||
$io->warning('Update aborted.');
|
||||
|
|
|
@ -32,12 +32,8 @@ use Symfony\Component\Console\Style\SymfonyStyle;
|
|||
#[\Symfony\Component\Console\Attribute\AsCommand('partdb:users:enable|partdb:user:enable', 'Enables/Disable the login of one or more users')]
|
||||
class UserEnableCommand extends Command
|
||||
{
|
||||
protected EntityManagerInterface $entityManager;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, string $name = null)
|
||||
public function __construct(protected EntityManagerInterface $entityManager, string $name = null)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
|
||||
parent::__construct($name);
|
||||
}
|
||||
|
||||
|
@ -70,7 +66,7 @@ class UserEnableCommand extends Command
|
|||
} else { //Otherwise, fetch the users from DB
|
||||
foreach ($usernames as $username) {
|
||||
$user = $repo->findByEmailOrName($username);
|
||||
if ($user === null) {
|
||||
if (!$user instanceof \App\Entity\UserSystem\User) {
|
||||
$io->error('No user found with username: '.$username);
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
@ -84,9 +80,7 @@ class UserEnableCommand extends Command
|
|||
$io->note('The following users will be enabled:');
|
||||
}
|
||||
$io->table(['Username', 'Enabled/Disabled'],
|
||||
array_map(static function(User $user) {
|
||||
return [$user->getFullName(true), $user->isDisabled() ? 'Disabled' : 'Enabled'];
|
||||
}, $users));
|
||||
array_map(static fn(User $user) => [$user->getFullName(true), $user->isDisabled() ? 'Disabled' : 'Enabled'], $users));
|
||||
|
||||
if(!$io->confirm('Do you want to continue?')) {
|
||||
$io->warning('Aborting!');
|
||||
|
|
|
@ -31,12 +31,8 @@ use Symfony\Component\Console\Style\SymfonyStyle;
|
|||
#[\Symfony\Component\Console\Attribute\AsCommand('partdb:users:list|users:list', 'Lists all users')]
|
||||
class UserListCommand extends Command
|
||||
{
|
||||
protected EntityManagerInterface $entityManager;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
public function __construct(protected EntityManagerInterface $entityManager)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
|
@ -83,7 +79,7 @@ class UserListCommand extends Command
|
|||
$user->getUsername(),
|
||||
$user->getFullName(),
|
||||
$user->getEmail(),
|
||||
$user->getGroup() !== null ? $user->getGroup()->getName() . ' (ID: ' . $user->getGroup()->getID() . ')' : 'No group',
|
||||
$user->getGroup() instanceof \App\Entity\UserSystem\Group ? $user->getGroup()->getName() . ' (ID: ' . $user->getGroup()->getID() . ')' : 'No group',
|
||||
$user->isDisabled() ? 'Yes' : 'No',
|
||||
$user->isSAMLUser() ? 'SAML' : 'Local',
|
||||
]);
|
||||
|
|
|
@ -37,17 +37,11 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
#[\Symfony\Component\Console\Attribute\AsCommand('partdb:users:permissions|partdb:user:permissions', 'View and edit the permissions of a given user')]
|
||||
class UsersPermissionsCommand extends Command
|
||||
{
|
||||
protected EntityManagerInterface $entityManager;
|
||||
protected UserRepository $userRepository;
|
||||
protected PermissionManager $permissionResolver;
|
||||
protected TranslatorInterface $translator;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, PermissionManager $permissionResolver, TranslatorInterface $translator)
|
||||
public function __construct(protected EntityManagerInterface $entityManager, protected PermissionManager $permissionResolver, protected TranslatorInterface $translator)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->userRepository = $entityManager->getRepository(User::class);
|
||||
$this->permissionResolver = $permissionResolver;
|
||||
$this->translator = $translator;
|
||||
|
||||
parent::__construct(self::$defaultName);
|
||||
}
|
||||
|
@ -71,7 +65,7 @@ class UsersPermissionsCommand extends Command
|
|||
//Find user
|
||||
$io->note('Finding user with username: ' . $username);
|
||||
$user = $this->userRepository->findByEmailOrName($username);
|
||||
if ($user === null) {
|
||||
if (!$user instanceof \App\Entity\UserSystem\User) {
|
||||
$io->error('No user found with username: ' . $username);
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
@ -100,7 +94,7 @@ class UsersPermissionsCommand extends Command
|
|||
|
||||
|
||||
$new_value_str = $io->ask('Enter the new value for the permission (A = allow, D = disallow, I = inherit)');
|
||||
switch (strtolower($new_value_str)) {
|
||||
switch (strtolower((string) $new_value_str)) {
|
||||
case 'a':
|
||||
case 'allow':
|
||||
$new_value = true;
|
||||
|
@ -207,11 +201,11 @@ class UsersPermissionsCommand extends Command
|
|||
|
||||
if ($permission_value === true) {
|
||||
return '<fg=green>Allow</>';
|
||||
} else if ($permission_value === false) {
|
||||
} elseif ($permission_value === false) {
|
||||
return '<fg=red>Disallow</>';
|
||||
} else if ($permission_value === null && !$inherit) {
|
||||
} elseif ($permission_value === null && !$inherit) {
|
||||
return '<fg=blue>Inherit</>';
|
||||
} else if ($permission_value === null && $inherit) {
|
||||
} elseif ($permission_value === null && $inherit) {
|
||||
return '<fg=red>Disallow (Inherited)</>';
|
||||
}
|
||||
|
||||
|
|
|
@ -30,13 +30,8 @@ use Symfony\Component\Console\Style\SymfonyStyle;
|
|||
#[\Symfony\Component\Console\Attribute\AsCommand('partdb:version|app:version', 'Shows the currently installed version of Part-DB.')]
|
||||
class VersionCommand extends Command
|
||||
{
|
||||
protected VersionManagerInterface $versionManager;
|
||||
protected GitVersionInfo $gitVersionInfo;
|
||||
|
||||
public function __construct(VersionManagerInterface $versionManager, GitVersionInfo $gitVersionInfo)
|
||||
public function __construct(protected VersionManagerInterface $versionManager, protected GitVersionInfo $gitVersionInfo)
|
||||
{
|
||||
$this->versionManager = $versionManager;
|
||||
$this->gitVersionInfo = $gitVersionInfo;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
|
|
|
@ -72,29 +72,16 @@ abstract class BaseAdminController extends AbstractController
|
|||
protected string $route_base = '';
|
||||
protected string $attachment_class = '';
|
||||
protected ?string $parameter_class = '';
|
||||
|
||||
protected UserPasswordHasherInterface $passwordEncoder;
|
||||
protected TranslatorInterface $translator;
|
||||
protected AttachmentSubmitHandler $attachmentSubmitHandler;
|
||||
protected EventCommentHelper $commentHelper;
|
||||
|
||||
protected HistoryHelper $historyHelper;
|
||||
protected TimeTravel $timeTravel;
|
||||
protected DataTableFactory $dataTableFactory;
|
||||
/**
|
||||
* @var EventDispatcher|EventDispatcherInterface
|
||||
*/
|
||||
protected $eventDispatcher;
|
||||
protected LabelGenerator $labelGenerator;
|
||||
protected LabelExampleElementsGenerator $barcodeExampleGenerator;
|
||||
|
||||
protected EntityManagerInterface $entityManager;
|
||||
|
||||
public function __construct(TranslatorInterface $translator, UserPasswordHasherInterface $passwordEncoder,
|
||||
AttachmentSubmitHandler $attachmentSubmitHandler,
|
||||
EventCommentHelper $commentHelper, HistoryHelper $historyHelper, TimeTravel $timeTravel,
|
||||
DataTableFactory $dataTableFactory, EventDispatcherInterface $eventDispatcher, LabelExampleElementsGenerator $barcodeExampleGenerator,
|
||||
LabelGenerator $labelGenerator, EntityManagerInterface $entityManager)
|
||||
public function __construct(protected TranslatorInterface $translator, protected UserPasswordHasherInterface $passwordEncoder,
|
||||
protected AttachmentSubmitHandler $attachmentSubmitHandler,
|
||||
protected EventCommentHelper $commentHelper, protected HistoryHelper $historyHelper, protected TimeTravel $timeTravel,
|
||||
protected DataTableFactory $dataTableFactory, EventDispatcherInterface $eventDispatcher, protected LabelExampleElementsGenerator $barcodeExampleGenerator,
|
||||
protected LabelGenerator $labelGenerator, protected EntityManagerInterface $entityManager)
|
||||
{
|
||||
if ('' === $this->entity_class || '' === $this->form_class || '' === $this->twig_template || '' === $this->route_base) {
|
||||
throw new InvalidArgumentException('You have to override the $entity_class, $form_class, $route_base and $twig_template value in your subclasss!');
|
||||
|
@ -107,18 +94,7 @@ abstract class BaseAdminController extends AbstractController
|
|||
if ('' === $this->parameter_class || ($this->parameter_class && !is_a($this->parameter_class, AbstractParameter::class, true))) {
|
||||
throw new InvalidArgumentException('You have to override the $parameter_class value with a valid Parameter class in your subclass!');
|
||||
}
|
||||
|
||||
$this->translator = $translator;
|
||||
$this->passwordEncoder = $passwordEncoder;
|
||||
$this->attachmentSubmitHandler = $attachmentSubmitHandler;
|
||||
$this->commentHelper = $commentHelper;
|
||||
$this->historyHelper = $historyHelper;
|
||||
$this->timeTravel = $timeTravel;
|
||||
$this->dataTableFactory = $dataTableFactory;
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
$this->barcodeExampleGenerator = $barcodeExampleGenerator;
|
||||
$this->labelGenerator = $labelGenerator;
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
protected function revertElementIfNeeded(AbstractDBElement $entity, ?string $timestamp): ?DateTime
|
||||
|
@ -177,7 +153,7 @@ abstract class BaseAdminController extends AbstractController
|
|||
$form_options = [
|
||||
'attachment_class' => $this->attachment_class,
|
||||
'parameter_class' => $this->parameter_class,
|
||||
'disabled' => null !== $timeTravel_timestamp,
|
||||
'disabled' => $timeTravel_timestamp instanceof \DateTime,
|
||||
];
|
||||
|
||||
//Disable editing of options, if user is not allowed to use twig...
|
||||
|
@ -269,13 +245,7 @@ abstract class BaseAdminController extends AbstractController
|
|||
|
||||
protected function _new(Request $request, EntityManagerInterface $em, EntityImporter $importer, ?AbstractNamedDBElement $entity = null)
|
||||
{
|
||||
if (null === $entity) {
|
||||
/** @var AbstractStructuralDBElement|User $new_entity */
|
||||
$new_entity = new $this->entity_class();
|
||||
} else {
|
||||
/** @var AbstractStructuralDBElement|User $new_entity */
|
||||
$new_entity = clone $entity;
|
||||
}
|
||||
$new_entity = $entity instanceof \App\Entity\Base\AbstractNamedDBElement ? clone $entity : new $this->entity_class();
|
||||
|
||||
$this->denyAccessUnlessGranted('read', $new_entity);
|
||||
|
||||
|
@ -287,42 +257,37 @@ abstract class BaseAdminController extends AbstractController
|
|||
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
//Perform additional actions
|
||||
if ($this->additionalActionNew($form, $new_entity)) {
|
||||
//Upload passed files
|
||||
$attachments = $form['attachments'];
|
||||
foreach ($attachments as $attachment) {
|
||||
/** @var FormInterface $attachment */
|
||||
$options = [
|
||||
'secure_attachment' => $attachment['secureFile']->getData(),
|
||||
'download_url' => $attachment['downloadURL']->getData(),
|
||||
];
|
||||
//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 */
|
||||
$options = [
|
||||
'secure_attachment' => $attachment['secureFile']->getData(),
|
||||
'download_url' => $attachment['downloadURL']->getData(),
|
||||
];
|
||||
|
||||
try {
|
||||
$this->attachmentSubmitHandler->handleFormSubmit(
|
||||
$attachment->getData(),
|
||||
$attachment['file']->getData(),
|
||||
$options
|
||||
);
|
||||
} catch (AttachmentDownloadException $attachmentDownloadException) {
|
||||
$this->addFlash(
|
||||
'error',
|
||||
$this->translator->trans(
|
||||
'attachment.download_failed'
|
||||
).' '.$attachmentDownloadException->getMessage()
|
||||
);
|
||||
}
|
||||
try {
|
||||
$this->attachmentSubmitHandler->handleFormSubmit(
|
||||
$attachment->getData(),
|
||||
$attachment['file']->getData(),
|
||||
$options
|
||||
);
|
||||
} catch (AttachmentDownloadException $attachmentDownloadException) {
|
||||
$this->addFlash(
|
||||
'error',
|
||||
$this->translator->trans(
|
||||
'attachment.download_failed'
|
||||
).' '.$attachmentDownloadException->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
$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()]);
|
||||
}
|
||||
$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()]);
|
||||
}
|
||||
|
||||
if ($form->isSubmitted() && !$form->isValid()) {
|
||||
|
@ -369,7 +334,7 @@ abstract class BaseAdminController extends AbstractController
|
|||
}
|
||||
}
|
||||
}
|
||||
catch (UnexpectedValueException $e) {
|
||||
catch (UnexpectedValueException) {
|
||||
$this->addFlash('error', 'parts.import.flash.error.invalid_file');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,8 +64,6 @@ class CurrencyController extends BaseAdminController
|
|||
protected string $attachment_class = CurrencyAttachment::class;
|
||||
protected ?string $parameter_class = CurrencyParameter::class;
|
||||
|
||||
protected ExchangeRateUpdater $exchangeRateUpdater;
|
||||
|
||||
public function __construct(
|
||||
TranslatorInterface $translator,
|
||||
UserPasswordHasherInterface $passwordEncoder,
|
||||
|
@ -78,10 +76,8 @@ class CurrencyController extends BaseAdminController
|
|||
LabelExampleElementsGenerator $barcodeExampleGenerator,
|
||||
LabelGenerator $labelGenerator,
|
||||
EntityManagerInterface $entityManager,
|
||||
ExchangeRateUpdater $exchangeRateUpdater
|
||||
protected ExchangeRateUpdater $exchangeRateUpdater
|
||||
) {
|
||||
$this->exchangeRateUpdater = $exchangeRateUpdater;
|
||||
|
||||
parent::__construct(
|
||||
$translator,
|
||||
$passwordEncoder,
|
||||
|
|
|
@ -45,9 +45,6 @@ class ManufacturerController extends BaseAdminController
|
|||
protected string $attachment_class = ManufacturerAttachment::class;
|
||||
protected ?string $parameter_class = ManufacturerParameter::class;
|
||||
|
||||
/**
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
#[Route(path: '/{id}', name: 'manufacturer_delete', methods: ['DELETE'])]
|
||||
public function delete(Request $request, Manufacturer $entity, StructuralElementRecursionHelper $recursionHelper): RedirectResponse
|
||||
{
|
||||
|
|
|
@ -37,15 +37,8 @@ use Symfony\Contracts\Cache\CacheInterface;
|
|||
|
||||
class HomepageController extends AbstractController
|
||||
{
|
||||
protected CacheInterface $cache;
|
||||
protected KernelInterface $kernel;
|
||||
protected DataTableFactory $dataTable;
|
||||
|
||||
public function __construct(CacheInterface $cache, KernelInterface $kernel, DataTableFactory $dataTable)
|
||||
public function __construct(protected CacheInterface $cache, protected KernelInterface $kernel, protected DataTableFactory $dataTable)
|
||||
{
|
||||
$this->cache = $cache;
|
||||
$this->kernel = $kernel;
|
||||
$this->dataTable = $dataTable;
|
||||
}
|
||||
|
||||
public function getBanner(): string
|
||||
|
|
|
@ -62,20 +62,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
#[Route(path: '/label')]
|
||||
class LabelController extends AbstractController
|
||||
{
|
||||
protected LabelGenerator $labelGenerator;
|
||||
protected EntityManagerInterface $em;
|
||||
protected ElementTypeNameGenerator $elementTypeNameGenerator;
|
||||
protected RangeParser $rangeParser;
|
||||
protected TranslatorInterface $translator;
|
||||
|
||||
public function __construct(LabelGenerator $labelGenerator, EntityManagerInterface $em, ElementTypeNameGenerator $elementTypeNameGenerator,
|
||||
RangeParser $rangeParser, TranslatorInterface $translator)
|
||||
public function __construct(protected LabelGenerator $labelGenerator, protected EntityManagerInterface $em, protected ElementTypeNameGenerator $elementTypeNameGenerator, protected RangeParser $rangeParser, protected TranslatorInterface $translator)
|
||||
{
|
||||
$this->labelGenerator = $labelGenerator;
|
||||
$this->em = $em;
|
||||
$this->elementTypeNameGenerator = $elementTypeNameGenerator;
|
||||
$this->rangeParser = $rangeParser;
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
#[Route(path: '/dialog', name: 'label_dialog')]
|
||||
|
@ -85,15 +73,11 @@ class LabelController extends AbstractController
|
|||
$this->denyAccessUnlessGranted('@labels.create_labels');
|
||||
|
||||
//If we inherit a LabelProfile, the user need to have access to it...
|
||||
if (null !== $profile) {
|
||||
if ($profile instanceof \App\Entity\LabelSystem\LabelProfile) {
|
||||
$this->denyAccessUnlessGranted('read', $profile);
|
||||
}
|
||||
|
||||
if ($profile) {
|
||||
$label_options = $profile->getOptions();
|
||||
} else {
|
||||
$label_options = new LabelOptions();
|
||||
}
|
||||
$label_options = $profile instanceof \App\Entity\LabelSystem\LabelProfile ? $profile->getOptions() : new LabelOptions();
|
||||
|
||||
//We have to disable the options, if twig mode is selected and user is not allowed to use it.
|
||||
$disable_options = 'twig' === $label_options->getLinesMode() && !$this->isGranted('@labels.use_twig');
|
||||
|
@ -107,7 +91,7 @@ class LabelController extends AbstractController
|
|||
$target_id = $request->query->get('target_id', null);
|
||||
$generate = $request->query->getBoolean('generate', false);
|
||||
|
||||
if (null === $profile && is_string($target_type)) {
|
||||
if (!$profile instanceof \App\Entity\LabelSystem\LabelProfile && is_string($target_type)) {
|
||||
$label_options->setSupportedElement($target_type);
|
||||
}
|
||||
if (is_string($target_id)) {
|
||||
|
@ -124,10 +108,10 @@ class LabelController extends AbstractController
|
|||
$filename = 'invalid.pdf';
|
||||
|
||||
//Generate PDF either when the form is submitted and valid, or the form was not submit yet, and generate is set
|
||||
if (($form->isSubmitted() && $form->isValid()) || ($generate && !$form->isSubmitted() && null !== $profile)) {
|
||||
if (($form->isSubmitted() && $form->isValid()) || ($generate && !$form->isSubmitted() && $profile instanceof \App\Entity\LabelSystem\LabelProfile)) {
|
||||
$target_id = (string) $form->get('target_id')->getData();
|
||||
$targets = $this->findObjects($form_options->getSupportedElement(), $target_id);
|
||||
if (!empty($targets)) {
|
||||
if ($targets !== []) {
|
||||
try {
|
||||
$pdf_data = $this->labelGenerator->generateLabel($form_options, $targets);
|
||||
$filename = $this->getLabelName($targets[0], $profile);
|
||||
|
|
|
@ -52,20 +52,13 @@ use Symfony\Component\Routing\Annotation\Route;
|
|||
#[Route(path: '/log')]
|
||||
class LogController extends AbstractController
|
||||
{
|
||||
protected EntityManagerInterface $entityManager;
|
||||
protected TimeTravel $timeTravel;
|
||||
protected DBElementRepository $dbRepository;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, TimeTravel $timeTravel)
|
||||
public function __construct(protected EntityManagerInterface $entityManager, protected TimeTravel $timeTravel)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->timeTravel = $timeTravel;
|
||||
$this->dbRepository = $entityManager->getRepository(AbstractDBElement::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
#[Route(path: '/', name: 'log_view')]
|
||||
public function showLogs(Request $request, DataTableFactory $dataTable): Response
|
||||
{
|
||||
|
@ -96,8 +89,6 @@ class LogController extends AbstractController
|
|||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param AbstractLogEntry $logEntry
|
||||
* @return Response
|
||||
*/
|
||||
#[Route(path: '/{id}/details', name: 'log_details')]
|
||||
public function logDetails(AbstractLogEntry $logEntry, LogEntryExtraFormatter $logEntryExtraFormatter,
|
||||
|
@ -150,7 +141,7 @@ class LogController extends AbstractController
|
|||
}
|
||||
|
||||
$log_element = $this->entityManager->find(AbstractLogEntry::class, $id);
|
||||
if (null === $log_element) {
|
||||
if (!$log_element instanceof \App\Entity\LogSystem\AbstractLogEntry) {
|
||||
throw new InvalidArgumentException('No log entry with the given ID is existing!');
|
||||
}
|
||||
|
||||
|
|
|
@ -62,16 +62,8 @@ use function Symfony\Component\Translation\t;
|
|||
#[Route(path: '/part')]
|
||||
class PartController extends AbstractController
|
||||
{
|
||||
protected PricedetailHelper $pricedetailHelper;
|
||||
protected PartPreviewGenerator $partPreviewGenerator;
|
||||
protected EventCommentHelper $commentHelper;
|
||||
|
||||
public function __construct(PricedetailHelper $pricedetailHelper,
|
||||
PartPreviewGenerator $partPreviewGenerator, EventCommentHelper $commentHelper)
|
||||
public function __construct(protected PricedetailHelper $pricedetailHelper, protected PartPreviewGenerator $partPreviewGenerator, protected EventCommentHelper $commentHelper)
|
||||
{
|
||||
$this->pricedetailHelper = $pricedetailHelper;
|
||||
$this->partPreviewGenerator = $partPreviewGenerator;
|
||||
$this->commentHelper = $commentHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -218,11 +210,13 @@ class PartController extends AbstractController
|
|||
?Part $part = null, ?Project $project = null): Response
|
||||
{
|
||||
|
||||
if ($part) { //Clone part
|
||||
if ($part instanceof \App\Entity\Parts\Part) {
|
||||
//Clone part
|
||||
$new_part = clone $part;
|
||||
} else if ($project) { //Initialize a new part for a build part from the given project
|
||||
} elseif ($project instanceof \App\Entity\ProjectSystem\Project) {
|
||||
//Initialize a new part for a build part from the given project
|
||||
//Ensure that the project has not already a build part
|
||||
if ($project->getBuildPart() !== null) {
|
||||
if ($project->getBuildPart() instanceof \App\Entity\Parts\Part) {
|
||||
$this->addFlash('error', 'part.new_build_part.error.build_part_already_exists');
|
||||
return $this->redirectToRoute('part_edit', ['id' => $project->getBuildPart()->getID()]);
|
||||
}
|
||||
|
@ -235,7 +229,7 @@ class PartController extends AbstractController
|
|||
|
||||
$cid = $request->get('category', null);
|
||||
$category = $cid ? $em->find(Category::class, $cid) : null;
|
||||
if (null !== $category && null === $new_part->getCategory()) {
|
||||
if ($category instanceof \App\Entity\Parts\Category && !$new_part->getCategory() instanceof \App\Entity\Parts\Category) {
|
||||
$new_part->setCategory($category);
|
||||
$new_part->setDescription($category->getDefaultDescription());
|
||||
$new_part->setComment($category->getDefaultComment());
|
||||
|
@ -243,19 +237,19 @@ class PartController extends AbstractController
|
|||
|
||||
$fid = $request->get('footprint', null);
|
||||
$footprint = $fid ? $em->find(Footprint::class, $fid) : null;
|
||||
if (null !== $footprint && null === $new_part->getFootprint()) {
|
||||
if ($footprint instanceof \App\Entity\Parts\Footprint && !$new_part->getFootprint() instanceof \App\Entity\Parts\Footprint) {
|
||||
$new_part->setFootprint($footprint);
|
||||
}
|
||||
|
||||
$mid = $request->get('manufacturer', null);
|
||||
$manufacturer = $mid ? $em->find(Manufacturer::class, $mid) : null;
|
||||
if (null !== $manufacturer && null === $new_part->getManufacturer()) {
|
||||
if ($manufacturer instanceof \App\Entity\Parts\Manufacturer && !$new_part->getManufacturer() instanceof \App\Entity\Parts\Manufacturer) {
|
||||
$new_part->setManufacturer($manufacturer);
|
||||
}
|
||||
|
||||
$store_id = $request->get('storelocation', null);
|
||||
$storelocation = $store_id ? $em->find(Storelocation::class, $store_id) : null;
|
||||
if (null !== $storelocation && $new_part->getPartLots()->isEmpty()) {
|
||||
if ($storelocation instanceof \App\Entity\Parts\Storelocation && $new_part->getPartLots()->isEmpty()) {
|
||||
$partLot = new PartLot();
|
||||
$partLot->setStorageLocation($storelocation);
|
||||
$partLot->setInstockUnknown(true);
|
||||
|
@ -264,7 +258,7 @@ class PartController extends AbstractController
|
|||
|
||||
$supplier_id = $request->get('supplier', null);
|
||||
$supplier = $supplier_id ? $em->find(Supplier::class, $supplier_id) : null;
|
||||
if (null !== $supplier && $new_part->getOrderdetails()->isEmpty()) {
|
||||
if ($supplier instanceof \App\Entity\Parts\Supplier && $new_part->getOrderdetails()->isEmpty()) {
|
||||
$orderdetail = new Orderdetail();
|
||||
$orderdetail->setSupplier($supplier);
|
||||
$new_part->addOrderdetail($orderdetail);
|
||||
|
@ -335,7 +329,7 @@ class PartController extends AbstractController
|
|||
if ($this->isCsrfTokenValid('part_withraw' . $part->getID(), $request->request->get('_csfr'))) {
|
||||
//Retrieve partlot from the request
|
||||
$partLot = $em->find(PartLot::class, $request->request->get('lot_id'));
|
||||
if($partLot === null) {
|
||||
if(!$partLot instanceof \App\Entity\Parts\PartLot) {
|
||||
throw new \RuntimeException('Part lot not found!');
|
||||
}
|
||||
//Ensure that the partlot belongs to the part
|
||||
|
@ -375,7 +369,7 @@ class PartController extends AbstractController
|
|||
default:
|
||||
throw new \RuntimeException("Unknown action!");
|
||||
}
|
||||
} catch (AccessDeniedException $exception) {
|
||||
} catch (AccessDeniedException) {
|
||||
$this->addFlash('error', t('part.withdraw.access_denied'));
|
||||
goto err;
|
||||
}
|
||||
|
|
|
@ -36,22 +36,10 @@ use UnexpectedValueException;
|
|||
|
||||
class PartImportExportController extends AbstractController
|
||||
{
|
||||
private PartsTableActionHandler $partsTableActionHandler;
|
||||
private EntityImporter $entityImporter;
|
||||
private EventCommentHelper $commentHelper;
|
||||
|
||||
public function __construct(PartsTableActionHandler $partsTableActionHandler,
|
||||
EntityImporter $entityImporter, EventCommentHelper $commentHelper)
|
||||
public function __construct(private readonly PartsTableActionHandler $partsTableActionHandler, private readonly EntityImporter $entityImporter, private readonly EventCommentHelper $commentHelper)
|
||||
{
|
||||
$this->partsTableActionHandler = $partsTableActionHandler;
|
||||
$this->entityImporter = $entityImporter;
|
||||
$this->commentHelper = $commentHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
#[Route(path: '/parts/import', name: 'parts_import')]
|
||||
public function importParts(Request $request): Response
|
||||
{
|
||||
|
@ -116,16 +104,13 @@ class PartImportExportController extends AbstractController
|
|||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
#[Route(path: '/parts/export', name: 'parts_export', methods: ['GET'])]
|
||||
public function exportParts(Request $request, EntityExporter $entityExporter): Response
|
||||
{
|
||||
$ids = $request->query->get('ids', '');
|
||||
$parts = $this->partsTableActionHandler->idStringToArray($ids);
|
||||
|
||||
if (empty($parts)) {
|
||||
if ($parts === []) {
|
||||
throw new \RuntimeException('No parts found!');
|
||||
}
|
||||
|
||||
|
|
|
@ -48,18 +48,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
|
||||
class PartListsController extends AbstractController
|
||||
{
|
||||
private EntityManagerInterface $entityManager;
|
||||
private NodesListBuilder $nodesListBuilder;
|
||||
private DataTableFactory $dataTableFactory;
|
||||
|
||||
private TranslatorInterface $translator;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, NodesListBuilder $nodesListBuilder, DataTableFactory $dataTableFactory, TranslatorInterface $translator)
|
||||
public function __construct(private readonly EntityManagerInterface $entityManager, private readonly NodesListBuilder $nodesListBuilder, private readonly DataTableFactory $dataTableFactory, private readonly TranslatorInterface $translator)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->nodesListBuilder = $nodesListBuilder;
|
||||
$this->dataTableFactory = $dataTableFactory;
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
#[Route(path: '/table/action', name: 'table_action', methods: ['POST'])]
|
||||
|
@ -100,8 +90,6 @@ class PartListsController extends AbstractController
|
|||
|
||||
/**
|
||||
* Disable the given form interface after creation of the form by removing and reattaching the form.
|
||||
* @param FormInterface $form
|
||||
* @return void
|
||||
*/
|
||||
private function disableFormFieldAfterCreation(FormInterface $form, bool $disabled = true): void
|
||||
{
|
||||
|
@ -109,12 +97,12 @@ class PartListsController extends AbstractController
|
|||
$attrs['disabled'] = $disabled;
|
||||
|
||||
$parent = $form->getParent();
|
||||
if ($parent === null) {
|
||||
if (!$parent instanceof \Symfony\Component\Form\FormInterface) {
|
||||
throw new \RuntimeException('This function can only be used on form fields that are children of another form!');
|
||||
}
|
||||
|
||||
$parent->remove($form->getName());
|
||||
$parent->add($form->getName(), get_class($form->getConfig()->getType()->getInnerType()), $attrs);
|
||||
$parent->add($form->getName(), $form->getConfig()->getType()->getInnerType()::class, $attrs);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -125,7 +113,6 @@ class PartListsController extends AbstractController
|
|||
* @param callable|null $form_changer A function that is called with the form object as parameter. This function can be used to customize the form
|
||||
* @param array $additonal_template_vars Any additional template variables that should be passed to the template
|
||||
* @param array $additional_table_vars Any additional variables that should be passed to the table creation
|
||||
* @return Response
|
||||
*/
|
||||
protected function showListWithFilter(Request $request, string $template, ?callable $filter_changer = null, ?callable $form_changer = null, array $additonal_template_vars = [], array $additional_table_vars = []): Response
|
||||
{
|
||||
|
@ -172,9 +159,6 @@ class PartListsController extends AbstractController
|
|||
], $additonal_template_vars));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JsonResponse|Response
|
||||
*/
|
||||
#[Route(path: '/category/{id}/parts', name: 'part_list_category')]
|
||||
public function showCategory(Category $category, Request $request): Response
|
||||
{
|
||||
|
@ -193,9 +177,6 @@ class PartListsController extends AbstractController
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JsonResponse|Response
|
||||
*/
|
||||
#[Route(path: '/footprint/{id}/parts', name: 'part_list_footprint')]
|
||||
public function showFootprint(Footprint $footprint, Request $request): Response
|
||||
{
|
||||
|
@ -214,9 +195,6 @@ class PartListsController extends AbstractController
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JsonResponse|Response
|
||||
*/
|
||||
#[Route(path: '/manufacturer/{id}/parts', name: 'part_list_manufacturer')]
|
||||
public function showManufacturer(Manufacturer $manufacturer, Request $request): Response
|
||||
{
|
||||
|
@ -235,9 +213,6 @@ class PartListsController extends AbstractController
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JsonResponse|Response
|
||||
*/
|
||||
#[Route(path: '/store_location/{id}/parts', name: 'part_list_store_location')]
|
||||
public function showStorelocation(Storelocation $storelocation, Request $request): Response
|
||||
{
|
||||
|
@ -256,9 +231,6 @@ class PartListsController extends AbstractController
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JsonResponse|Response
|
||||
*/
|
||||
#[Route(path: '/supplier/{id}/parts', name: 'part_list_supplier')]
|
||||
public function showSupplier(Supplier $supplier, Request $request): Response
|
||||
{
|
||||
|
@ -277,9 +249,6 @@ class PartListsController extends AbstractController
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JsonResponse|Response
|
||||
*/
|
||||
#[Route(path: '/parts/by_tag/{tag}', name: 'part_list_tags', requirements: ['tag' => '.*'])]
|
||||
public function showTag(string $tag, Request $request): Response
|
||||
{
|
||||
|
@ -321,9 +290,6 @@ class PartListsController extends AbstractController
|
|||
return $filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JsonResponse|Response
|
||||
*/
|
||||
#[Route(path: '/parts/search', name: 'parts_search')]
|
||||
public function showSearch(Request $request, DataTableFactory $dataTable): Response
|
||||
{
|
||||
|
@ -343,9 +309,6 @@ class PartListsController extends AbstractController
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
#[Route(path: '/parts', name: 'parts_show_all')]
|
||||
public function showAll(Request $request): Response
|
||||
{
|
||||
|
|
|
@ -50,11 +50,8 @@ use function Symfony\Component\Translation\t;
|
|||
#[Route(path: '/project')]
|
||||
class ProjectController extends AbstractController
|
||||
{
|
||||
private DataTableFactory $dataTableFactory;
|
||||
|
||||
public function __construct(DataTableFactory $dataTableFactory)
|
||||
public function __construct(private readonly DataTableFactory $dataTableFactory)
|
||||
{
|
||||
$this->dataTableFactory = $dataTableFactory;
|
||||
}
|
||||
|
||||
#[Route(path: '/{id}/info', name: 'project_info', requirements: ['id' => '\d+'])]
|
||||
|
@ -180,9 +177,7 @@ class ProjectController extends AbstractController
|
|||
if (count ($errors) > 0) {
|
||||
$this->addFlash('error', t('project.bom_import.flash.invalid_entries'));
|
||||
}
|
||||
} catch (\UnexpectedValueException $e) {
|
||||
$this->addFlash('error', t('project.bom_import.flash.invalid_file', ['%message%' => $e->getMessage()]));
|
||||
} catch (SyntaxError $e) {
|
||||
} catch (\UnexpectedValueException|SyntaxError $e) {
|
||||
$this->addFlash('error', t('project.bom_import.flash.invalid_file', ['%message%' => $e->getMessage()]));
|
||||
}
|
||||
}
|
||||
|
@ -194,15 +189,11 @@ class ProjectController extends AbstractController
|
|||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Project|null $project
|
||||
*/
|
||||
#[Route(path: '/add_parts', name: 'project_add_parts_no_id')]
|
||||
#[Route(path: '/{id}/add_parts', name: 'project_add_parts', requirements: ['id' => '\d+'])]
|
||||
public function addPart(Request $request, EntityManagerInterface $entityManager, ?Project $project): Response
|
||||
{
|
||||
if($project) {
|
||||
if($project instanceof \App\Entity\ProjectSystem\Project) {
|
||||
$this->denyAccessUnlessGranted('edit', $project);
|
||||
} else {
|
||||
$this->denyAccessUnlessGranted('@projects.edit');
|
||||
|
@ -212,7 +203,7 @@ class ProjectController extends AbstractController
|
|||
$builder->add('project', StructuralEntityType::class, [
|
||||
'class' => Project::class,
|
||||
'required' => true,
|
||||
'disabled' => $project !== null, //If a project is given, disable the field
|
||||
'disabled' => $project instanceof \App\Entity\ProjectSystem\Project, //If a project is given, disable the field
|
||||
'data' => $project,
|
||||
'constraints' => [
|
||||
new NotNull()
|
||||
|
@ -224,7 +215,7 @@ class ProjectController extends AbstractController
|
|||
|
||||
//Preset the BOM entries with the selected parts, when the form was not submitted yet
|
||||
$preset_data = new ArrayCollection();
|
||||
foreach (explode(',', $request->get('parts', '')) as $part_id) {
|
||||
foreach (explode(',', (string) $request->get('parts', '')) as $part_id) {
|
||||
$part = $entityManager->getRepository(Part::class)->find($part_id);
|
||||
if (null !== $part) {
|
||||
//If there is already a BOM entry for this part, we use this one (we edit it then)
|
||||
|
|
|
@ -32,15 +32,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
|
||||
class RedirectController extends AbstractController
|
||||
{
|
||||
protected string $default_locale;
|
||||
protected TranslatorInterface $translator;
|
||||
protected bool $enforce_index_php;
|
||||
|
||||
public function __construct(string $default_locale, TranslatorInterface $translator, bool $enforce_index_php)
|
||||
public function __construct(protected string $default_locale, protected TranslatorInterface $translator, protected bool $enforce_index_php)
|
||||
{
|
||||
$this->default_locale = $default_locale;
|
||||
$this->translator = $translator;
|
||||
$this->enforce_index_php = $enforce_index_php;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -54,13 +54,8 @@ use Symfony\Component\Routing\Annotation\Route;
|
|||
#[Route(path: '/scan')]
|
||||
class ScanController extends AbstractController
|
||||
{
|
||||
protected BarcodeRedirector $barcodeParser;
|
||||
protected BarcodeNormalizer $barcodeNormalizer;
|
||||
|
||||
public function __construct(BarcodeRedirector $barcodeParser, BarcodeNormalizer $barcodeNormalizer)
|
||||
public function __construct(protected BarcodeRedirector $barcodeParser, protected BarcodeNormalizer $barcodeNormalizer)
|
||||
{
|
||||
$this->barcodeParser = $barcodeParser;
|
||||
$this->barcodeNormalizer = $barcodeNormalizer;
|
||||
}
|
||||
|
||||
#[Route(path: '', name: 'scan_dialog')]
|
||||
|
@ -79,10 +74,10 @@ class ScanController extends AbstractController
|
|||
|
||||
try {
|
||||
return $this->redirect($this->barcodeParser->getRedirectURL($type, $id));
|
||||
} catch (EntityNotFoundException $exception) {
|
||||
} catch (EntityNotFoundException) {
|
||||
$this->addFlash('success', 'scan.qr_not_found');
|
||||
}
|
||||
} catch (InvalidArgumentException $exception) {
|
||||
} catch (InvalidArgumentException) {
|
||||
$this->addFlash('error', 'scan.format_unknown');
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +96,7 @@ class ScanController extends AbstractController
|
|||
$this->addFlash('success', 'scan.qr_success');
|
||||
|
||||
return $this->redirect($this->barcodeParser->getRedirectURL($type, $id));
|
||||
} catch (EntityNotFoundException $exception) {
|
||||
} catch (EntityNotFoundException) {
|
||||
$this->addFlash('success', 'scan.qr_not_found');
|
||||
|
||||
return $this->redirectToRoute('homepage');
|
||||
|
|
|
@ -48,13 +48,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
|
||||
class SecurityController extends AbstractController
|
||||
{
|
||||
protected TranslatorInterface $translator;
|
||||
protected bool $allow_email_pw_reset;
|
||||
|
||||
public function __construct(TranslatorInterface $translator, bool $allow_email_pw_reset)
|
||||
public function __construct(protected TranslatorInterface $translator, protected bool $allow_email_pw_reset)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
$this->allow_email_pw_reset = $allow_email_pw_reset;
|
||||
}
|
||||
|
||||
#[Route(path: '/login', name: 'login', methods: ['GET', 'POST'])]
|
||||
|
@ -76,7 +71,7 @@ class SecurityController extends AbstractController
|
|||
* @return RedirectResponse|Response
|
||||
*/
|
||||
#[Route(path: '/pw_reset/request', name: 'pw_reset_request')]
|
||||
public function requestPwReset(PasswordResetManager $passwordReset, Request $request)
|
||||
public function requestPwReset(PasswordResetManager $passwordReset, Request $request): \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
|
||||
{
|
||||
if (!$this->allow_email_pw_reset) {
|
||||
throw new AccessDeniedHttpException('The password reset via email is disabled!');
|
||||
|
@ -119,7 +114,7 @@ class SecurityController extends AbstractController
|
|||
* @return RedirectResponse|Response
|
||||
*/
|
||||
#[Route(path: '/pw_reset/new_pw/{user}/{token}', name: 'pw_reset_new_pw')]
|
||||
public function pwResetNewPw(PasswordResetManager $passwordReset, Request $request, EntityManagerInterface $em, EventDispatcherInterface $eventDispatcher, ?string $user = null, ?string $token = null)
|
||||
public function pwResetNewPw(PasswordResetManager $passwordReset, Request $request, EntityManagerInterface $em, EventDispatcherInterface $eventDispatcher, ?string $user = null, ?string $token = null): \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
|
||||
{
|
||||
if (!$this->allow_email_pw_reset) {
|
||||
throw new AccessDeniedHttpException('The password reset via email is disabled!');
|
||||
|
@ -189,7 +184,7 @@ class SecurityController extends AbstractController
|
|||
}
|
||||
|
||||
#[Route(path: '/logout', name: 'logout')]
|
||||
public function logout(): void
|
||||
public function logout(): never
|
||||
{
|
||||
throw new RuntimeException('Will be intercepted before getting here');
|
||||
}
|
||||
|
|
|
@ -42,15 +42,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
#[Route(path: '/select_api')]
|
||||
class SelectAPIController extends AbstractController
|
||||
{
|
||||
private NodesListBuilder $nodesListBuilder;
|
||||
private TranslatorInterface $translator;
|
||||
private StructuralEntityChoiceHelper $choiceHelper;
|
||||
|
||||
public function __construct(NodesListBuilder $nodesListBuilder, TranslatorInterface $translator, StructuralEntityChoiceHelper $choiceHelper)
|
||||
public function __construct(private readonly NodesListBuilder $nodesListBuilder, private readonly TranslatorInterface $translator, private readonly StructuralEntityChoiceHelper $choiceHelper)
|
||||
{
|
||||
$this->nodesListBuilder = $nodesListBuilder;
|
||||
$this->translator = $translator;
|
||||
$this->choiceHelper = $choiceHelper;
|
||||
}
|
||||
|
||||
#[Route(path: '/category', name: 'select_category')]
|
||||
|
@ -92,17 +85,12 @@ class SelectAPIController extends AbstractController
|
|||
3 => $this->translator->trans('export.level.full'),
|
||||
];
|
||||
|
||||
return $this->json(array_map(static function ($key, $value) {
|
||||
return [
|
||||
'text' => $value,
|
||||
'value' => $key,
|
||||
];
|
||||
}, array_keys($entries), $entries));
|
||||
return $this->json(array_map(static fn($key, $value) => [
|
||||
'text' => $value,
|
||||
'value' => $key,
|
||||
], array_keys($entries), $entries));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
#[Route(path: '/label_profiles', name: 'select_label_profiles')]
|
||||
public function labelProfiles(EntityManagerInterface $entityManager): Response
|
||||
{
|
||||
|
@ -121,9 +109,6 @@ class SelectAPIController extends AbstractController
|
|||
return $this->json($nodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
#[Route(path: '/label_profiles_lot', name: 'select_label_profiles_lot')]
|
||||
public function labelProfilesLot(EntityManagerInterface $entityManager): Response
|
||||
{
|
||||
|
|
|
@ -77,7 +77,7 @@ class ToolsController extends AbstractController
|
|||
'php_version' => PHP_VERSION,
|
||||
'php_uname' => php_uname('a'),
|
||||
'php_sapi' => PHP_SAPI,
|
||||
'php_extensions' => array_merge(get_loaded_extensions()),
|
||||
'php_extensions' => [...get_loaded_extensions()],
|
||||
'php_opcache_enabled' => ini_get('opcache.enable'),
|
||||
'php_upload_max_filesize' => ini_get('upload_max_filesize'),
|
||||
'php_post_max_size' => ini_get('post_max_size'),
|
||||
|
@ -91,32 +91,22 @@ class ToolsController extends AbstractController
|
|||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
#[Route(path: '/builtin_footprints', name: 'tools_builtin_footprints_viewer')]
|
||||
public function builtInFootprintsViewer(BuiltinAttachmentsFinder $builtinAttachmentsFinder, AttachmentURLGenerator $urlGenerator): Response
|
||||
{
|
||||
$this->denyAccessUnlessGranted('@tools.builtin_footprints_viewer');
|
||||
|
||||
$grouped_footprints = $builtinAttachmentsFinder->getListOfFootprintsGroupedByFolder();
|
||||
$grouped_footprints = array_map(function($group) use ($urlGenerator) {
|
||||
return array_map(function($placeholder_filepath) use ($urlGenerator) {
|
||||
return [
|
||||
'filename' => basename($placeholder_filepath),
|
||||
'assets_path' => $urlGenerator->placeholderPathToAssetPath($placeholder_filepath),
|
||||
];
|
||||
}, $group);
|
||||
}, $grouped_footprints);
|
||||
$grouped_footprints = array_map(fn($group) => array_map(fn($placeholder_filepath) => [
|
||||
'filename' => basename((string) $placeholder_filepath),
|
||||
'assets_path' => $urlGenerator->placeholderPathToAssetPath($placeholder_filepath),
|
||||
], $group), $grouped_footprints);
|
||||
|
||||
return $this->render('tools/builtin_footprints_viewer/builtin_footprints_viewer.html.twig', [
|
||||
'grouped_footprints' => $grouped_footprints,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
#[Route(path: '/ic_logos', name: 'tools_ic_logos')]
|
||||
public function icLogos(): Response
|
||||
{
|
||||
|
|
|
@ -40,11 +40,8 @@ use Symfony\Component\Routing\Annotation\Route;
|
|||
#[Route(path: '/tree')]
|
||||
class TreeController extends AbstractController
|
||||
{
|
||||
protected TreeViewGenerator $treeGenerator;
|
||||
|
||||
public function __construct(TreeViewGenerator $treeGenerator)
|
||||
public function __construct(protected TreeViewGenerator $treeGenerator)
|
||||
{
|
||||
$this->treeGenerator = $treeGenerator;
|
||||
}
|
||||
|
||||
#[Route(path: '/tools', name: 'tree_tools')]
|
||||
|
|
|
@ -55,13 +55,8 @@ use Symfony\Component\Serializer\Serializer;
|
|||
#[Route(path: '/typeahead')]
|
||||
class TypeaheadController extends AbstractController
|
||||
{
|
||||
protected AttachmentURLGenerator $urlGenerator;
|
||||
protected Packages $assets;
|
||||
|
||||
public function __construct(AttachmentURLGenerator $URLGenerator, Packages $assets)
|
||||
public function __construct(protected AttachmentURLGenerator $urlGenerator, protected Packages $assets)
|
||||
{
|
||||
$this->urlGenerator = $URLGenerator;
|
||||
$this->assets = $assets;
|
||||
}
|
||||
|
||||
#[Route(path: '/builtInResources/search', name: 'typeahead_builtInRessources')]
|
||||
|
@ -93,45 +88,26 @@ class TypeaheadController extends AbstractController
|
|||
|
||||
/**
|
||||
* This function map the parameter type to the class, so we can access its repository
|
||||
* @param string $type
|
||||
* @return class-string
|
||||
*/
|
||||
private function typeToParameterClass(string $type): string
|
||||
{
|
||||
switch ($type) {
|
||||
case 'category':
|
||||
return CategoryParameter::class;
|
||||
case 'part':
|
||||
return PartParameter::class;
|
||||
case 'device':
|
||||
return ProjectParameter::class;
|
||||
case 'footprint':
|
||||
return FootprintParameter::class;
|
||||
case 'manufacturer':
|
||||
return ManufacturerParameter::class;
|
||||
case 'storelocation':
|
||||
return StorelocationParameter::class;
|
||||
case 'supplier':
|
||||
return SupplierParameter::class;
|
||||
case 'attachment_type':
|
||||
return AttachmentTypeParameter::class;
|
||||
case 'group':
|
||||
return GroupParameter::class;
|
||||
case 'measurement_unit':
|
||||
return MeasurementUnitParameter::class;
|
||||
case 'currency':
|
||||
return Currency::class;
|
||||
|
||||
default:
|
||||
throw new \InvalidArgumentException('Invalid parameter type: '.$type);
|
||||
}
|
||||
return match ($type) {
|
||||
'category' => CategoryParameter::class,
|
||||
'part' => PartParameter::class,
|
||||
'device' => ProjectParameter::class,
|
||||
'footprint' => FootprintParameter::class,
|
||||
'manufacturer' => ManufacturerParameter::class,
|
||||
'storelocation' => StorelocationParameter::class,
|
||||
'supplier' => SupplierParameter::class,
|
||||
'attachment_type' => AttachmentTypeParameter::class,
|
||||
'group' => GroupParameter::class,
|
||||
'measurement_unit' => MeasurementUnitParameter::class,
|
||||
'currency' => Currency::class,
|
||||
default => throw new \InvalidArgumentException('Invalid parameter type: '.$type),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param EntityManagerInterface $entityManager
|
||||
* @return JsonResponse
|
||||
*/
|
||||
#[Route(path: '/parts/search/{query}', name: 'typeahead_parts')]
|
||||
public function parts(EntityManagerInterface $entityManager, PartPreviewGenerator $previewGenerator,
|
||||
AttachmentURLGenerator $attachmentURLGenerator, string $query = ""): JsonResponse
|
||||
|
@ -146,7 +122,7 @@ class TypeaheadController extends AbstractController
|
|||
foreach ($parts as $part) {
|
||||
//Determine the picture to show:
|
||||
$preview_attachment = $previewGenerator->getTablePreviewAttachment($part);
|
||||
if($preview_attachment !== null) {
|
||||
if($preview_attachment instanceof \App\Entity\Attachments\Attachment) {
|
||||
$preview_url = $attachmentURLGenerator->getThumbnailURL($preview_attachment, 'thumbnail_sm');
|
||||
} else {
|
||||
$preview_url = '';
|
||||
|
@ -156,8 +132,8 @@ class TypeaheadController extends AbstractController
|
|||
$data[] = [
|
||||
'id' => $part->getID(),
|
||||
'name' => $part->getName(),
|
||||
'category' => $part->getCategory() ? $part->getCategory()->getName() : 'Unknown',
|
||||
'footprint' => $part->getFootprint() ? $part->getFootprint()->getName() : '',
|
||||
'category' => $part->getCategory() instanceof \App\Entity\Parts\Category ? $part->getCategory()->getName() : 'Unknown',
|
||||
'footprint' => $part->getFootprint() instanceof \App\Entity\Parts\Footprint ? $part->getFootprint()->getName() : '',
|
||||
'description' => mb_strimwidth($part->getDescription(), 0, 127, '...'),
|
||||
'image' => $preview_url,
|
||||
];
|
||||
|
@ -166,10 +142,6 @@ class TypeaheadController extends AbstractController
|
|||
return new JsonResponse($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @return JsonResponse
|
||||
*/
|
||||
#[Route(path: '/parameters/{type}/search/{query}', name: 'typeahead_parameters', requirements: ['type' => '.+'])]
|
||||
public function parameters(string $type, EntityManagerInterface $entityManager, string $query = ""): JsonResponse
|
||||
{
|
||||
|
|
|
@ -180,7 +180,7 @@ class UserController extends AdminPages\BaseAdminController
|
|||
public function userInfo(?User $user, Packages $packages, Request $request, DataTableFactory $dataTableFactory): Response
|
||||
{
|
||||
//If no user id was passed, then we show info about the current user
|
||||
if (null === $user) {
|
||||
if (!$user instanceof \App\Entity\UserSystem\User) {
|
||||
$tmp = $this->getUser();
|
||||
if (!$tmp instanceof User) {
|
||||
throw new InvalidArgumentException('Userinfo only works for database users!');
|
||||
|
|
|
@ -54,16 +54,13 @@ use Symfony\Component\Validator\Constraints\Length;
|
|||
#[Route(path: '/user')]
|
||||
class UserSettingsController extends AbstractController
|
||||
{
|
||||
protected bool $demo_mode;
|
||||
|
||||
/**
|
||||
* @var EventDispatcher|EventDispatcherInterface
|
||||
*/
|
||||
protected $eventDispatcher;
|
||||
|
||||
public function __construct(bool $demo_mode, EventDispatcherInterface $eventDispatcher)
|
||||
public function __construct(protected bool $demo_mode, EventDispatcherInterface $eventDispatcher)
|
||||
{
|
||||
$this->demo_mode = $demo_mode;
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
}
|
||||
|
||||
|
@ -121,49 +118,43 @@ class UserSettingsController extends AbstractController
|
|||
$key_repo = $entityManager->getRepository(U2FKey::class);
|
||||
/** @var U2FKey|null $u2f */
|
||||
$u2f = $key_repo->find($key_id);
|
||||
if (null === $u2f) {
|
||||
if (!$u2f instanceof \App\Entity\UserSystem\U2FKey) {
|
||||
$this->addFlash('danger', 'tfa_u2f.u2f_delete.not_existing');
|
||||
|
||||
return $this->redirectToRoute('user_settings');
|
||||
}
|
||||
|
||||
//User can only delete its own U2F keys
|
||||
if ($u2f->getUser() !== $user) {
|
||||
$this->addFlash('danger', 'tfa_u2f.u2f_delete.access_denied');
|
||||
|
||||
return $this->redirectToRoute('user_settings');
|
||||
}
|
||||
|
||||
$backupCodeManager->disableBackupCodesIfUnused($user);
|
||||
$entityManager->remove($u2f);
|
||||
$entityManager->flush();
|
||||
$this->addFlash('success', 'tfa.u2f.u2f_delete.success');
|
||||
|
||||
$security_event = new SecurityEvent($user);
|
||||
$this->eventDispatcher->dispatch($security_event, SecurityEvents::U2F_REMOVED);
|
||||
} else if ($request->request->has('webauthn_key_id')) {
|
||||
} elseif ($request->request->has('webauthn_key_id')) {
|
||||
$key_id = $request->request->get('webauthn_key_id');
|
||||
$key_repo = $entityManager->getRepository(WebauthnKey::class);
|
||||
/** @var WebauthnKey|null $key */
|
||||
$key = $key_repo->find($key_id);
|
||||
if (null === $key) {
|
||||
if (!$key instanceof \App\Entity\UserSystem\WebauthnKey) {
|
||||
$this->addFlash('error', 'tfa_u2f.u2f_delete.not_existing');
|
||||
|
||||
return $this->redirectToRoute('user_settings');
|
||||
}
|
||||
|
||||
//User can only delete its own U2F keys
|
||||
if ($key->getUser() !== $user) {
|
||||
$this->addFlash('error', 'tfa_u2f.u2f_delete.access_denied');
|
||||
|
||||
return $this->redirectToRoute('user_settings');
|
||||
}
|
||||
|
||||
$backupCodeManager->disableBackupCodesIfUnused($user);
|
||||
$entityManager->remove($key);
|
||||
$entityManager->flush();
|
||||
$this->addFlash('success', 'tfa.u2f.u2f_delete.success');
|
||||
|
||||
$security_event = new SecurityEvent($user);
|
||||
$this->eventDispatcher->dispatch($security_event, SecurityEvents::U2F_REMOVED);
|
||||
}
|
||||
|
@ -174,11 +165,8 @@ class UserSettingsController extends AbstractController
|
|||
return $this->redirectToRoute('user_settings');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RuntimeException|RedirectResponse
|
||||
*/
|
||||
#[Route(path: '/invalidate_trustedDevices', name: 'tfa_trustedDevices_invalidate', methods: ['DELETE'])]
|
||||
public function resetTrustedDevices(Request $request, EntityManagerInterface $entityManager)
|
||||
public function resetTrustedDevices(Request $request, EntityManagerInterface $entityManager): \RuntimeException|\Symfony\Component\HttpFoundation\RedirectResponse
|
||||
{
|
||||
if ($this->demo_mode) {
|
||||
throw new RuntimeException('You can not do 2FA things in demo mode');
|
||||
|
@ -215,7 +203,7 @@ class UserSettingsController extends AbstractController
|
|||
* @return RedirectResponse|Response
|
||||
*/
|
||||
#[Route(path: '/settings', name: 'user_settings')]
|
||||
public function userSettings(Request $request, EntityManagerInterface $em, UserPasswordHasherInterface $passwordEncoder, GoogleAuthenticator $googleAuthenticator, BackupCodeManager $backupCodeManager, FormFactoryInterface $formFactory, UserAvatarHelper $avatarHelper)
|
||||
public function userSettings(Request $request, EntityManagerInterface $em, UserPasswordHasherInterface $passwordEncoder, GoogleAuthenticator $googleAuthenticator, BackupCodeManager $backupCodeManager, FormFactoryInterface $formFactory, UserAvatarHelper $avatarHelper): \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = $this->getUser();
|
||||
|
@ -254,13 +242,11 @@ class UserSettingsController extends AbstractController
|
|||
}
|
||||
|
||||
/** @var Form $form We need a form implementation for the next calls */
|
||||
if ($form->getClickedButton() && 'remove_avatar' === $form->getClickedButton()->getName()) {
|
||||
//Remove the avatar attachment from the user if requested
|
||||
if ($user->getMasterPictureAttachment() !== null) {
|
||||
$em->remove($user->getMasterPictureAttachment());
|
||||
$user->setMasterPictureAttachment(null);
|
||||
$page_need_reload = true;
|
||||
}
|
||||
//Remove the avatar attachment from the user if requested
|
||||
if ($form->getClickedButton() && 'remove_avatar' === $form->getClickedButton()->getName() && $user->getMasterPictureAttachment() instanceof \App\Entity\Attachments\Attachment) {
|
||||
$em->remove($user->getMasterPictureAttachment());
|
||||
$user->setMasterPictureAttachment(null);
|
||||
$page_need_reload = true;
|
||||
}
|
||||
|
||||
$em->flush();
|
||||
|
|
|
@ -33,11 +33,8 @@ use function Symfony\Component\Translation\t;
|
|||
|
||||
class WebauthnKeyRegistrationController extends AbstractController
|
||||
{
|
||||
private bool $demo_mode;
|
||||
|
||||
public function __construct(bool $demo_mode)
|
||||
public function __construct(private readonly bool $demo_mode)
|
||||
{
|
||||
$this->demo_mode = $demo_mode;
|
||||
}
|
||||
|
||||
#[Route(path: '/webauthn/register', name: 'webauthn_register')]
|
||||
|
@ -73,7 +70,7 @@ class WebauthnKeyRegistrationController extends AbstractController
|
|||
//Check the response
|
||||
try {
|
||||
$new_key = $registrationHelper->checkRegistrationResponse($webauthnResponse);
|
||||
} catch (\Exception $exception) {
|
||||
} catch (\Exception) {
|
||||
$this->addFlash('error', t('tfa_u2f.add_key.registration_error'));
|
||||
return $this->redirectToRoute('webauthn_register');
|
||||
}
|
||||
|
|
|
@ -38,11 +38,8 @@ use InvalidArgumentException;
|
|||
|
||||
class DataStructureFixtures extends Fixture
|
||||
{
|
||||
protected EntityManagerInterface $em;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
public function __construct(protected EntityManagerInterface $em)
|
||||
{
|
||||
$this->em = $entityManager;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -30,18 +30,12 @@ use Doctrine\Persistence\ObjectManager;
|
|||
|
||||
class GroupFixtures extends Fixture
|
||||
{
|
||||
public const ADMINS = 'group-admin';
|
||||
public const USERS = 'group-users';
|
||||
public const READONLY = 'group-readonly';
|
||||
final public const ADMINS = 'group-admin';
|
||||
final public const USERS = 'group-users';
|
||||
final public const READONLY = 'group-readonly';
|
||||
|
||||
|
||||
private PermissionPresetsHelper $permission_presets;
|
||||
private PermissionManager $permissionManager;
|
||||
|
||||
public function __construct(PermissionPresetsHelper $permissionPresetsHelper, PermissionManager $permissionManager)
|
||||
public function __construct(private readonly PermissionPresetsHelper $permission_presets, private readonly PermissionManager $permissionManager)
|
||||
{
|
||||
$this->permission_presets = $permissionPresetsHelper;
|
||||
$this->permissionManager = $permissionManager;
|
||||
}
|
||||
|
||||
public function load(ObjectManager $manager): void
|
||||
|
|
|
@ -49,11 +49,8 @@ use Doctrine\Persistence\ObjectManager;
|
|||
|
||||
class LabelProfileFixtures extends Fixture
|
||||
{
|
||||
protected EntityManagerInterface $em;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
public function __construct(protected EntityManagerInterface $em)
|
||||
{
|
||||
$this->em = $entityManager;
|
||||
}
|
||||
|
||||
public function load(ObjectManager $manager): void
|
||||
|
|
|
@ -60,11 +60,8 @@ use Doctrine\Persistence\ObjectManager;
|
|||
|
||||
class PartFixtures extends Fixture
|
||||
{
|
||||
protected EntityManagerInterface $em;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
public function __construct(protected EntityManagerInterface $em)
|
||||
{
|
||||
$this->em = $entityManager;
|
||||
}
|
||||
|
||||
public function load(ObjectManager $manager): void
|
||||
|
|
|
@ -30,13 +30,8 @@ use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
|||
|
||||
class UserFixtures extends Fixture
|
||||
{
|
||||
protected UserPasswordHasherInterface $encoder;
|
||||
protected EntityManagerInterface $em;
|
||||
|
||||
public function __construct(UserPasswordHasherInterface $encoder, EntityManagerInterface $entityManager)
|
||||
public function __construct(protected UserPasswordHasherInterface $encoder, protected EntityManagerInterface $em)
|
||||
{
|
||||
$this->em = $entityManager;
|
||||
$this->encoder = $encoder;
|
||||
}
|
||||
|
||||
public function load(ObjectManager $manager): void
|
||||
|
|
|
@ -42,27 +42,14 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
|
||||
final class AttachmentDataTable implements DataTableTypeInterface
|
||||
{
|
||||
private TranslatorInterface $translator;
|
||||
private EntityURLGenerator $entityURLGenerator;
|
||||
private AttachmentManager $attachmentHelper;
|
||||
private ElementTypeNameGenerator $elementTypeNameGenerator;
|
||||
private AttachmentURLGenerator $attachmentURLGenerator;
|
||||
|
||||
public function __construct(TranslatorInterface $translator, EntityURLGenerator $entityURLGenerator,
|
||||
AttachmentManager $attachmentHelper, AttachmentURLGenerator $attachmentURLGenerator,
|
||||
ElementTypeNameGenerator $elementTypeNameGenerator)
|
||||
public function __construct(private readonly TranslatorInterface $translator, private readonly EntityURLGenerator $entityURLGenerator, private readonly AttachmentManager $attachmentHelper, private readonly AttachmentURLGenerator $attachmentURLGenerator, private readonly ElementTypeNameGenerator $elementTypeNameGenerator)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
$this->entityURLGenerator = $entityURLGenerator;
|
||||
$this->attachmentHelper = $attachmentHelper;
|
||||
$this->elementTypeNameGenerator = $elementTypeNameGenerator;
|
||||
$this->attachmentURLGenerator = $attachmentURLGenerator;
|
||||
}
|
||||
|
||||
public function configure(DataTable $dataTable, array $options): void
|
||||
{
|
||||
$dataTable->add('dont_matter', RowClassColumn::class, [
|
||||
'render' => function ($value, Attachment $context) {
|
||||
'render' => function ($value, Attachment $context): string {
|
||||
//Mark attachments with missing files yellow
|
||||
if(!$this->attachmentHelper->isFileExisting($context)){
|
||||
return 'table-warning';
|
||||
|
@ -75,7 +62,7 @@ final class AttachmentDataTable implements DataTableTypeInterface
|
|||
$dataTable->add('picture', TextColumn::class, [
|
||||
'label' => '',
|
||||
'className' => 'no-colvis',
|
||||
'render' => function ($value, Attachment $context) {
|
||||
'render' => function ($value, Attachment $context): string {
|
||||
if ($context->isPicture()
|
||||
&& !$context->isExternal()
|
||||
&& $this->attachmentHelper->isFileExisting($context)) {
|
||||
|
@ -125,25 +112,21 @@ final class AttachmentDataTable implements DataTableTypeInterface
|
|||
$dataTable->add('attachment_type', TextColumn::class, [
|
||||
'label' => 'attachment.table.type',
|
||||
'field' => 'attachment_type.name',
|
||||
'render' => function ($value, Attachment $context) {
|
||||
return sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
$this->entityURLGenerator->editURL($context->getAttachmentType()),
|
||||
htmlspecialchars($value)
|
||||
);
|
||||
},
|
||||
'render' => fn($value, Attachment $context): string => sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
$this->entityURLGenerator->editURL($context->getAttachmentType()),
|
||||
htmlspecialchars((string) $value)
|
||||
),
|
||||
]);
|
||||
|
||||
$dataTable->add('element', TextColumn::class, [
|
||||
'label' => 'attachment.table.element',
|
||||
//'propertyPath' => 'element.name',
|
||||
'render' => function ($value, Attachment $context) {
|
||||
return sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
$this->entityURLGenerator->infoURL($context->getElement()),
|
||||
$this->elementTypeNameGenerator->getTypeNameCombination($context->getElement(), true)
|
||||
);
|
||||
},
|
||||
'render' => fn($value, Attachment $context): string => sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
$this->entityURLGenerator->infoURL($context->getElement()),
|
||||
$this->elementTypeNameGenerator->getTypeNameCombination($context->getElement(), true)
|
||||
),
|
||||
]);
|
||||
|
||||
$dataTable->add('filename', TextColumn::class, [
|
||||
|
|
|
@ -31,13 +31,8 @@ use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
|||
|
||||
class EntityColumn extends AbstractColumn
|
||||
{
|
||||
protected EntityURLGenerator $urlGenerator;
|
||||
protected PropertyAccessorInterface $accessor;
|
||||
|
||||
public function __construct(EntityURLGenerator $URLGenerator, PropertyAccessorInterface $accessor)
|
||||
public function __construct(protected EntityURLGenerator $urlGenerator, protected PropertyAccessorInterface $accessor)
|
||||
{
|
||||
$this->urlGenerator = $URLGenerator;
|
||||
$this->accessor = $accessor;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,34 +53,30 @@ class EntityColumn extends AbstractColumn
|
|||
|
||||
$resolver->setRequired('property');
|
||||
|
||||
$resolver->setDefault('field', static function (Options $option) {
|
||||
return $option['property'].'.name';
|
||||
});
|
||||
$resolver->setDefault('field', static fn(Options $option): string => $option['property'].'.name');
|
||||
|
||||
$resolver->setDefault('render', function (Options $options) {
|
||||
return function ($value, $context) use ($options) {
|
||||
if ($this->accessor->isReadable($context, $options['property'])) {
|
||||
$entity = $this->accessor->getValue($context, $options['property']);
|
||||
} else {
|
||||
$entity = null;
|
||||
$resolver->setDefault('render', fn(Options $options) => function ($value, $context) use ($options): string {
|
||||
if ($this->accessor->isReadable($context, $options['property'])) {
|
||||
$entity = $this->accessor->getValue($context, $options['property']);
|
||||
} else {
|
||||
$entity = null;
|
||||
}
|
||||
|
||||
/** @var AbstractNamedDBElement|null $entity */
|
||||
|
||||
if ($entity instanceof \App\Entity\Base\AbstractNamedDBElement) {
|
||||
if (null !== $entity->getID()) {
|
||||
return sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
$this->urlGenerator->listPartsURL($entity),
|
||||
htmlspecialchars($entity->getName())
|
||||
);
|
||||
}
|
||||
|
||||
/** @var AbstractNamedDBElement|null $entity */
|
||||
return sprintf('<i>%s</i>', $value);
|
||||
}
|
||||
|
||||
if (null !== $entity) {
|
||||
if (null !== $entity->getID()) {
|
||||
return sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
$this->urlGenerator->listPartsURL($entity),
|
||||
htmlspecialchars($entity->getName())
|
||||
);
|
||||
}
|
||||
|
||||
return sprintf('<i>%s</i>', $value);
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
return '';
|
||||
});
|
||||
|
||||
return $this;
|
||||
|
|
|
@ -38,7 +38,6 @@ class LocaleDateTimeColumn extends AbstractColumn
|
|||
{
|
||||
/**
|
||||
* @param $value
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function normalize($value): string
|
||||
|
|
|
@ -28,13 +28,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
|
||||
class LogEntryExtraColumn extends AbstractColumn
|
||||
{
|
||||
protected TranslatorInterface $translator;
|
||||
protected LogEntryExtraFormatter $formatter;
|
||||
|
||||
public function __construct(TranslatorInterface $translator, LogEntryExtraFormatter $formatter)
|
||||
public function __construct(protected TranslatorInterface $translator, protected LogEntryExtraFormatter $formatter)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
$this->formatter = $formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,11 +44,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
|
||||
class LogEntryTargetColumn extends AbstractColumn
|
||||
{
|
||||
private LogTargetHelper $logTargetHelper;
|
||||
|
||||
public function __construct(LogTargetHelper $logTargetHelper)
|
||||
public function __construct(private readonly LogTargetHelper $logTargetHelper)
|
||||
{
|
||||
$this->logTargetHelper = $logTargetHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,11 +27,8 @@ use Omines\DataTablesBundle\Column\AbstractColumn;
|
|||
|
||||
class MarkdownColumn extends AbstractColumn
|
||||
{
|
||||
protected MarkdownParser $markdown;
|
||||
|
||||
public function __construct(MarkdownParser $markdown)
|
||||
public function __construct(protected MarkdownParser $markdown)
|
||||
{
|
||||
$this->markdown = $markdown;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -33,15 +33,8 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
|
|||
|
||||
class PartAttachmentsColumn extends AbstractColumn
|
||||
{
|
||||
protected FAIconGenerator $FAIconGenerator;
|
||||
protected EntityURLGenerator $urlGenerator;
|
||||
protected AttachmentManager $attachmentManager;
|
||||
|
||||
public function __construct(FAIconGenerator $FAIconGenerator, EntityURLGenerator $urlGenerator, AttachmentManager $attachmentManager)
|
||||
public function __construct(protected FAIconGenerator $FAIconGenerator, protected EntityURLGenerator $urlGenerator, protected AttachmentManager $attachmentManager)
|
||||
{
|
||||
$this->FAIconGenerator = $FAIconGenerator;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->attachmentManager = $attachmentManager;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -61,9 +54,7 @@ class PartAttachmentsColumn extends AbstractColumn
|
|||
throw new RuntimeException('$context must be a Part object!');
|
||||
}
|
||||
$tmp = '';
|
||||
$attachments = $context->getAttachments()->filter(function (Attachment $attachment) {
|
||||
return $attachment->getShowInTable() && $this->attachmentManager->isFileExisting($attachment);
|
||||
});
|
||||
$attachments = $context->getAttachments()->filter(fn(Attachment $attachment) => $attachment->getShowInTable() && $this->attachmentManager->isFileExisting($attachment));
|
||||
|
||||
$count = 5;
|
||||
foreach ($attachments as $attachment) {
|
||||
|
|
|
@ -25,11 +25,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
|
||||
class PrettyBoolColumn extends AbstractColumn
|
||||
{
|
||||
protected TranslatorInterface $translator;
|
||||
|
||||
public function __construct(TranslatorInterface $translator)
|
||||
public function __construct(protected TranslatorInterface $translator)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
public function normalize($value): ?bool
|
||||
|
|
|
@ -51,13 +51,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
|
||||
class RevertLogColumn extends AbstractColumn
|
||||
{
|
||||
protected TranslatorInterface $translator;
|
||||
protected \Symfony\Bundle\SecurityBundle\Security $security;
|
||||
|
||||
public function __construct(TranslatorInterface $translator, \Symfony\Bundle\SecurityBundle\Security $security)
|
||||
public function __construct(protected TranslatorInterface $translator, protected \Symfony\Bundle\SecurityBundle\Security $security)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
$this->security = $security;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,8 +100,6 @@ class RevertLogColumn extends AbstractColumn
|
|||
$this->translator->trans('log.undo.revert')
|
||||
);
|
||||
|
||||
$tmp .= '</div>';
|
||||
|
||||
return $tmp;
|
||||
return $tmp . '</div>';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,11 +26,8 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
|
|||
|
||||
class SIUnitNumberColumn extends AbstractColumn
|
||||
{
|
||||
protected SIFormatter $formatter;
|
||||
|
||||
public function __construct(SIFormatter $formatter)
|
||||
public function __construct(protected SIFormatter $formatter)
|
||||
{
|
||||
$this->formatter = $formatter;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): self
|
||||
|
|
|
@ -27,11 +27,8 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
|||
|
||||
class TagsColumn extends AbstractColumn
|
||||
{
|
||||
protected UrlGeneratorInterface $urlGenerator;
|
||||
|
||||
public function __construct(UrlGeneratorInterface $urlGenerator)
|
||||
public function __construct(protected UrlGeneratorInterface $urlGenerator)
|
||||
{
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,7 +43,7 @@ class TagsColumn extends AbstractColumn
|
|||
return [];
|
||||
}
|
||||
|
||||
return explode(',', $value);
|
||||
return explode(',', (string) $value);
|
||||
}
|
||||
|
||||
public function render($tags, $context): string
|
||||
|
@ -61,7 +58,7 @@ class TagsColumn extends AbstractColumn
|
|||
$html .= sprintf(
|
||||
'<a href="%s" class="badge bg-primary badge-table">%s</a>',
|
||||
$this->urlGenerator->generate('part_list_tags', ['tag' => $tag]),
|
||||
htmlspecialchars($tag)
|
||||
htmlspecialchars((string) $tag)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -54,16 +54,12 @@ class ErrorDataTable implements DataTableTypeInterface
|
|||
|
||||
$dataTable
|
||||
->add('dont_matter_we_only_set_color', RowClassColumn::class, [
|
||||
'render' => function ($value, $context) {
|
||||
return 'table-warning';
|
||||
},
|
||||
'render' => fn($value, $context): string => 'table-warning',
|
||||
])
|
||||
|
||||
->add('error', TextColumn::class, [
|
||||
'label' => 'error_table.error',
|
||||
'render' => function ($value, $context) {
|
||||
return '<i class="fa-solid fa-triangle-exclamation fa-fw"></i> ' . $value;
|
||||
},
|
||||
'render' => fn($value, $context): string => '<i class="fa-solid fa-triangle-exclamation fa-fw"></i> ' . $value,
|
||||
])
|
||||
;
|
||||
|
||||
|
|
|
@ -60,59 +60,38 @@ class AttachmentFilter implements FilterInterface
|
|||
$this->applyAllChildFilters($queryBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return NumberConstraint
|
||||
*/
|
||||
public function getDbId(): NumberConstraint
|
||||
{
|
||||
return $this->dbId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TextConstraint
|
||||
*/
|
||||
public function getName(): TextConstraint
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DateTimeConstraint
|
||||
*/
|
||||
public function getLastModified(): DateTimeConstraint
|
||||
{
|
||||
return $this->lastModified;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DateTimeConstraint
|
||||
*/
|
||||
public function getAddedDate(): DateTimeConstraint
|
||||
{
|
||||
return $this->addedDate;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return BooleanConstraint
|
||||
*/
|
||||
public function getShowInTable(): BooleanConstraint
|
||||
{
|
||||
return $this->showInTable;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return EntityConstraint
|
||||
*/
|
||||
public function getAttachmentType(): EntityConstraint
|
||||
{
|
||||
return $this->attachmentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return InstanceOfConstraint
|
||||
*/
|
||||
public function getTargetType(): InstanceOfConstraint
|
||||
{
|
||||
return $this->targetType;
|
||||
|
|
|
@ -60,8 +60,6 @@ trait CompoundFilterTrait
|
|||
|
||||
/**
|
||||
* Applies all children filters that are declared as property of this filter using reflection.
|
||||
* @param QueryBuilder $queryBuilder
|
||||
* @return void
|
||||
*/
|
||||
protected function applyAllChildFilters(QueryBuilder $queryBuilder): void
|
||||
{
|
||||
|
|
|
@ -26,11 +26,6 @@ abstract class AbstractConstraint implements FilterInterface
|
|||
{
|
||||
use FilterTrait;
|
||||
|
||||
/**
|
||||
* @var string The property where this BooleanConstraint should apply to
|
||||
*/
|
||||
protected string $property;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
|
@ -43,9 +38,11 @@ abstract class AbstractConstraint implements FilterInterface
|
|||
*/
|
||||
abstract public function isEnabled(): bool;
|
||||
|
||||
public function __construct(string $property, string $identifier = null)
|
||||
public function __construct(/**
|
||||
* @var string The property where this BooleanConstraint should apply to
|
||||
*/
|
||||
protected string $property, string $identifier = null)
|
||||
{
|
||||
$this->property = $property;
|
||||
$this->identifier = $identifier ?? $this->generateParameterIdentifier($property);
|
||||
}
|
||||
}
|
|
@ -24,19 +24,14 @@ use Doctrine\ORM\QueryBuilder;
|
|||
|
||||
class BooleanConstraint extends AbstractConstraint
|
||||
{
|
||||
/** @var bool|null The value of our constraint */
|
||||
protected ?bool $value;
|
||||
|
||||
|
||||
public function __construct(string $property, string $identifier = null, ?bool $default_value = null)
|
||||
public function __construct(string $property, string $identifier = null, /** @var bool|null The value of our constraint */
|
||||
protected ?bool $value = null)
|
||||
{
|
||||
parent::__construct($property, $identifier);
|
||||
$this->value = $default_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of this constraint. Null means "don't filter", true means "filter for true", false means "filter for false".
|
||||
* @return bool|null
|
||||
*/
|
||||
public function getValue(): ?bool
|
||||
{
|
||||
|
@ -45,7 +40,6 @@ class BooleanConstraint extends AbstractConstraint
|
|||
|
||||
/**
|
||||
* Sets the value of this constraint. Null means "don't filter", true means "filter for true", false means "filter for false".
|
||||
* @param bool|null $value
|
||||
*/
|
||||
public function setValue(?bool $value): void
|
||||
{
|
||||
|
|
|
@ -24,7 +24,7 @@ use Doctrine\ORM\QueryBuilder;
|
|||
|
||||
class ChoiceConstraint extends AbstractConstraint
|
||||
{
|
||||
public const ALLOWED_OPERATOR_VALUES = ['ANY', 'NONE'];
|
||||
final public const ALLOWED_OPERATOR_VALUES = ['ANY', 'NONE'];
|
||||
|
||||
/**
|
||||
* @var string[]|int[] The values to compare to
|
||||
|
@ -46,7 +46,6 @@ class ChoiceConstraint extends AbstractConstraint
|
|||
|
||||
/**
|
||||
* @param string[]|int[] $value
|
||||
* @return ChoiceConstraint
|
||||
*/
|
||||
public function setValue(array $value): ChoiceConstraint
|
||||
{
|
||||
|
@ -54,18 +53,11 @@ class ChoiceConstraint extends AbstractConstraint
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getOperator(): string
|
||||
{
|
||||
return $this->operator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $operator
|
||||
* @return ChoiceConstraint
|
||||
*/
|
||||
public function setOperator(string $operator): ChoiceConstraint
|
||||
{
|
||||
$this->operator = $operator;
|
||||
|
|
|
@ -33,26 +33,6 @@ class EntityConstraint extends AbstractConstraint
|
|||
private const ALLOWED_OPERATOR_VALUES_BASE = ['=', '!='];
|
||||
private const ALLOWED_OPERATOR_VALUES_STRUCTURAL = ['INCLUDING_CHILDREN', 'EXCLUDING_CHILDREN'];
|
||||
|
||||
/**
|
||||
* @var NodesListBuilder
|
||||
*/
|
||||
protected ?NodesListBuilder $nodesListBuilder;
|
||||
|
||||
/**
|
||||
* @var class-string<T> The class to use for the comparison
|
||||
*/
|
||||
protected string $class;
|
||||
|
||||
/**
|
||||
* @var string|null The operator to use
|
||||
*/
|
||||
protected ?string $operator;
|
||||
|
||||
/**
|
||||
* @var T The value to compare to
|
||||
*/
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* @param NodesListBuilder|null $nodesListBuilder
|
||||
* @param class-string<T> $class
|
||||
|
@ -61,18 +41,13 @@ class EntityConstraint extends AbstractConstraint
|
|||
* @param null $value
|
||||
* @param string $operator
|
||||
*/
|
||||
public function __construct(?NodesListBuilder $nodesListBuilder, string $class, string $property, string $identifier = null, $value = null, string $operator = '')
|
||||
public function __construct(protected ?\App\Services\Trees\NodesListBuilder $nodesListBuilder, protected string $class, string $property, string $identifier = null, protected $value = null, protected ?string $operator = '')
|
||||
{
|
||||
$this->nodesListBuilder = $nodesListBuilder;
|
||||
$this->class = $class;
|
||||
|
||||
if ($nodesListBuilder === null && $this->isStructural()) {
|
||||
if (!$nodesListBuilder instanceof \App\Services\Trees\NodesListBuilder && $this->isStructural()) {
|
||||
throw new \InvalidArgumentException('NodesListBuilder must be provided for structural entities');
|
||||
}
|
||||
|
||||
parent::__construct($property, $identifier);
|
||||
$this->value = $value;
|
||||
$this->operator = $operator;
|
||||
}
|
||||
|
||||
public function getClass(): string
|
||||
|
@ -80,17 +55,11 @@ class EntityConstraint extends AbstractConstraint
|
|||
return $this->class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getOperator(): ?string
|
||||
{
|
||||
return $this->operator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $operator
|
||||
*/
|
||||
public function setOperator(?string $operator): self
|
||||
{
|
||||
$this->operator = $operator;
|
||||
|
@ -119,7 +88,6 @@ class EntityConstraint extends AbstractConstraint
|
|||
|
||||
/**
|
||||
* Checks whether the constraints apply to a structural type or not
|
||||
* @return bool
|
||||
*/
|
||||
public function isStructural(): bool
|
||||
{
|
||||
|
@ -136,7 +104,7 @@ class EntityConstraint extends AbstractConstraint
|
|||
$tmp = self::ALLOWED_OPERATOR_VALUES_BASE;
|
||||
|
||||
if ($this->isStructural()) {
|
||||
$tmp = array_merge($tmp, self::ALLOWED_OPERATOR_VALUES_STRUCTURAL);
|
||||
$tmp = [...$tmp, ...self::ALLOWED_OPERATOR_VALUES_STRUCTURAL];
|
||||
}
|
||||
|
||||
return $tmp;
|
||||
|
@ -160,7 +128,7 @@ class EntityConstraint extends AbstractConstraint
|
|||
}
|
||||
|
||||
//We need to handle null values differently, as they can not be compared with == or !=
|
||||
if ($this->value === null) {
|
||||
if (!$this->value instanceof \App\Entity\Base\AbstractDBElement) {
|
||||
if($this->operator === '=' || $this->operator === 'INCLUDING_CHILDREN') {
|
||||
$queryBuilder->andWhere(sprintf("%s IS NULL", $this->property));
|
||||
return;
|
||||
|
|
|
@ -35,7 +35,6 @@ trait FilterTrait
|
|||
|
||||
/**
|
||||
* Checks if the given input is an aggregateFunction like COUNT(part.partsLot) or so
|
||||
* @return bool
|
||||
*/
|
||||
protected function isAggregateFunctionString(string $input): bool
|
||||
{
|
||||
|
@ -44,8 +43,6 @@ trait FilterTrait
|
|||
|
||||
/**
|
||||
* Generates a parameter identifier that can be used for the given property. It gives random results, to be unique, so you have to cache it.
|
||||
* @param string $property
|
||||
* @return string
|
||||
*/
|
||||
protected function generateParameterIdentifier(string $property): string
|
||||
{
|
||||
|
@ -57,13 +54,8 @@ trait FilterTrait
|
|||
|
||||
/**
|
||||
* Adds a simple constraint in the form of (property OPERATOR value) (e.g. "part.name = :name") to the given query builder.
|
||||
* @param QueryBuilder $queryBuilder
|
||||
* @param string $property
|
||||
* @param string $comparison_operator
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
protected function addSimpleAndConstraint(QueryBuilder $queryBuilder, string $property, string $parameterIdentifier, string $comparison_operator, $value): void
|
||||
protected function addSimpleAndConstraint(QueryBuilder $queryBuilder, string $property, string $parameterIdentifier, string $comparison_operator, mixed $value): void
|
||||
{
|
||||
if ($comparison_operator === 'IN' || $comparison_operator === 'NOT IN') {
|
||||
$expression = sprintf("%s %s (:%s)", $property, $comparison_operator, $parameterIdentifier);
|
||||
|
|
|
@ -27,7 +27,7 @@ use Doctrine\ORM\QueryBuilder;
|
|||
*/
|
||||
class InstanceOfConstraint extends AbstractConstraint
|
||||
{
|
||||
public const ALLOWED_OPERATOR_VALUES = ['ANY', 'NONE'];
|
||||
final public const ALLOWED_OPERATOR_VALUES = ['ANY', 'NONE'];
|
||||
|
||||
/**
|
||||
* @var string[] The values to compare to (fully qualified class names)
|
||||
|
@ -57,16 +57,12 @@ class InstanceOfConstraint extends AbstractConstraint
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getOperator(): string
|
||||
{
|
||||
return $this->operator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $operator
|
||||
* @return $this
|
||||
*/
|
||||
public function setOperator(string $operator): self
|
||||
|
|
|
@ -25,61 +25,28 @@ use RuntimeException;
|
|||
|
||||
class NumberConstraint extends AbstractConstraint
|
||||
{
|
||||
public const ALLOWED_OPERATOR_VALUES = ['=', '!=', '<', '>', '<=', '>=', 'BETWEEN'];
|
||||
final public const ALLOWED_OPERATOR_VALUES = ['=', '!=', '<', '>', '<=', '>=', 'BETWEEN'];
|
||||
|
||||
|
||||
/**
|
||||
* The value1 used for comparison (this is the main one used for all mono-value comparisons)
|
||||
* @var float|null|int|\DateTimeInterface
|
||||
*/
|
||||
protected $value1;
|
||||
|
||||
/**
|
||||
* The second value used when operator is RANGE; this is the upper bound of the range
|
||||
* @var float|null|int|\DateTimeInterface
|
||||
*/
|
||||
protected $value2;
|
||||
|
||||
/**
|
||||
* @var string|null The operator to use
|
||||
*/
|
||||
protected ?string $operator;
|
||||
|
||||
/**
|
||||
* @return float|int|null|\DateTimeInterface
|
||||
*/
|
||||
public function getValue1()
|
||||
public function getValue1(): float|int|null|\DateTimeInterface
|
||||
{
|
||||
return $this->value1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float|int|\DateTimeInterface|null $value1
|
||||
*/
|
||||
public function setValue1($value1): void
|
||||
public function setValue1(float|int|\DateTimeInterface|null $value1): void
|
||||
{
|
||||
$this->value1 = $value1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float|int|null
|
||||
*/
|
||||
public function getValue2()
|
||||
public function getValue2(): float|int|null
|
||||
{
|
||||
return $this->value2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float|int|null $value2
|
||||
*/
|
||||
public function setValue2($value2): void
|
||||
public function setValue2(float|int|null $value2): void
|
||||
{
|
||||
$this->value2 = $value2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getOperator(): string
|
||||
{
|
||||
return $this->operator;
|
||||
|
@ -94,12 +61,22 @@ class NumberConstraint extends AbstractConstraint
|
|||
}
|
||||
|
||||
|
||||
public function __construct(string $property, string $identifier = null, $value1 = null, string $operator = null, $value2 = null)
|
||||
/**
|
||||
* @param float|null|int|\DateTimeInterface $value1
|
||||
* @param float|null|int|\DateTimeInterface $value2
|
||||
*/
|
||||
public function __construct(string $property, string $identifier = null, /**
|
||||
* The value1 used for comparison (this is the main one used for all mono-value comparisons)
|
||||
*/
|
||||
protected float|int|\DateTimeInterface|null $value1 = null, /**
|
||||
* @var string|null The operator to use
|
||||
*/
|
||||
protected ?string $operator = null, /**
|
||||
* The second value used when operator is RANGE; this is the upper bound of the range
|
||||
*/
|
||||
protected float|int|\DateTimeInterface|null $value2 = null)
|
||||
{
|
||||
parent::__construct($property, $identifier);
|
||||
$this->value1 = $value1;
|
||||
$this->value2 = $value2;
|
||||
$this->operator = $operator;
|
||||
}
|
||||
|
||||
public function isEnabled(): bool
|
||||
|
|
|
@ -103,71 +103,44 @@ class ParameterConstraint extends AbstractConstraint
|
|||
$queryBuilder->andWhere('(' . $subqb->getDQL() . ') > 0');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return ParameterConstraint
|
||||
*/
|
||||
public function setName(string $name): ParameterConstraint
|
||||
{
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSymbol(): string
|
||||
{
|
||||
return $this->symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $symbol
|
||||
* @return ParameterConstraint
|
||||
*/
|
||||
public function setSymbol(string $symbol): ParameterConstraint
|
||||
{
|
||||
$this->symbol = $symbol;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getUnit(): string
|
||||
{
|
||||
return $this->unit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $unit
|
||||
* @return ParameterConstraint
|
||||
*/
|
||||
public function setUnit(string $unit): ParameterConstraint
|
||||
{
|
||||
$this->unit = $unit;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TextConstraint
|
||||
*/
|
||||
public function getValueText(): TextConstraint
|
||||
{
|
||||
return $this->value_text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ParameterValueConstraint
|
||||
*/
|
||||
public function getValue(): ParameterValueConstraint
|
||||
{
|
||||
return $this->value;
|
||||
|
|
|
@ -25,18 +25,14 @@ use Doctrine\ORM\QueryBuilder;
|
|||
|
||||
class ParameterValueConstraint extends NumberConstraint
|
||||
{
|
||||
protected string $alias;
|
||||
|
||||
public const ALLOWED_OPERATOR_VALUES = ['=', '!=', '<', '>', '<=', '>=', 'BETWEEN',
|
||||
final public const ALLOWED_OPERATOR_VALUES = ['=', '!=', '<', '>', '<=', '>=', 'BETWEEN',
|
||||
//Additional operators
|
||||
'IN_RANGE', 'NOT_IN_RANGE', 'GREATER_THAN_RANGE', 'GREATER_EQUAL_RANGE', 'LESS_THAN_RANGE', 'LESS_EQUAL_RANGE', 'RANGE_IN_RANGE', 'RANGE_INTERSECT_RANGE'];
|
||||
|
||||
/**
|
||||
* @param string $alias The alias which is used in the sub query of ParameterConstraint
|
||||
*/
|
||||
public function __construct(string $alias) {
|
||||
$this->alias = $alias;
|
||||
|
||||
public function __construct(protected string $alias) {
|
||||
parent::__construct($alias . '.value_typical');
|
||||
}
|
||||
|
||||
|
|
|
@ -26,23 +26,20 @@ use Doctrine\ORM\QueryBuilder;
|
|||
|
||||
class TagsConstraint extends AbstractConstraint
|
||||
{
|
||||
public const ALLOWED_OPERATOR_VALUES = ['ANY', 'ALL', 'NONE'];
|
||||
final public const ALLOWED_OPERATOR_VALUES = ['ANY', 'ALL', 'NONE'];
|
||||
|
||||
/**
|
||||
* @var string|null The operator to use
|
||||
* @param string $value
|
||||
*/
|
||||
protected ?string $operator;
|
||||
|
||||
/**
|
||||
public function __construct(string $property, string $identifier = null, /**
|
||||
* @var string The value to compare to
|
||||
*/
|
||||
protected $value;
|
||||
|
||||
public function __construct(string $property, string $identifier = null, $value = null, string $operator = '')
|
||||
protected $value = null, /**
|
||||
* @var string|null The operator to use
|
||||
*/
|
||||
protected ?string $operator = '')
|
||||
{
|
||||
parent::__construct($property, $identifier);
|
||||
$this->value = $value;
|
||||
$this->operator = $operator;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -62,17 +59,11 @@ class TagsConstraint extends AbstractConstraint
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getValue(): string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*/
|
||||
public function setValue(string $value): self
|
||||
{
|
||||
$this->value = $value;
|
||||
|
@ -96,9 +87,6 @@ class TagsConstraint extends AbstractConstraint
|
|||
|
||||
/**
|
||||
* Builds an expression to query for a single tag
|
||||
* @param QueryBuilder $queryBuilder
|
||||
* @param string $tag
|
||||
* @return Expr\Orx
|
||||
*/
|
||||
protected function getExpressionForTag(QueryBuilder $queryBuilder, string $tag): Expr\Orx
|
||||
{
|
||||
|
|
|
@ -25,23 +25,20 @@ use Doctrine\ORM\QueryBuilder;
|
|||
class TextConstraint extends AbstractConstraint
|
||||
{
|
||||
|
||||
public const ALLOWED_OPERATOR_VALUES = ['=', '!=', 'STARTS', 'ENDS', 'CONTAINS', 'LIKE', 'REGEX'];
|
||||
final public const ALLOWED_OPERATOR_VALUES = ['=', '!=', 'STARTS', 'ENDS', 'CONTAINS', 'LIKE', 'REGEX'];
|
||||
|
||||
/**
|
||||
* @var string|null The operator to use
|
||||
* @param string $value
|
||||
*/
|
||||
protected ?string $operator;
|
||||
|
||||
/**
|
||||
public function __construct(string $property, string $identifier = null, /**
|
||||
* @var string The value to compare to
|
||||
*/
|
||||
protected $value;
|
||||
|
||||
public function __construct(string $property, string $identifier = null, $value = null, string $operator = '')
|
||||
protected $value = null, /**
|
||||
* @var string|null The operator to use
|
||||
*/
|
||||
protected ?string $operator = '')
|
||||
{
|
||||
parent::__construct($property, $identifier);
|
||||
$this->value = $value;
|
||||
$this->operator = $operator;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -61,17 +58,11 @@ class TextConstraint extends AbstractConstraint
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getValue(): string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*/
|
||||
public function setValue(string $value): self
|
||||
{
|
||||
$this->value = $value;
|
||||
|
@ -105,11 +96,11 @@ class TextConstraint extends AbstractConstraint
|
|||
$like_value = null;
|
||||
if ($this->operator === 'LIKE') {
|
||||
$like_value = $this->value;
|
||||
} else if ($this->operator === 'STARTS') {
|
||||
} elseif ($this->operator === 'STARTS') {
|
||||
$like_value = $this->value . '%';
|
||||
} else if ($this->operator === 'ENDS') {
|
||||
} elseif ($this->operator === 'ENDS') {
|
||||
$like_value = '%' . $this->value;
|
||||
} else if ($this->operator === 'CONTAINS') {
|
||||
} elseif ($this->operator === 'CONTAINS') {
|
||||
$like_value = '%' . $this->value . '%';
|
||||
}
|
||||
|
||||
|
|
|
@ -58,9 +58,6 @@ class LogFilter implements FilterInterface
|
|||
$this->applyAllChildFilters($queryBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DateTimeConstraint
|
||||
*/
|
||||
public function getTimestamp(): DateTimeConstraint
|
||||
{
|
||||
return $this->timestamp;
|
||||
|
@ -69,38 +66,26 @@ class LogFilter implements FilterInterface
|
|||
/**
|
||||
* @return IntConstraint|NumberConstraint
|
||||
*/
|
||||
public function getDbId()
|
||||
public function getDbId(): \App\DataTables\Filters\Constraints\IntConstraint|\App\DataTables\Filters\Constraints\NumberConstraint
|
||||
{
|
||||
return $this->dbId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ChoiceConstraint
|
||||
*/
|
||||
public function getLevel(): ChoiceConstraint
|
||||
{
|
||||
return $this->level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return InstanceOfConstraint
|
||||
*/
|
||||
public function getEventType(): InstanceOfConstraint
|
||||
{
|
||||
return $this->eventType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ChoiceConstraint
|
||||
*/
|
||||
public function getTargetType(): ChoiceConstraint
|
||||
{
|
||||
return $this->targetType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IntConstraint
|
||||
*/
|
||||
public function getTargetId(): IntConstraint
|
||||
{
|
||||
return $this->targetId;
|
||||
|
|
|
@ -145,17 +145,11 @@ class PartFilter implements FilterInterface
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return BooleanConstraint
|
||||
*/
|
||||
public function getFavorite(): BooleanConstraint
|
||||
{
|
||||
return $this->favorite;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BooleanConstraint
|
||||
*/
|
||||
public function getNeedsReview(): BooleanConstraint
|
||||
{
|
||||
return $this->needsReview;
|
||||
|
@ -176,17 +170,11 @@ class PartFilter implements FilterInterface
|
|||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DateTimeConstraint
|
||||
*/
|
||||
public function getLastModified(): DateTimeConstraint
|
||||
{
|
||||
return $this->lastModified;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DateTimeConstraint
|
||||
*/
|
||||
public function getAddedDate(): DateTimeConstraint
|
||||
{
|
||||
return $this->addedDate;
|
||||
|
@ -197,49 +185,31 @@ class PartFilter implements FilterInterface
|
|||
return $this->category;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityConstraint
|
||||
*/
|
||||
public function getFootprint(): EntityConstraint
|
||||
{
|
||||
return $this->footprint;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityConstraint
|
||||
*/
|
||||
public function getManufacturer(): EntityConstraint
|
||||
{
|
||||
return $this->manufacturer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityConstraint
|
||||
*/
|
||||
public function getSupplier(): EntityConstraint
|
||||
{
|
||||
return $this->supplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityConstraint
|
||||
*/
|
||||
public function getStorelocation(): EntityConstraint
|
||||
{
|
||||
return $this->storelocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityConstraint
|
||||
*/
|
||||
public function getMeasurementUnit(): EntityConstraint
|
||||
{
|
||||
return $this->measurementUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return NumberConstraint
|
||||
*/
|
||||
public function getDbId(): NumberConstraint
|
||||
{
|
||||
return $this->dbId;
|
||||
|
@ -250,33 +220,21 @@ class PartFilter implements FilterInterface
|
|||
return $this->ipn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TextConstraint
|
||||
*/
|
||||
public function getComment(): TextConstraint
|
||||
{
|
||||
return $this->comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return NumberConstraint
|
||||
*/
|
||||
public function getMinAmount(): NumberConstraint
|
||||
{
|
||||
return $this->minAmount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TextConstraint
|
||||
*/
|
||||
public function getManufacturerProductUrl(): TextConstraint
|
||||
{
|
||||
return $this->manufacturer_product_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TextConstraint
|
||||
*/
|
||||
public function getManufacturerProductNumber(): TextConstraint
|
||||
{
|
||||
return $this->manufacturer_product_number;
|
||||
|
@ -287,73 +245,46 @@ class PartFilter implements FilterInterface
|
|||
return $this->lotCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityConstraint
|
||||
*/
|
||||
public function getLotOwner(): EntityConstraint
|
||||
{
|
||||
return $this->lotOwner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TagsConstraint
|
||||
*/
|
||||
public function getTags(): TagsConstraint
|
||||
{
|
||||
return $this->tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IntConstraint
|
||||
*/
|
||||
public function getOrderdetailsCount(): IntConstraint
|
||||
{
|
||||
return $this->orderdetailsCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IntConstraint
|
||||
*/
|
||||
public function getAttachmentsCount(): IntConstraint
|
||||
{
|
||||
return $this->attachmentsCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BooleanConstraint
|
||||
*/
|
||||
public function getLotNeedsRefill(): BooleanConstraint
|
||||
{
|
||||
return $this->lotNeedsRefill;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BooleanConstraint
|
||||
*/
|
||||
public function getLotUnknownAmount(): BooleanConstraint
|
||||
{
|
||||
return $this->lotUnknownAmount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DateTimeConstraint
|
||||
*/
|
||||
public function getLotExpirationDate(): DateTimeConstraint
|
||||
{
|
||||
return $this->lotExpirationDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityConstraint
|
||||
*/
|
||||
public function getAttachmentType(): EntityConstraint
|
||||
{
|
||||
return $this->attachmentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TextConstraint
|
||||
*/
|
||||
public function getAttachmentName(): TextConstraint
|
||||
{
|
||||
return $this->attachmentName;
|
||||
|
@ -369,9 +300,6 @@ class PartFilter implements FilterInterface
|
|||
return $this->amountSum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArrayCollection
|
||||
*/
|
||||
public function getParameters(): ArrayCollection
|
||||
{
|
||||
return $this->parameters;
|
||||
|
@ -382,25 +310,16 @@ class PartFilter implements FilterInterface
|
|||
return $this->parametersCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TextConstraint
|
||||
*/
|
||||
public function getLotDescription(): TextConstraint
|
||||
{
|
||||
return $this->lotDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BooleanConstraint
|
||||
*/
|
||||
public function getObsolete(): BooleanConstraint
|
||||
{
|
||||
return $this->obsolete;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LessThanDesiredConstraint
|
||||
*/
|
||||
public function getLessThanDesired(): LessThanDesiredConstraint
|
||||
{
|
||||
return $this->lessThanDesired;
|
||||
|
|
|
@ -26,9 +26,6 @@ use Doctrine\ORM\QueryBuilder;
|
|||
class PartSearchFilter implements FilterInterface
|
||||
{
|
||||
|
||||
/** @var string The string to query for */
|
||||
protected string $keyword;
|
||||
|
||||
/** @var boolean Whether to use regex for searching */
|
||||
protected bool $regex = false;
|
||||
|
||||
|
@ -68,9 +65,11 @@ class PartSearchFilter implements FilterInterface
|
|||
/** @var bool Use Internal Part number for searching */
|
||||
protected bool $ipn = true;
|
||||
|
||||
public function __construct(string $query)
|
||||
public function __construct(
|
||||
/** @var string The string to query for */
|
||||
protected string $keyword
|
||||
)
|
||||
{
|
||||
$this->keyword = $query;
|
||||
}
|
||||
|
||||
protected function getFieldsToSearch(): array
|
||||
|
@ -122,12 +121,12 @@ class PartSearchFilter implements FilterInterface
|
|||
$fields_to_search = $this->getFieldsToSearch();
|
||||
|
||||
//If we have nothing to search for, do nothing
|
||||
if (empty($fields_to_search) || empty($this->keyword)) {
|
||||
if ($fields_to_search === [] || empty($this->keyword)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Convert the fields to search to a list of expressions
|
||||
$expressions = array_map(function (string $field) {
|
||||
$expressions = array_map(function (string $field): string {
|
||||
if ($this->regex) {
|
||||
return sprintf("REGEXP(%s, :search_query) = 1", $field);
|
||||
}
|
||||
|
@ -148,162 +147,99 @@ class PartSearchFilter implements FilterInterface
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getKeyword(): string
|
||||
{
|
||||
return $this->keyword;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $keyword
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setKeyword(string $keyword): PartSearchFilter
|
||||
{
|
||||
$this->keyword = $keyword;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isRegex(): bool
|
||||
{
|
||||
return $this->regex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $regex
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setRegex(bool $regex): PartSearchFilter
|
||||
{
|
||||
$this->regex = $regex;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isName(): bool
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $name
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setName(bool $name): PartSearchFilter
|
||||
{
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isCategory(): bool
|
||||
{
|
||||
return $this->category;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $category
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setCategory(bool $category): PartSearchFilter
|
||||
{
|
||||
$this->category = $category;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isDescription(): bool
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $description
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setDescription(bool $description): PartSearchFilter
|
||||
{
|
||||
$this->description = $description;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isTags(): bool
|
||||
{
|
||||
return $this->tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $tags
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setTags(bool $tags): PartSearchFilter
|
||||
{
|
||||
$this->tags = $tags;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isStorelocation(): bool
|
||||
{
|
||||
return $this->storelocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $storelocation
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setStorelocation(bool $storelocation): PartSearchFilter
|
||||
{
|
||||
$this->storelocation = $storelocation;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isOrdernr(): bool
|
||||
{
|
||||
return $this->ordernr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $ordernr
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setOrdernr(bool $ordernr): PartSearchFilter
|
||||
{
|
||||
$this->ordernr = $ordernr;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isMpn(): bool
|
||||
{
|
||||
return $this->mpn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $mpn
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setMpn(bool $mpn): PartSearchFilter
|
||||
{
|
||||
$this->mpn = $mpn;
|
||||
|
@ -321,72 +257,44 @@ class PartSearchFilter implements FilterInterface
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isSupplier(): bool
|
||||
{
|
||||
return $this->supplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $supplier
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setSupplier(bool $supplier): PartSearchFilter
|
||||
{
|
||||
$this->supplier = $supplier;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isManufacturer(): bool
|
||||
{
|
||||
return $this->manufacturer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $manufacturer
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setManufacturer(bool $manufacturer): PartSearchFilter
|
||||
{
|
||||
$this->manufacturer = $manufacturer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isFootprint(): bool
|
||||
{
|
||||
return $this->footprint;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $footprint
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setFootprint(bool $footprint): PartSearchFilter
|
||||
{
|
||||
$this->footprint = $footprint;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isComment(): bool
|
||||
{
|
||||
return $this->comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $comment
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setComment(bool $comment): PartSearchFilter
|
||||
{
|
||||
$this->comment = $comment;
|
||||
|
|
|
@ -31,19 +31,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
*/
|
||||
class PartDataTableHelper
|
||||
{
|
||||
private PartPreviewGenerator $previewGenerator;
|
||||
private AttachmentURLGenerator $attachmentURLGenerator;
|
||||
|
||||
private TranslatorInterface $translator;
|
||||
private EntityURLGenerator $entityURLGenerator;
|
||||
|
||||
public function __construct(PartPreviewGenerator $previewGenerator, AttachmentURLGenerator $attachmentURLGenerator,
|
||||
EntityURLGenerator $entityURLGenerator, TranslatorInterface $translator)
|
||||
public function __construct(private readonly PartPreviewGenerator $previewGenerator, private readonly AttachmentURLGenerator $attachmentURLGenerator, private readonly EntityURLGenerator $entityURLGenerator, private readonly TranslatorInterface $translator)
|
||||
{
|
||||
$this->previewGenerator = $previewGenerator;
|
||||
$this->attachmentURLGenerator = $attachmentURLGenerator;
|
||||
$this->translator = $translator;
|
||||
$this->entityURLGenerator = $entityURLGenerator;
|
||||
}
|
||||
|
||||
public function renderName(Part $context): string
|
||||
|
@ -57,7 +46,7 @@ class PartDataTableHelper
|
|||
if ($context->isNeedsReview()) {
|
||||
$icon = sprintf('<i class="fa-solid fa-ambulance fa-fw me-1" title="%s"></i>', $this->translator->trans('part.needs_review.badge'));
|
||||
}
|
||||
if ($context->getBuiltProject() !== null) {
|
||||
if ($context->getBuiltProject() instanceof \App\Entity\ProjectSystem\Project) {
|
||||
$icon = sprintf('<i class="fa-solid fa-box-archive fa-fw me-1" title="%s"></i>',
|
||||
$this->translator->trans('part.info.projectBuildPart.hint') . ': ' . $context->getBuiltProject()->getName());
|
||||
}
|
||||
|
@ -74,7 +63,7 @@ class PartDataTableHelper
|
|||
public function renderPicture(Part $context): string
|
||||
{
|
||||
$preview_attachment = $this->previewGenerator->getTablePreviewAttachment($context);
|
||||
if (null === $preview_attachment) {
|
||||
if (!$preview_attachment instanceof \App\Entity\Attachments\Attachment) {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
|
|
@ -61,27 +61,13 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
|
||||
class LogDataTable implements DataTableTypeInterface
|
||||
{
|
||||
protected ElementTypeNameGenerator $elementTypeNameGenerator;
|
||||
protected TranslatorInterface $translator;
|
||||
protected UrlGeneratorInterface $urlGenerator;
|
||||
protected EntityURLGenerator $entityURLGenerator;
|
||||
protected LogEntryRepository $logRepo;
|
||||
protected \Symfony\Bundle\SecurityBundle\Security $security;
|
||||
protected UserAvatarHelper $userAvatarHelper;
|
||||
protected LogLevelHelper $logLevelHelper;
|
||||
|
||||
public function __construct(ElementTypeNameGenerator $elementTypeNameGenerator, TranslatorInterface $translator,
|
||||
UrlGeneratorInterface $urlGenerator, EntityURLGenerator $entityURLGenerator, EntityManagerInterface $entityManager,
|
||||
\Symfony\Bundle\SecurityBundle\Security $security, UserAvatarHelper $userAvatarHelper, LogLevelHelper $logLevelHelper)
|
||||
public function __construct(protected ElementTypeNameGenerator $elementTypeNameGenerator, protected TranslatorInterface $translator,
|
||||
protected UrlGeneratorInterface $urlGenerator, protected EntityURLGenerator $entityURLGenerator, EntityManagerInterface $entityManager,
|
||||
protected \Symfony\Bundle\SecurityBundle\Security $security, protected UserAvatarHelper $userAvatarHelper, protected LogLevelHelper $logLevelHelper)
|
||||
{
|
||||
$this->elementTypeNameGenerator = $elementTypeNameGenerator;
|
||||
$this->translator = $translator;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->entityURLGenerator = $entityURLGenerator;
|
||||
$this->logRepo = $entityManager->getRepository(AbstractLogEntry::class);
|
||||
$this->security = $security;
|
||||
$this->userAvatarHelper = $userAvatarHelper;
|
||||
$this->logLevelHelper = $logLevelHelper;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $optionsResolver): void
|
||||
|
@ -115,21 +101,17 @@ class LogDataTable implements DataTableTypeInterface
|
|||
|
||||
//This special $$rowClass column is used to set the row class depending on the log level. The class gets set by the frontend controller
|
||||
$dataTable->add('dont_matter', RowClassColumn::class, [
|
||||
'render' => function ($value, AbstractLogEntry $context) {
|
||||
return $this->logLevelHelper->logLevelToTableColorClass($context->getLevelString());
|
||||
},
|
||||
'render' => fn($value, AbstractLogEntry $context) => $this->logLevelHelper->logLevelToTableColorClass($context->getLevelString()),
|
||||
]);
|
||||
|
||||
$dataTable->add('symbol', TextColumn::class, [
|
||||
'label' => '',
|
||||
'className' => 'no-colvis',
|
||||
'render' => function ($value, AbstractLogEntry $context) {
|
||||
return sprintf(
|
||||
'<i class="fas fa-fw %s" title="%s"></i>',
|
||||
$this->logLevelHelper->logLevelToIconClass($context->getLevelString()),
|
||||
$context->getLevelString()
|
||||
);
|
||||
},
|
||||
'render' => fn($value, AbstractLogEntry $context): string => sprintf(
|
||||
'<i class="fas fa-fw %s" title="%s"></i>',
|
||||
$this->logLevelHelper->logLevelToIconClass($context->getLevelString()),
|
||||
$context->getLevelString()
|
||||
),
|
||||
]);
|
||||
|
||||
$dataTable->add('id', TextColumn::class, [
|
||||
|
@ -140,12 +122,10 @@ class LogDataTable implements DataTableTypeInterface
|
|||
$dataTable->add('timestamp', LocaleDateTimeColumn::class, [
|
||||
'label' => 'log.timestamp',
|
||||
'timeFormat' => 'medium',
|
||||
'render' => function (string $value, AbstractLogEntry $context) {
|
||||
return sprintf('<a href="%s">%s</a>',
|
||||
$this->urlGenerator->generate('log_details', ['id' => $context->getId()]),
|
||||
$value
|
||||
);
|
||||
}
|
||||
'render' => fn(string $value, AbstractLogEntry $context): string => sprintf('<a href="%s">%s</a>',
|
||||
$this->urlGenerator->generate('log_details', ['id' => $context->getId()]),
|
||||
$value
|
||||
)
|
||||
]);
|
||||
|
||||
$dataTable->add('type', TextColumn::class, [
|
||||
|
@ -169,18 +149,16 @@ class LogDataTable implements DataTableTypeInterface
|
|||
'label' => 'log.level',
|
||||
'visible' => 'system_log' === $options['mode'],
|
||||
'propertyPath' => 'levelString',
|
||||
'render' => function (string $value, AbstractLogEntry $context) {
|
||||
return $this->translator->trans('log.level.'.$value);
|
||||
},
|
||||
'render' => fn(string $value, AbstractLogEntry $context) => $this->translator->trans('log.level.'.$value),
|
||||
]);
|
||||
|
||||
$dataTable->add('user', TextColumn::class, [
|
||||
'label' => 'log.user',
|
||||
'render' => function ($value, AbstractLogEntry $context) {
|
||||
'render' => function ($value, AbstractLogEntry $context): string {
|
||||
$user = $context->getUser();
|
||||
|
||||
//If user was deleted, show the info from the username field
|
||||
if ($user === null) {
|
||||
if (!$user instanceof \App\Entity\UserSystem\User) {
|
||||
if ($context->isCLIEntry()) {
|
||||
return sprintf('%s [%s]',
|
||||
htmlentities($context->getCLIUsername()),
|
||||
|
@ -241,19 +219,17 @@ class LogDataTable implements DataTableTypeInterface
|
|||
) {
|
||||
try {
|
||||
$target = $this->logRepo->getTargetElement($context);
|
||||
if (null !== $target) {
|
||||
if ($target instanceof \App\Entity\Base\AbstractDBElement) {
|
||||
return $this->entityURLGenerator->timeTravelURL($target, $context->getTimestamp());
|
||||
}
|
||||
} catch (EntityNotSupportedException $exception) {
|
||||
} catch (EntityNotSupportedException) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
'disabled' => function ($value, AbstractLogEntry $context) {
|
||||
return !$this->security->isGranted('show_history', $context->getTargetClass());
|
||||
},
|
||||
'disabled' => fn($value, AbstractLogEntry $context) => !$this->security->isGranted('show_history', $context->getTargetClass()),
|
||||
]);
|
||||
|
||||
$dataTable->add('actionRevert', RevertLogColumn::class, [
|
||||
|
@ -310,7 +286,7 @@ class LogDataTable implements DataTableTypeInterface
|
|||
foreach ($options['filter_elements'] as $element) {
|
||||
/** @var AbstractDBElement $element */
|
||||
|
||||
$target_type = AbstractLogEntry::targetTypeClassToID(get_class($element));
|
||||
$target_type = AbstractLogEntry::targetTypeClassToID($element::class);
|
||||
$target_id = $element->getID();
|
||||
$builder->orWhere("log.target_type = ${target_type} AND log.target_id = ${target_id}");
|
||||
}
|
||||
|
|
|
@ -54,22 +54,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
|
||||
final class PartsDataTable implements DataTableTypeInterface
|
||||
{
|
||||
private TranslatorInterface $translator;
|
||||
private AmountFormatter $amountFormatter;
|
||||
private \Symfony\Bundle\SecurityBundle\Security $security;
|
||||
|
||||
private PartDataTableHelper $partDataTableHelper;
|
||||
|
||||
private EntityURLGenerator $urlGenerator;
|
||||
|
||||
public function __construct(EntityURLGenerator $urlGenerator, TranslatorInterface $translator,
|
||||
AmountFormatter $amountFormatter,PartDataTableHelper $partDataTableHelper, \Symfony\Bundle\SecurityBundle\Security $security)
|
||||
public function __construct(private readonly EntityURLGenerator $urlGenerator, private readonly TranslatorInterface $translator, private readonly AmountFormatter $amountFormatter, private readonly PartDataTableHelper $partDataTableHelper, private readonly \Symfony\Bundle\SecurityBundle\Security $security)
|
||||
{
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->translator = $translator;
|
||||
$this->amountFormatter = $amountFormatter;
|
||||
$this->security = $security;
|
||||
$this->partDataTableHelper = $partDataTableHelper;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $optionsResolver): void
|
||||
|
@ -92,7 +78,7 @@ final class PartsDataTable implements DataTableTypeInterface
|
|||
$dataTable
|
||||
//Color the table rows depending on the review and favorite status
|
||||
->add('dont_matter', RowClassColumn::class, [
|
||||
'render' => function ($value, Part $context) {
|
||||
'render' => function ($value, Part $context): string {
|
||||
if ($context->isNeedsReview()) {
|
||||
return 'table-secondary';
|
||||
}
|
||||
|
@ -108,15 +94,11 @@ final class PartsDataTable implements DataTableTypeInterface
|
|||
->add('picture', TextColumn::class, [
|
||||
'label' => '',
|
||||
'className' => 'no-colvis',
|
||||
'render' => function ($value, Part $context) {
|
||||
return $this->partDataTableHelper->renderPicture($context);
|
||||
},
|
||||
'render' => fn($value, Part $context) => $this->partDataTableHelper->renderPicture($context),
|
||||
])
|
||||
->add('name', TextColumn::class, [
|
||||
'label' => $this->translator->trans('part.table.name'),
|
||||
'render' => function ($value, Part $context) {
|
||||
return $this->partDataTableHelper->renderName($context);
|
||||
},
|
||||
'render' => fn($value, Part $context) => $this->partDataTableHelper->renderName($context),
|
||||
])
|
||||
->add('id', TextColumn::class, [
|
||||
'label' => $this->translator->trans('part.table.id'),
|
||||
|
@ -153,11 +135,11 @@ final class PartsDataTable implements DataTableTypeInterface
|
|||
$dataTable->add('storelocation', TextColumn::class, [
|
||||
'label' => $this->translator->trans('part.table.storeLocations'),
|
||||
'orderField' => 'storelocations.name',
|
||||
'render' => function ($value, Part $context) {
|
||||
'render' => function ($value, Part $context): string {
|
||||
$tmp = [];
|
||||
foreach ($context->getPartLots() as $lot) {
|
||||
//Ignore lots without storelocation
|
||||
if (null === $lot->getStorageLocation()) {
|
||||
if (!$lot->getStorageLocation() instanceof \App\Entity\Parts\Storelocation) {
|
||||
continue;
|
||||
}
|
||||
$tmp[] = sprintf(
|
||||
|
@ -216,9 +198,7 @@ final class PartsDataTable implements DataTableTypeInterface
|
|||
->add('minamount', TextColumn::class, [
|
||||
'label' => $this->translator->trans('part.table.minamount'),
|
||||
'visible' => false,
|
||||
'render' => function ($value, Part $context) {
|
||||
return htmlspecialchars($this->amountFormatter->format($value, $context->getPartUnit()));
|
||||
},
|
||||
'render' => fn($value, Part $context): string => htmlspecialchars($this->amountFormatter->format($value, $context->getPartUnit())),
|
||||
]);
|
||||
|
||||
if ($this->security->isGranted('@footprints.read')) {
|
||||
|
@ -278,12 +258,8 @@ final class PartsDataTable implements DataTableTypeInterface
|
|||
->add('edit', IconLinkColumn::class, [
|
||||
'label' => $this->translator->trans('part.table.edit'),
|
||||
'visible' => false,
|
||||
'href' => function ($value, Part $context) {
|
||||
return $this->urlGenerator->editURL($context);
|
||||
},
|
||||
'disabled' => function ($value, Part $context) {
|
||||
return !$this->security->isGranted('edit', $context);
|
||||
},
|
||||
'href' => fn($value, Part $context) => $this->urlGenerator->editURL($context),
|
||||
'disabled' => fn($value, Part $context) => !$this->security->isGranted('edit', $context),
|
||||
'title' => $this->translator->trans('part.table.edit.title'),
|
||||
])
|
||||
|
||||
|
|
|
@ -40,18 +40,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
|
||||
class ProjectBomEntriesDataTable implements DataTableTypeInterface
|
||||
{
|
||||
protected TranslatorInterface $translator;
|
||||
protected PartDataTableHelper $partDataTableHelper;
|
||||
protected EntityURLGenerator $entityURLGenerator;
|
||||
protected AmountFormatter $amountFormatter;
|
||||
|
||||
public function __construct(TranslatorInterface $translator, PartDataTableHelper $partDataTableHelper,
|
||||
EntityURLGenerator $entityURLGenerator, AmountFormatter $amountFormatter)
|
||||
public function __construct(protected TranslatorInterface $translator, protected PartDataTableHelper $partDataTableHelper, protected EntityURLGenerator $entityURLGenerator, protected AmountFormatter $amountFormatter)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
$this->partDataTableHelper = $partDataTableHelper;
|
||||
$this->entityURLGenerator = $entityURLGenerator;
|
||||
$this->amountFormatter = $amountFormatter;
|
||||
}
|
||||
|
||||
|
||||
|
@ -63,7 +53,7 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface
|
|||
'label' => '',
|
||||
'className' => 'no-colvis',
|
||||
'render' => function ($value, ProjectBOMEntry $context) {
|
||||
if($context->getPart() === null) {
|
||||
if(!$context->getPart() instanceof \App\Entity\Parts\Part) {
|
||||
return '';
|
||||
}
|
||||
return $this->partDataTableHelper->renderPicture($context->getPart());
|
||||
|
@ -79,9 +69,9 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface
|
|||
'label' => $this->translator->trans('project.bom.quantity'),
|
||||
'className' => 'text-center',
|
||||
'orderField' => 'bom_entry.quantity',
|
||||
'render' => function ($value, ProjectBOMEntry $context) {
|
||||
'render' => function ($value, ProjectBOMEntry $context): float|string {
|
||||
//If we have a non-part entry, only show the rounded quantity
|
||||
if ($context->getPart() === null) {
|
||||
if (!$context->getPart() instanceof \App\Entity\Parts\Part) {
|
||||
return round($context->getQuantity());
|
||||
}
|
||||
//Otherwise use the unit of the part to format the quantity
|
||||
|
@ -93,10 +83,10 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface
|
|||
'label' => $this->translator->trans('part.table.name'),
|
||||
'orderField' => 'part.name',
|
||||
'render' => function ($value, ProjectBOMEntry $context) {
|
||||
if($context->getPart() === null) {
|
||||
if(!$context->getPart() instanceof \App\Entity\Parts\Part) {
|
||||
return htmlspecialchars($context->getName());
|
||||
}
|
||||
if($context->getPart() !== null) {
|
||||
if($context->getPart() instanceof \App\Entity\Parts\Part) {
|
||||
$tmp = $this->partDataTableHelper->renderName($context->getPart());
|
||||
if(!empty($context->getName())) {
|
||||
$tmp .= '<br><b>'.htmlspecialchars($context->getName()).'</b>';
|
||||
|
@ -110,7 +100,7 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface
|
|||
->add('description', MarkdownColumn::class, [
|
||||
'label' => $this->translator->trans('part.table.description'),
|
||||
'data' => function (ProjectBOMEntry $context) {
|
||||
if($context->getPart() !== null) {
|
||||
if($context->getPart() instanceof \App\Entity\Parts\Part) {
|
||||
return $context->getPart()->getDescription();
|
||||
}
|
||||
//For non-part BOM entries show the comment field
|
||||
|
|
|
@ -47,11 +47,8 @@ use function preg_match;
|
|||
*/
|
||||
class ResetAutoIncrementORMPurger implements PurgerInterface, ORMPurgerInterface
|
||||
{
|
||||
public const PURGE_MODE_DELETE = 1;
|
||||
public const PURGE_MODE_TRUNCATE = 2;
|
||||
|
||||
/** @var EntityManagerInterface|null */
|
||||
private ?EntityManagerInterface $em;
|
||||
final public const PURGE_MODE_DELETE = 1;
|
||||
final public const PURGE_MODE_TRUNCATE = 2;
|
||||
|
||||
/**
|
||||
* If the purge should be done through DELETE or TRUNCATE statements
|
||||
|
@ -60,31 +57,26 @@ class ResetAutoIncrementORMPurger implements PurgerInterface, ORMPurgerInterface
|
|||
*/
|
||||
private int $purgeMode = self::PURGE_MODE_DELETE;
|
||||
|
||||
/**
|
||||
* Table/view names to be excluded from purge
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private array $excluded;
|
||||
|
||||
/**
|
||||
* Construct new purger instance.
|
||||
*
|
||||
* @param EntityManagerInterface|null $em EntityManagerInterface instance used for persistence.
|
||||
* @param string[] $excluded array of table/view names to be excluded from purge
|
||||
*/
|
||||
public function __construct(?EntityManagerInterface $em = null, array $excluded = [])
|
||||
public function __construct(
|
||||
private ?\Doctrine\ORM\EntityManagerInterface $em = null,
|
||||
/**
|
||||
* Table/view names to be excluded from purge
|
||||
*/
|
||||
private readonly array $excluded = []
|
||||
)
|
||||
{
|
||||
$this->em = $em;
|
||||
$this->excluded = $excluded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the purge mode
|
||||
*
|
||||
* @param int $mode
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPurgeMode(int $mode): void
|
||||
{
|
||||
|
@ -93,8 +85,6 @@ class ResetAutoIncrementORMPurger implements PurgerInterface, ORMPurgerInterface
|
|||
|
||||
/**
|
||||
* Get the purge mode
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getPurgeMode(): int
|
||||
{
|
||||
|
@ -123,7 +113,7 @@ class ResetAutoIncrementORMPurger implements PurgerInterface, ORMPurgerInterface
|
|||
$classes = [];
|
||||
|
||||
foreach ($this->em->getMetadataFactory()->getAllMetadata() as $metadata) {
|
||||
if ($metadata->isMappedSuperclass || (isset($metadata->isEmbeddedClass) && $metadata->isEmbeddedClass)) {
|
||||
if ($metadata->isMappedSuperclass || ($metadata->isEmbeddedClass !== null && $metadata->isEmbeddedClass)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -143,7 +133,7 @@ class ResetAutoIncrementORMPurger implements PurgerInterface, ORMPurgerInterface
|
|||
$class = $commitOrder[$i];
|
||||
|
||||
if (
|
||||
(isset($class->isEmbeddedClass) && $class->isEmbeddedClass) ||
|
||||
($class->isEmbeddedClass !== null && $class->isEmbeddedClass) ||
|
||||
$class->isMappedSuperclass ||
|
||||
($class->isInheritanceTypeSingleTable() && $class->name !== $class->rootEntityName)
|
||||
) {
|
||||
|
@ -172,13 +162,13 @@ class ResetAutoIncrementORMPurger implements PurgerInterface, ORMPurgerInterface
|
|||
|
||||
foreach ($orderedTables as $tbl) {
|
||||
// If we have a filter expression, check it and skip if necessary
|
||||
if (! $emptyFilterExpression && ! preg_match($filterExpr, $tbl)) {
|
||||
if (! $emptyFilterExpression && ! preg_match($filterExpr, (string) $tbl)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The table name might be quoted, we have to trim it
|
||||
// See https://github.com/Part-DB/Part-DB-server/issues/299
|
||||
$tbl = trim($tbl, '"');
|
||||
$tbl = trim((string) $tbl, '"');
|
||||
$tbl = trim($tbl, '`');
|
||||
|
||||
// If the table is excluded, skip it as well
|
||||
|
@ -276,11 +266,6 @@ class ResetAutoIncrementORMPurger implements PurgerInterface, ORMPurgerInterface
|
|||
return array_reverse($sorter->sort());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $classes
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getAssociationTables(array $classes, AbstractPlatform $platform): array
|
||||
{
|
||||
$associationTables = [];
|
||||
|
@ -310,9 +295,6 @@ class ResetAutoIncrementORMPurger implements PurgerInterface, ORMPurgerInterface
|
|||
return $this->em->getConfiguration()->getQuoteStrategy()->getTableName($class, $platform);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $assoc
|
||||
*/
|
||||
private function getJoinTableName(
|
||||
array $assoc,
|
||||
ClassMetadata $class,
|
||||
|
|
|
@ -45,7 +45,7 @@ class SQLiteRegexExtension implements EventSubscriberInterface
|
|||
if($native_connection instanceof \PDO && method_exists($native_connection, 'sqliteCreateFunction' )) {
|
||||
$native_connection->sqliteCreateFunction('REGEXP', function ($pattern, $value) {
|
||||
try {
|
||||
return (false !== mb_ereg($pattern, $value)) ? 1 : 0;
|
||||
return (mb_ereg($pattern, $value)) ? 1 : 0;
|
||||
} catch (\ErrorException $e) {
|
||||
throw InvalidRegexException::fromMBRegexError($e);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ use Doctrine\DBAL\Types\Type;
|
|||
|
||||
class BigDecimalType extends Type
|
||||
{
|
||||
public const BIG_DECIMAL = 'big_decimal';
|
||||
final public const BIG_DECIMAL = 'big_decimal';
|
||||
|
||||
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string
|
||||
{
|
||||
|
@ -53,7 +53,7 @@ class BigDecimalType extends Type
|
|||
*/
|
||||
public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string
|
||||
{
|
||||
if (null === $value) {
|
||||
if (!$value instanceof \Brick\Math\BigDecimal) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ class UTCDateTimeType extends DateTimeType
|
|||
*/
|
||||
public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string
|
||||
{
|
||||
if (!self::$utc_timezone) {
|
||||
if (!self::$utc_timezone instanceof \DateTimeZone) {
|
||||
self::$utc_timezone = new DateTimeZone('UTC');
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ class UTCDateTimeType extends DateTimeType
|
|||
|
||||
public function convertToPHPValue($value, AbstractPlatform $platform): ?DateTime
|
||||
{
|
||||
if (!self::$utc_timezone) {
|
||||
if (!self::$utc_timezone instanceof \DateTimeZone) {
|
||||
self::$utc_timezone = new DateTimeZone('UTC');
|
||||
}
|
||||
|
||||
|
|
|
@ -34,11 +34,11 @@ use LogicException;
|
|||
/**
|
||||
* Class Attachment.
|
||||
*/
|
||||
#[ORM\Entity(repositoryClass: 'App\Repository\AttachmentRepository')]
|
||||
#[ORM\Entity(repositoryClass: \App\Repository\AttachmentRepository::class)]
|
||||
#[ORM\InheritanceType('SINGLE_TABLE')]
|
||||
#[ORM\DiscriminatorColumn(name: 'class_name', type: 'string')]
|
||||
#[ORM\DiscriminatorMap(['PartDB\Part' => 'PartAttachment', 'Part' => 'PartAttachment', 'PartDB\Device' => 'ProjectAttachment', 'Device' => 'ProjectAttachment', 'AttachmentType' => 'AttachmentTypeAttachment', 'Category' => 'CategoryAttachment', 'Footprint' => 'FootprintAttachment', 'Manufacturer' => 'ManufacturerAttachment', 'Currency' => 'CurrencyAttachment', 'Group' => 'GroupAttachment', 'MeasurementUnit' => 'MeasurementUnitAttachment', 'Storelocation' => 'StorelocationAttachment', 'Supplier' => 'SupplierAttachment', 'User' => 'UserAttachment', 'LabelProfile' => 'LabelAttachment'])]
|
||||
#[ORM\EntityListeners(['App\EntityListeners\AttachmentDeleteListener'])]
|
||||
#[ORM\EntityListeners([\App\EntityListeners\AttachmentDeleteListener::class])]
|
||||
#[ORM\Table(name: '`attachments`')]
|
||||
#[ORM\Index(name: 'attachments_idx_id_element_id_class_name', columns: ['id', 'element_id', 'class_name'])]
|
||||
#[ORM\Index(name: 'attachments_idx_class_name_id', columns: ['class_name', 'id'])]
|
||||
|
@ -51,23 +51,23 @@ abstract class Attachment extends AbstractNamedDBElement
|
|||
* Based on: https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types
|
||||
* It will be used to determine if an attachment is a picture and therefore will be shown to user as preview.
|
||||
*/
|
||||
public const PICTURE_EXTS = ['apng', 'bmp', 'gif', 'ico', 'cur', 'jpg', 'jpeg', 'jfif', 'pjpeg', 'pjp', 'png',
|
||||
final public const PICTURE_EXTS = ['apng', 'bmp', 'gif', 'ico', 'cur', 'jpg', 'jpeg', 'jfif', 'pjpeg', 'pjp', 'png',
|
||||
'svg', 'webp', ];
|
||||
|
||||
/**
|
||||
* A list of extensions that will be treated as a 3D Model that can be shown to user directly in Part-DB.
|
||||
*/
|
||||
public const MODEL_EXTS = ['x3d'];
|
||||
final public const MODEL_EXTS = ['x3d'];
|
||||
|
||||
/**
|
||||
* When the path begins with one of the placeholders.
|
||||
*/
|
||||
public const INTERNAL_PLACEHOLDER = ['%BASE%', '%MEDIA%', '%SECURE%'];
|
||||
final public const INTERNAL_PLACEHOLDER = ['%BASE%', '%MEDIA%', '%SECURE%'];
|
||||
|
||||
/**
|
||||
* @var array placeholders for attachments which using built in files
|
||||
*/
|
||||
public const BUILTIN_PLACEHOLDER = ['%FOOTPRINTS%', '%FOOTPRINTS3D%'];
|
||||
final public const BUILTIN_PLACEHOLDER = ['%FOOTPRINTS%', '%FOOTPRINTS3D%'];
|
||||
|
||||
/**
|
||||
* @var string The class of the element that can be passed to this attachment. Must be overridden in subclasses.
|
||||
|
|
|
@ -33,7 +33,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
|||
/**
|
||||
* Class AttachmentType.
|
||||
*/
|
||||
#[ORM\Entity(repositoryClass: 'App\Repository\StructuralDBElementRepository')]
|
||||
#[ORM\Entity(repositoryClass: \App\Repository\StructuralDBElementRepository::class)]
|
||||
#[ORM\Table(name: '`attachment_types`')]
|
||||
#[ORM\Index(name: 'attachment_types_idx_name', columns: ['name'])]
|
||||
#[ORM\Index(name: 'attachment_types_idx_parent_name', columns: ['parent_id', 'name'])]
|
||||
|
@ -45,7 +45,7 @@ class AttachmentType extends AbstractStructuralDBElement
|
|||
|
||||
#[ORM\ManyToOne(targetEntity: 'AttachmentType', inversedBy: 'children')]
|
||||
#[ORM\JoinColumn(name: 'parent_id')]
|
||||
protected ?AbstractStructuralDBElement $parent;
|
||||
protected ?AbstractStructuralDBElement $parent = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
|
@ -57,14 +57,14 @@ class AttachmentType extends AbstractStructuralDBElement
|
|||
* @var Collection<int, AttachmentTypeAttachment>
|
||||
*/
|
||||
#[Assert\Valid]
|
||||
#[ORM\OneToMany(targetEntity: 'App\Entity\Attachments\AttachmentTypeAttachment', mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
|
||||
#[ORM\OneToMany(targetEntity: \App\Entity\Attachments\AttachmentTypeAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
|
||||
#[ORM\OrderBy(['name' => 'ASC'])]
|
||||
protected Collection $attachments;
|
||||
|
||||
/** @var Collection<int, AttachmentTypeParameter>
|
||||
*/
|
||||
#[Assert\Valid]
|
||||
#[ORM\OneToMany(targetEntity: 'App\Entity\Parameters\AttachmentTypeParameter', mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
|
||||
#[ORM\OneToMany(targetEntity: \App\Entity\Parameters\AttachmentTypeParameter::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
|
||||
#[ORM\OrderBy(['group' => 'ASC', 'name' => 'ASC'])]
|
||||
protected Collection $parameters;
|
||||
|
||||
|
|
|
@ -32,11 +32,11 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
|||
#[ORM\Entity]
|
||||
class AttachmentTypeAttachment extends Attachment
|
||||
{
|
||||
public const ALLOWED_ELEMENT_CLASS = AttachmentType::class;
|
||||
final public const ALLOWED_ELEMENT_CLASS = AttachmentType::class;
|
||||
/**
|
||||
* @var AttachmentContainingDBElement|null the element this attachment is associated with
|
||||
*/
|
||||
#[ORM\ManyToOne(targetEntity: 'App\Entity\Attachments\AttachmentType', inversedBy: 'attachments')]
|
||||
#[ORM\ManyToOne(targetEntity: \App\Entity\Attachments\AttachmentType::class, inversedBy: 'attachments')]
|
||||
#[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')]
|
||||
protected ?AttachmentContainingDBElement $element = null;
|
||||
}
|
||||
|
|
|
@ -33,11 +33,11 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
|||
#[ORM\Entity]
|
||||
class CategoryAttachment extends Attachment
|
||||
{
|
||||
public const ALLOWED_ELEMENT_CLASS = Category::class;
|
||||
final public const ALLOWED_ELEMENT_CLASS = Category::class;
|
||||
/**
|
||||
* @var AttachmentContainingDBElement|null the element this attachment is associated with
|
||||
*/
|
||||
#[ORM\ManyToOne(targetEntity: 'App\Entity\Parts\Category', inversedBy: 'attachments')]
|
||||
#[ORM\ManyToOne(targetEntity: \App\Entity\Parts\Category::class, inversedBy: 'attachments')]
|
||||
#[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')]
|
||||
protected ?AttachmentContainingDBElement $element = null;
|
||||
}
|
||||
|
|
|
@ -33,11 +33,11 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
|||
#[ORM\Entity]
|
||||
class CurrencyAttachment extends Attachment
|
||||
{
|
||||
public const ALLOWED_ELEMENT_CLASS = Currency::class;
|
||||
final public const ALLOWED_ELEMENT_CLASS = Currency::class;
|
||||
/**
|
||||
* @var Currency|null the element this attachment is associated with
|
||||
*/
|
||||
#[ORM\ManyToOne(targetEntity: 'App\Entity\PriceInformations\Currency', inversedBy: 'attachments')]
|
||||
#[ORM\ManyToOne(targetEntity: \App\Entity\PriceInformations\Currency::class, inversedBy: 'attachments')]
|
||||
#[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')]
|
||||
protected ?AttachmentContainingDBElement $element = null;
|
||||
}
|
||||
|
|
|
@ -33,11 +33,11 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
|||
#[ORM\Entity]
|
||||
class FootprintAttachment extends Attachment
|
||||
{
|
||||
public const ALLOWED_ELEMENT_CLASS = Footprint::class;
|
||||
final public const ALLOWED_ELEMENT_CLASS = Footprint::class;
|
||||
/**
|
||||
* @var Footprint|null the element this attachment is associated with
|
||||
*/
|
||||
#[ORM\ManyToOne(targetEntity: 'App\Entity\Parts\Footprint', inversedBy: 'attachments')]
|
||||
#[ORM\ManyToOne(targetEntity: \App\Entity\Parts\Footprint::class, inversedBy: 'attachments')]
|
||||
#[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')]
|
||||
protected ?AttachmentContainingDBElement $element = null;
|
||||
}
|
||||
|
|
|
@ -33,12 +33,12 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
|||
#[ORM\Entity]
|
||||
class GroupAttachment extends Attachment
|
||||
{
|
||||
public const ALLOWED_ELEMENT_CLASS = Group::class;
|
||||
final public const ALLOWED_ELEMENT_CLASS = Group::class;
|
||||
|
||||
/**
|
||||
* @var Group|null the element this attachment is associated with
|
||||
*/
|
||||
#[ORM\ManyToOne(targetEntity: 'App\Entity\UserSystem\Group', inversedBy: 'attachments')]
|
||||
#[ORM\ManyToOne(targetEntity: \App\Entity\UserSystem\Group::class, inversedBy: 'attachments')]
|
||||
#[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')]
|
||||
protected ?AttachmentContainingDBElement $element = null;
|
||||
}
|
||||
|
|
|
@ -52,12 +52,12 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
|||
#[ORM\Entity]
|
||||
class LabelAttachment extends Attachment
|
||||
{
|
||||
public const ALLOWED_ELEMENT_CLASS = LabelProfile::class;
|
||||
final public const ALLOWED_ELEMENT_CLASS = LabelProfile::class;
|
||||
|
||||
/**
|
||||
* @var LabelProfile the element this attachment is associated with
|
||||
*/
|
||||
#[ORM\ManyToOne(targetEntity: 'App\Entity\LabelSystem\LabelProfile', inversedBy: 'attachments')]
|
||||
#[ORM\ManyToOne(targetEntity: \App\Entity\LabelSystem\LabelProfile::class, inversedBy: 'attachments')]
|
||||
#[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')]
|
||||
protected ?AttachmentContainingDBElement $element = null;
|
||||
}
|
||||
|
|
|
@ -33,12 +33,12 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
|||
#[ORM\Entity]
|
||||
class ManufacturerAttachment extends Attachment
|
||||
{
|
||||
public const ALLOWED_ELEMENT_CLASS = Manufacturer::class;
|
||||
final public const ALLOWED_ELEMENT_CLASS = Manufacturer::class;
|
||||
|
||||
/**
|
||||
* @var Manufacturer|null the element this attachment is associated with
|
||||
*/
|
||||
#[ORM\ManyToOne(targetEntity: 'App\Entity\Parts\Manufacturer', inversedBy: 'attachments')]
|
||||
#[ORM\ManyToOne(targetEntity: \App\Entity\Parts\Manufacturer::class, inversedBy: 'attachments')]
|
||||
#[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')]
|
||||
protected ?AttachmentContainingDBElement $element = null;
|
||||
}
|
||||
|
|
|
@ -34,11 +34,11 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
|||
#[ORM\Entity]
|
||||
class MeasurementUnitAttachment extends Attachment
|
||||
{
|
||||
public const ALLOWED_ELEMENT_CLASS = MeasurementUnit::class;
|
||||
final public const ALLOWED_ELEMENT_CLASS = MeasurementUnit::class;
|
||||
/**
|
||||
* @var Manufacturer|null the element this attachment is associated with
|
||||
*/
|
||||
#[ORM\ManyToOne(targetEntity: 'App\Entity\Parts\MeasurementUnit', inversedBy: 'attachments')]
|
||||
#[ORM\ManyToOne(targetEntity: \App\Entity\Parts\MeasurementUnit::class, inversedBy: 'attachments')]
|
||||
#[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')]
|
||||
protected ?AttachmentContainingDBElement $element = null;
|
||||
}
|
||||
|
|
|
@ -33,11 +33,11 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
|||
#[ORM\Entity]
|
||||
class PartAttachment extends Attachment
|
||||
{
|
||||
public const ALLOWED_ELEMENT_CLASS = Part::class;
|
||||
final public const ALLOWED_ELEMENT_CLASS = Part::class;
|
||||
/**
|
||||
* @var Part the element this attachment is associated with
|
||||
*/
|
||||
#[ORM\ManyToOne(targetEntity: 'App\Entity\Parts\Part', inversedBy: 'attachments')]
|
||||
#[ORM\ManyToOne(targetEntity: \App\Entity\Parts\Part::class, inversedBy: 'attachments')]
|
||||
#[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')]
|
||||
protected ?AttachmentContainingDBElement $element = null;
|
||||
}
|
||||
|
|
|
@ -33,11 +33,11 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
|||
#[ORM\Entity]
|
||||
class ProjectAttachment extends Attachment
|
||||
{
|
||||
public const ALLOWED_ELEMENT_CLASS = Project::class;
|
||||
final public const ALLOWED_ELEMENT_CLASS = Project::class;
|
||||
/**
|
||||
* @var Project|null the element this attachment is associated with
|
||||
*/
|
||||
#[ORM\ManyToOne(targetEntity: 'App\Entity\ProjectSystem\Project', inversedBy: 'attachments')]
|
||||
#[ORM\ManyToOne(targetEntity: \App\Entity\ProjectSystem\Project::class, inversedBy: 'attachments')]
|
||||
#[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')]
|
||||
protected ?AttachmentContainingDBElement $element = null;
|
||||
}
|
||||
|
|
|
@ -33,12 +33,12 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
|||
#[ORM\Entity]
|
||||
class StorelocationAttachment extends Attachment
|
||||
{
|
||||
public const ALLOWED_ELEMENT_CLASS = Storelocation::class;
|
||||
final public const ALLOWED_ELEMENT_CLASS = Storelocation::class;
|
||||
|
||||
/**
|
||||
* @var Storelocation|null the element this attachment is associated with
|
||||
*/
|
||||
#[ORM\ManyToOne(targetEntity: 'App\Entity\Parts\Storelocation', inversedBy: 'attachments')]
|
||||
#[ORM\ManyToOne(targetEntity: \App\Entity\Parts\Storelocation::class, inversedBy: 'attachments')]
|
||||
#[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')]
|
||||
protected ?AttachmentContainingDBElement $element = null;
|
||||
}
|
||||
|
|
|
@ -33,12 +33,12 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
|||
#[ORM\Entity]
|
||||
class SupplierAttachment extends Attachment
|
||||
{
|
||||
public const ALLOWED_ELEMENT_CLASS = Supplier::class;
|
||||
final public const ALLOWED_ELEMENT_CLASS = Supplier::class;
|
||||
|
||||
/**
|
||||
* @var Supplier|null the element this attachment is associated with
|
||||
*/
|
||||
#[ORM\ManyToOne(targetEntity: 'App\Entity\Parts\Supplier', inversedBy: 'attachments')]
|
||||
#[ORM\ManyToOne(targetEntity: \App\Entity\Parts\Supplier::class, inversedBy: 'attachments')]
|
||||
#[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')]
|
||||
protected ?AttachmentContainingDBElement $element = null;
|
||||
}
|
||||
|
|
|
@ -33,12 +33,12 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
|||
#[ORM\Entity]
|
||||
class UserAttachment extends Attachment
|
||||
{
|
||||
public const ALLOWED_ELEMENT_CLASS = User::class;
|
||||
final public const ALLOWED_ELEMENT_CLASS = User::class;
|
||||
|
||||
/**
|
||||
* @var User|null the element this attachment is associated with
|
||||
*/
|
||||
#[ORM\ManyToOne(targetEntity: 'App\Entity\UserSystem\User', inversedBy: 'attachments')]
|
||||
#[ORM\ManyToOne(targetEntity: \App\Entity\UserSystem\User::class, inversedBy: 'attachments')]
|
||||
#[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')]
|
||||
protected ?AttachmentContainingDBElement $element = null;
|
||||
}
|
||||
|
|
|
@ -35,8 +35,8 @@ use Symfony\Component\Serializer\Annotation\Groups;
|
|||
* Every database table which are managed with this class (or a subclass of it)
|
||||
* must have the table row "id"!! The ID is the unique key to identify the elements.
|
||||
*/
|
||||
#[DiscriminatorMap(typeProperty: 'type', mapping: ['attachment_type' => 'App\Entity\Attachments\AttachmentType', 'attachment' => 'App\Entity\Attachments\Attachment', 'attachment_type_attachment' => 'App\Entity\Attachments\AttachmentTypeAttachment', 'category_attachment' => 'App\Entity\Attachments\CategoryAttachment', 'currency_attachment' => 'App\Entity\Attachments\CurrencyAttachment', 'footprint_attachment' => 'App\Entity\Attachments\FootprintAttachment', 'group_attachment' => 'App\Entity\Attachments\GroupAttachment', 'label_attachment' => 'App\Entity\Attachments\LabelAttachment', 'manufacturer_attachment' => 'App\Entity\Attachments\ManufacturerAttachment', 'measurement_unit_attachment' => 'App\Entity\Attachments\MeasurementUnitAttachment', 'part_attachment' => 'App\Entity\Attachments\PartAttachment', 'project_attachment' => 'App\Entity\Attachments\ProjectAttachment', 'storelocation_attachment' => 'App\Entity\Attachments\StorelocationAttachment', 'supplier_attachment' => 'App\Entity\Attachments\SupplierAttachment', 'user_attachment' => 'App\Entity\Attachments\UserAttachment', 'category' => 'App\Entity\Parts\Category', 'project' => 'App\Entity\ProjectSystem\Project', 'project_bom_entry' => 'App\Entity\ProjectSystem\ProjectBOMEntry', 'footprint' => 'App\Entity\Parts\Footprint', 'group' => 'App\Entity\UserSystem\Group', 'manufacturer' => 'App\Entity\Parts\Manufacturer', 'orderdetail' => 'App\Entity\PriceInformations\Orderdetail', 'part' => 'App\Entity\Parts\Part', 'pricedetail' => 'App\Entity\PriceInformation\Pricedetail', 'storelocation' => 'App\Entity\Parts\Storelocation', 'part_lot' => 'App\Entity\Parts\PartLot', 'currency' => 'App\Entity\PriceInformations\Currency', 'measurement_unit' => 'App\Entity\Parts\MeasurementUnit', 'parameter' => 'App\Entity\Parts\AbstractParameter', 'supplier' => 'App\Entity\Parts\Supplier', 'user' => 'App\Entity\UserSystem\User'])]
|
||||
#[ORM\MappedSuperclass(repositoryClass: 'App\Repository\DBElementRepository')]
|
||||
#[DiscriminatorMap(typeProperty: 'type', mapping: ['attachment_type' => \App\Entity\Attachments\AttachmentType::class, 'attachment' => \App\Entity\Attachments\Attachment::class, 'attachment_type_attachment' => \App\Entity\Attachments\AttachmentTypeAttachment::class, 'category_attachment' => \App\Entity\Attachments\CategoryAttachment::class, 'currency_attachment' => \App\Entity\Attachments\CurrencyAttachment::class, 'footprint_attachment' => \App\Entity\Attachments\FootprintAttachment::class, 'group_attachment' => \App\Entity\Attachments\GroupAttachment::class, 'label_attachment' => \App\Entity\Attachments\LabelAttachment::class, 'manufacturer_attachment' => \App\Entity\Attachments\ManufacturerAttachment::class, 'measurement_unit_attachment' => \App\Entity\Attachments\MeasurementUnitAttachment::class, 'part_attachment' => \App\Entity\Attachments\PartAttachment::class, 'project_attachment' => \App\Entity\Attachments\ProjectAttachment::class, 'storelocation_attachment' => \App\Entity\Attachments\StorelocationAttachment::class, 'supplier_attachment' => \App\Entity\Attachments\SupplierAttachment::class, 'user_attachment' => \App\Entity\Attachments\UserAttachment::class, 'category' => \App\Entity\Parts\Category::class, 'project' => \App\Entity\ProjectSystem\Project::class, 'project_bom_entry' => \App\Entity\ProjectSystem\ProjectBOMEntry::class, 'footprint' => \App\Entity\Parts\Footprint::class, 'group' => \App\Entity\UserSystem\Group::class, 'manufacturer' => \App\Entity\Parts\Manufacturer::class, 'orderdetail' => \App\Entity\PriceInformations\Orderdetail::class, 'part' => \App\Entity\Parts\Part::class, 'pricedetail' => 'App\Entity\PriceInformation\Pricedetail', 'storelocation' => \App\Entity\Parts\Storelocation::class, 'part_lot' => \App\Entity\Parts\PartLot::class, 'currency' => \App\Entity\PriceInformations\Currency::class, 'measurement_unit' => \App\Entity\Parts\MeasurementUnit::class, 'parameter' => 'App\Entity\Parts\AbstractParameter', 'supplier' => \App\Entity\Parts\Supplier::class, 'user' => \App\Entity\UserSystem\User::class])]
|
||||
#[ORM\MappedSuperclass(repositoryClass: \App\Repository\DBElementRepository::class)]
|
||||
abstract class AbstractDBElement implements JsonSerializable
|
||||
{
|
||||
/** @var int|null The Identification number for this part. This value is unique for the element in this table.
|
||||
|
|
|
@ -33,7 +33,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
|||
*/
|
||||
#[ORM\MappedSuperclass(repositoryClass: 'App\Repository\NamedDBElement')]
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
abstract class AbstractNamedDBElement extends AbstractDBElement implements NamedElementInterface, TimeStampableInterface
|
||||
abstract class AbstractNamedDBElement extends AbstractDBElement implements NamedElementInterface, TimeStampableInterface, \Stringable
|
||||
{
|
||||
use TimestampTrait;
|
||||
|
||||
|
@ -51,7 +51,7 @@ abstract class AbstractNamedDBElement extends AbstractDBElement implements Named
|
|||
*
|
||||
******************************************************************************/
|
||||
|
||||
public function __toString()
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->getName();
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ use Symfony\Component\Serializer\Annotation\Groups;
|
|||
/**
|
||||
* Class PartsContainingDBElement.
|
||||
*/
|
||||
#[ORM\MappedSuperclass(repositoryClass: 'App\Repository\AbstractPartsContainingRepository')]
|
||||
#[ORM\MappedSuperclass(repositoryClass: \App\Repository\AbstractPartsContainingRepository::class)]
|
||||
abstract class AbstractPartsContainingDBElement extends AbstractStructuralDBElement
|
||||
{
|
||||
#[Groups(['full'])]
|
||||
|
|
|
@ -46,8 +46,8 @@ use Symfony\Component\Serializer\Annotation\Groups;
|
|||
*
|
||||
*/
|
||||
#[UniqueEntity(fields: ['name', 'parent'], ignoreNull: false, message: 'structural.entity.unique_name')]
|
||||
#[ORM\MappedSuperclass(repositoryClass: 'App\Repository\StructuralDBElementRepository')]
|
||||
#[ORM\EntityListeners(['App\EntityListeners\TreeCacheInvalidationListener'])]
|
||||
#[ORM\MappedSuperclass(repositoryClass: \App\Repository\StructuralDBElementRepository::class)]
|
||||
#[ORM\EntityListeners([\App\EntityListeners\TreeCacheInvalidationListener::class])]
|
||||
abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
|
||||
{
|
||||
use ParametersTrait;
|
||||
|
@ -105,7 +105,6 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
|
|||
parent::__construct();
|
||||
$this->children = new ArrayCollection();
|
||||
$this->parameters = new ArrayCollection();
|
||||
$this->parent = null;
|
||||
}
|
||||
|
||||
public function __clone()
|
||||
|
@ -141,11 +140,11 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
|
|||
|
||||
//Check if both elements compared, are from the same type
|
||||
// (we have to check inheritance, or we get exceptions when using doctrine entities (they have a proxy type):
|
||||
if (!is_a($another_element, $class_name) && !is_a($this, get_class($another_element))) {
|
||||
if (!$another_element instanceof $class_name && !is_a($this, $another_element::class)) {
|
||||
throw new InvalidArgumentException('isChildOf() only works for objects of the same type!');
|
||||
}
|
||||
|
||||
if (null === $this->getParent()) { // this is the root node
|
||||
if (!$this->getParent() instanceof \App\Entity\Base\AbstractStructuralDBElement) { // this is the root node
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -170,7 +169,7 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
|
|||
*/
|
||||
public function isRoot(): bool
|
||||
{
|
||||
return null === $this->parent;
|
||||
return !$this->parent instanceof \App\Entity\Base\AbstractStructuralDBElement;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -213,9 +212,9 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
|
|||
/*
|
||||
* Only check for nodes that have a parent. In the other cases zero is correct.
|
||||
*/
|
||||
if (0 === $this->level && null !== $this->parent) {
|
||||
if (0 === $this->level && $this->parent instanceof \App\Entity\Base\AbstractStructuralDBElement) {
|
||||
$element = $this->parent;
|
||||
while (null !== $element) {
|
||||
while ($element instanceof \App\Entity\Base\AbstractStructuralDBElement) {
|
||||
/** @var AbstractStructuralDBElement $element */
|
||||
$element = $element->parent;
|
||||
++$this->level;
|
||||
|
@ -234,14 +233,14 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
|
|||
*/
|
||||
public function getFullPath(string $delimiter = self::PATH_DELIMITER_ARROW): string
|
||||
{
|
||||
if (empty($this->full_path_strings)) {
|
||||
if ($this->full_path_strings === []) {
|
||||
$this->full_path_strings = [];
|
||||
$this->full_path_strings[] = $this->getName();
|
||||
$element = $this;
|
||||
|
||||
$overflow = 20; //We only allow 20 levels depth
|
||||
|
||||
while (null !== $element->parent && $overflow >= 0) {
|
||||
while ($element->parent instanceof \App\Entity\Base\AbstractStructuralDBElement && $overflow >= 0) {
|
||||
$element = $element->parent;
|
||||
$this->full_path_strings[] = $element->getName();
|
||||
//Decrement to prevent mem overflow.
|
||||
|
@ -328,7 +327,7 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
|
|||
$this->parent = $new_parent;
|
||||
|
||||
//Add this element as child to the new parent
|
||||
if (null !== $new_parent) {
|
||||
if ($new_parent instanceof \App\Entity\Base\AbstractStructuralDBElement) {
|
||||
$new_parent->getChildren()->add($this);
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ trait MasterAttachmentTrait
|
|||
* @var Attachment|null
|
||||
*/
|
||||
#[Assert\Expression('value == null or value.isPicture()', message: 'part.master_attachment.must_be_picture')]
|
||||
#[ORM\ManyToOne(targetEntity: 'App\Entity\Attachments\Attachment')]
|
||||
#[ORM\ManyToOne(targetEntity: \App\Entity\Attachments\Attachment::class)]
|
||||
#[ORM\JoinColumn(name: 'id_preview_attachment', onDelete: 'SET NULL')]
|
||||
protected ?Attachment $master_picture_attachment = null;
|
||||
|
||||
|
|
|
@ -47,11 +47,11 @@ use Symfony\Component\Validator\Constraints as Assert;
|
|||
#[ORM\Embeddable]
|
||||
class LabelOptions
|
||||
{
|
||||
public const BARCODE_TYPES = ['none', /*'ean8',*/ 'qr', 'code39', 'datamatrix', 'code93', 'code128'];
|
||||
public const SUPPORTED_ELEMENTS = ['part', 'part_lot', 'storelocation'];
|
||||
public const PICTURE_TYPES = ['none', 'element_picture', 'main_attachment'];
|
||||
final public const BARCODE_TYPES = ['none', /*'ean8',*/ 'qr', 'code39', 'datamatrix', 'code93', 'code128'];
|
||||
final public const SUPPORTED_ELEMENTS = ['part', 'part_lot', 'storelocation'];
|
||||
final public const PICTURE_TYPES = ['none', 'element_picture', 'main_attachment'];
|
||||
|
||||
public const LINES_MODES = ['html', 'twig'];
|
||||
final public const LINES_MODES = ['html', 'twig'];
|
||||
|
||||
/**
|
||||
* @var float The page size of the label in mm
|
||||
|
@ -111,9 +111,6 @@ class LabelOptions
|
|||
return $this->width;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LabelOptions
|
||||
*/
|
||||
public function setWidth(float $width): self
|
||||
{
|
||||
$this->width = $width;
|
||||
|
@ -126,9 +123,6 @@ class LabelOptions
|
|||
return $this->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LabelOptions
|
||||
*/
|
||||
public function setHeight(float $height): self
|
||||
{
|
||||
$this->height = $height;
|
||||
|
@ -141,9 +135,6 @@ class LabelOptions
|
|||
return $this->barcode_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LabelOptions
|
||||
*/
|
||||
public function setBarcodeType(string $barcode_type): self
|
||||
{
|
||||
$this->barcode_type = $barcode_type;
|
||||
|
@ -156,9 +147,6 @@ class LabelOptions
|
|||
return $this->picture_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LabelOptions
|
||||
*/
|
||||
public function setPictureType(string $picture_type): self
|
||||
{
|
||||
$this->picture_type = $picture_type;
|
||||
|
@ -171,9 +159,6 @@ class LabelOptions
|
|||
return $this->supported_element;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LabelOptions
|
||||
*/
|
||||
public function setSupportedElement(string $supported_element): self
|
||||
{
|
||||
$this->supported_element = $supported_element;
|
||||
|
@ -186,9 +171,6 @@ class LabelOptions
|
|||
return $this->lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LabelOptions
|
||||
*/
|
||||
public function setLines(string $lines): self
|
||||
{
|
||||
$this->lines = $lines;
|
||||
|
@ -204,9 +186,6 @@ class LabelOptions
|
|||
return $this->additional_css;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LabelOptions
|
||||
*/
|
||||
public function setAdditionalCss(string $additional_css): self
|
||||
{
|
||||
$this->additional_css = $additional_css;
|
||||
|
@ -219,9 +198,6 @@ class LabelOptions
|
|||
return $this->lines_mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LabelOptions
|
||||
*/
|
||||
public function setLinesMode(string $lines_mode): self
|
||||
{
|
||||
$this->lines_mode = $lines_mode;
|
||||
|
|
|
@ -49,15 +49,15 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
|||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[UniqueEntity(['name', 'options.supported_element'])]
|
||||
#[ORM\Entity(repositoryClass: 'App\Repository\LabelProfileRepository')]
|
||||
#[ORM\EntityListeners(['App\EntityListeners\TreeCacheInvalidationListener'])]
|
||||
#[ORM\Entity(repositoryClass: \App\Repository\LabelProfileRepository::class)]
|
||||
#[ORM\EntityListeners([\App\EntityListeners\TreeCacheInvalidationListener::class])]
|
||||
#[ORM\Table(name: 'label_profiles')]
|
||||
class LabelProfile extends AttachmentContainingDBElement
|
||||
{
|
||||
/**
|
||||
* @var Collection<int, LabelAttachment>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: 'App\Entity\Attachments\LabelAttachment', mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
|
||||
#[ORM\OneToMany(targetEntity: \App\Entity\Attachments\LabelAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
|
||||
#[ORM\OrderBy(['name' => 'ASC'])]
|
||||
protected Collection $attachments;
|
||||
|
||||
|
@ -126,8 +126,6 @@ class LabelProfile extends AttachmentContainingDBElement
|
|||
|
||||
/**
|
||||
* Sets the show in dropdown menu.
|
||||
*
|
||||
* @return LabelProfile
|
||||
*/
|
||||
public function setShowInDropdown(bool $show_in_dropdown): self
|
||||
{
|
||||
|
|
|
@ -61,14 +61,14 @@ use App\Repository\LogEntryRepository;
|
|||
#[ORM\Index(columns: ['datetime'], name: 'log_idx_datetime')]
|
||||
abstract class AbstractLogEntry extends AbstractDBElement
|
||||
{
|
||||
public const LEVEL_EMERGENCY = 0;
|
||||
public const LEVEL_ALERT = 1;
|
||||
public const LEVEL_CRITICAL = 2;
|
||||
public const LEVEL_ERROR = 3;
|
||||
public const LEVEL_WARNING = 4;
|
||||
public const LEVEL_NOTICE = 5;
|
||||
public const LEVEL_INFO = 6;
|
||||
public const LEVEL_DEBUG = 7;
|
||||
final public const LEVEL_EMERGENCY = 0;
|
||||
final public const LEVEL_ALERT = 1;
|
||||
final public const LEVEL_CRITICAL = 2;
|
||||
final public const LEVEL_ERROR = 3;
|
||||
final public const LEVEL_WARNING = 4;
|
||||
final public const LEVEL_NOTICE = 5;
|
||||
final public const LEVEL_INFO = 6;
|
||||
final public const LEVEL_DEBUG = 7;
|
||||
|
||||
protected const TARGET_TYPE_NONE = 0;
|
||||
protected const TARGET_TYPE_USER = 1;
|
||||
|
@ -129,7 +129,7 @@ abstract class AbstractLogEntry extends AbstractDBElement
|
|||
|
||||
/** @var User|null The user which has caused this log entry
|
||||
*/
|
||||
#[ORM\ManyToOne(targetEntity: 'App\Entity\UserSystem\User', fetch: 'EAGER')]
|
||||
#[ORM\ManyToOne(targetEntity: \App\Entity\UserSystem\User::class, fetch: 'EAGER')]
|
||||
#[ORM\JoinColumn(name: 'id_user', onDelete: 'SET NULL')]
|
||||
protected ?User $user = null;
|
||||
|
||||
|
@ -147,7 +147,7 @@ abstract class AbstractLogEntry extends AbstractDBElement
|
|||
/** @var int The priority level of the associated level. 0 is highest, 7 lowest
|
||||
*/
|
||||
#[ORM\Column(type: 'tinyint', name: 'level')]
|
||||
protected int $level;
|
||||
protected int $level = self::LEVEL_WARNING;
|
||||
|
||||
/** @var int The ID of the element targeted by this event
|
||||
*/
|
||||
|
@ -173,7 +173,6 @@ abstract class AbstractLogEntry extends AbstractDBElement
|
|||
public function __construct()
|
||||
{
|
||||
$this->timestamp = new DateTime();
|
||||
$this->level = self::LEVEL_WARNING;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -214,7 +213,6 @@ abstract class AbstractLogEntry extends AbstractDBElement
|
|||
* Marks this log entry as a CLI entry, and set the username of the CLI user.
|
||||
* This removes the association to a user object in database, as CLI users are not really related to logged in
|
||||
* Part-DB users.
|
||||
* @param string $cli_username
|
||||
* @return $this
|
||||
*/
|
||||
public function setCLIUsername(string $cli_username): self
|
||||
|
@ -372,14 +370,14 @@ abstract class AbstractLogEntry extends AbstractDBElement
|
|||
*/
|
||||
public function setTargetElement(?AbstractDBElement $element): self
|
||||
{
|
||||
if (null === $element) {
|
||||
if (!$element instanceof \App\Entity\Base\AbstractDBElement) {
|
||||
$this->target_id = 0;
|
||||
$this->target_type = self::TARGET_TYPE_NONE;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->target_type = static::targetTypeClassToID(get_class($element));
|
||||
$this->target_type = static::targetTypeClassToID($element::class);
|
||||
$this->target_id = $element->getID();
|
||||
|
||||
return $this;
|
||||
|
|
|
@ -93,11 +93,9 @@ class CollectionElementDeleted extends AbstractLogEntry implements LogWithEventU
|
|||
public function __construct(AbstractDBElement $changed_element, string $collection_name, AbstractDBElement $deletedElement)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->level = self::LEVEL_INFO;
|
||||
$this->setTargetElement($changed_element);
|
||||
$this->extra['n'] = $collection_name;
|
||||
$this->extra['c'] = self::targetTypeClassToID(get_class($deletedElement));
|
||||
$this->extra['c'] = self::targetTypeClassToID($deletedElement::class);
|
||||
$this->extra['i'] = $deletedElement->getID();
|
||||
if ($deletedElement instanceof NamedElementInterface) {
|
||||
$this->extra['o'] = $deletedElement->getName();
|
||||
|
@ -141,8 +139,6 @@ class CollectionElementDeleted extends AbstractLogEntry implements LogWithEventU
|
|||
/**
|
||||
* This functions maps an abstract class name derived from the extra c element to an instantiable class name (based on the target element of this log entry).
|
||||
* For example if the target element is a part and the extra c element is "App\Entity\Attachments\Attachment", this function will return "App\Entity\Attachments\PartAttachment".
|
||||
* @param string $abstract_class
|
||||
* @return string
|
||||
*/
|
||||
private function resolveAbstractClassToInstantiableClass(string $abstract_class): string
|
||||
{
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue