Merge branch 'master' into log_detail_page

This commit is contained in:
Jan Böhmer 2023-04-29 22:46:38 +02:00
commit 4c6ceab8e8
291 changed files with 1994 additions and 1621 deletions

View file

@ -10,7 +10,6 @@ use PhpZip\ZipFile;
use Spatie\DbDumper\Databases\MySql;
use Spatie\DbDumper\DbDumper;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\Input;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;

View file

@ -45,12 +45,12 @@ use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
use function count;
/**
* This command converts the BBCode used by old Part-DB versions (<1.0), to the current used markdown format.
* This command converts the BBCode used by old Part-DB versions (<1.0), to the current used Markdown format.
*/
class ConvertBBCodeCommand extends Command
{
/**
* @var string The LIKE criteria used to detect on SQL server if a entry contains BBCode
* @var string The LIKE criteria used to detect on SQL server if an entry contains BBCode
*/
protected const BBCODE_CRITERIA = '%[%]%[/%]%';
/**

View file

@ -69,7 +69,7 @@ class ImportPartKeeprCommand extends Command
$this->addOption('--import-users', null, InputOption::VALUE_NONE, 'Import users (passwords will not be imported).');
}
public function execute(InputInterface $input, OutputInterface $output)
public function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);

View file

@ -27,9 +27,7 @@ use App\Services\LogSystem\EventCommentHelper;
use App\Services\UserSystem\PermissionSchemaUpdater;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
@ -91,12 +89,12 @@ 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(function (Group $group) {
$io->listing(array_map(static function (Group $group) {
return $group->getName() . ' (ID: '. $group->getID() .', Current version: ' . $group->getPermissions()->getSchemaVersion() . ')';
}, $groups_to_upgrade));
$io->section('Users that need an update:');
$io->listing(array_map(function (User $user) {
$io->listing(array_map(static function (User $user) {
return $user->getUsername() . ' (ID: '. $user->getID() .', Current version: ' . $user->getPermissions()->getSchemaVersion() . ')';
}, $users_to_upgrade));

View file

@ -87,7 +87,7 @@ class UserEnableCommand extends Command
$io->note('The following users will be enabled:');
}
$io->table(['Username', 'Enabled/Disabled'],
array_map(function(User $user) {
array_map(static function(User $user) {
return [$user->getFullName(true), $user->isDisabled() ? 'Disabled' : 'Enabled'];
}, $users));

View file

@ -269,7 +269,6 @@ abstract class BaseAdminController extends AbstractController
protected function _new(Request $request, EntityManagerInterface $em, EntityImporter $importer, ?AbstractNamedDBElement $entity = null)
{
$master_picture_backup = null;
if (null === $entity) {
/** @var AbstractStructuralDBElement|User $new_entity */
$new_entity = new $this->entity_class();
@ -390,7 +389,7 @@ abstract class BaseAdminController extends AbstractController
foreach ($errors as $error) {
if ($error['entity'] instanceof AbstractStructuralDBElement) {
$this->addFlash('error', $error['entity']->getFullPath().':'.$error['violations']);
} else { //When we dont have a structural element, we can only show the name
} else { //When we don't have a structural element, we can only show the name
$this->addFlash('error', $error['entity']->getName().':'.$error['violations']);
}
}
@ -413,11 +412,11 @@ abstract class BaseAdminController extends AbstractController
}
/**
* Performs checks if the element can be deleted safely. Otherwise an flash message is added.
* Performs checks if the element can be deleted safely. Otherwise, a flash message is added.
*
* @param AbstractNamedDBElement $entity the element that should be checked
*
* @return bool True if the the element can be deleted, false if not
* @return bool True if the element can be deleted, false if not
*/
protected function deleteCheck(AbstractNamedDBElement $entity): bool
{

View file

@ -25,7 +25,6 @@ namespace App\Controller\AdminPages;
use App\Entity\Attachments\ProjectAttachment;
use App\Entity\ProjectSystem\Project;
use App\Entity\Parameters\ProjectParameter;
use App\Form\AdminPages\BaseEntityAdminForm;
use App\Form\AdminPages\ProjectAdminForm;
use App\Services\ImportExportSystem\EntityExporter;
use App\Services\ImportExportSystem\EntityImporter;

View file

@ -24,12 +24,8 @@ namespace App\Controller;
use App\DataTables\AttachmentDataTable;
use App\DataTables\Filters\AttachmentFilter;
use App\DataTables\Filters\PartFilter;
use App\DataTables\PartsDataTable;
use App\Entity\Attachments\Attachment;
use App\Entity\Attachments\PartAttachment;
use App\Form\Filters\AttachmentFilterType;
use App\Form\Filters\PartFilterType;
use App\Services\Attachments\AttachmentManager;
use App\Services\Trees\NodesListBuilder;
use Omines\DataTablesBundle\DataTableFactory;
@ -106,10 +102,8 @@ class AttachmentFileController extends AbstractController
/**
* @Route("/attachment/list", name="attachment_list")
*
* @return JsonResponse|Response
*/
public function attachmentsTable(Request $request, DataTableFactory $dataTableFactory, NodesListBuilder $nodesListBuilder)
public function attachmentsTable(Request $request, DataTableFactory $dataTableFactory, NodesListBuilder $nodesListBuilder): Response
{
$this->denyAccessUnlessGranted('@attachments.list_attachments');

View file

@ -74,9 +74,9 @@ class GroupController extends BaseAdminController
//We need to stop the execution here, or our permissions changes will be overwritten by the form values
return $this->redirectToRoute('group_edit', ['id' => $entity->getID()]);
} else {
$this->addFlash('danger', 'csfr_invalid');
}
$this->addFlash('danger', 'csfr_invalid');
}
return $this->_edit($entity, $request, $em, $timestamp);

View file

@ -68,9 +68,9 @@ class LogController extends AbstractController
/**
* @Route("/", name="log_view")
*
* @return JsonResponse|Response
* @return Response
*/
public function showLogs(Request $request, DataTableFactory $dataTable)
public function showLogs(Request $request, DataTableFactory $dataTable): Response
{
$this->denyAccessUnlessGranted('@system.show_logs');

View file

@ -53,7 +53,6 @@ use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Contracts\Translation\TranslatorInterface;
@ -351,8 +350,10 @@ class PartController extends AbstractController
if($partLot->getPart() !== $part) {
throw new \RuntimeException("The origin partlot does not belong to the part!");
}
//Try to determine the target lot (used for move actions)
$targetLot = $em->find(PartLot::class, $request->request->get('target_id'));
//Try to determine the target lot (used for move actions), if the parameter is existing
$targetId = $request->request->get('target_id', null);
$targetLot = $targetId ? $em->find(PartLot::class, $targetId) : null;
if ($targetLot && $targetLot->getPart() !== $part) {
throw new \RuntimeException("The target partlot does not belong to the part!");
}
@ -396,7 +397,7 @@ class PartController extends AbstractController
}
err:
//If an redirect was passed, then redirect there
//If a redirect was passed, then redirect there
if($request->request->get('_redirect')) {
return $this->redirect($request->request->get('_redirect'));
}

View file

@ -26,8 +26,6 @@ use App\Services\ImportExportSystem\EntityExporter;
use App\Services\ImportExportSystem\EntityImporter;
use App\Services\LogSystem\EventCommentHelper;
use App\Services\Parts\PartsTableActionHandler;
use Doctrine\ORM\EntityManagerInterface;
use InvalidArgumentException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;

View file

@ -158,7 +158,7 @@ class PartListsController extends AbstractController
*
* @return JsonResponse|Response
*/
public function showCategory(Category $category, Request $request)
public function showCategory(Category $category, Request $request): Response
{
$this->denyAccessUnlessGranted('@categories.read');
@ -180,7 +180,7 @@ class PartListsController extends AbstractController
*
* @return JsonResponse|Response
*/
public function showFootprint(Footprint $footprint, Request $request)
public function showFootprint(Footprint $footprint, Request $request): Response
{
$this->denyAccessUnlessGranted('@footprints.read');
@ -202,7 +202,7 @@ class PartListsController extends AbstractController
*
* @return JsonResponse|Response
*/
public function showManufacturer(Manufacturer $manufacturer, Request $request)
public function showManufacturer(Manufacturer $manufacturer, Request $request): Response
{
$this->denyAccessUnlessGranted('@manufacturers.read');
@ -224,7 +224,7 @@ class PartListsController extends AbstractController
*
* @return JsonResponse|Response
*/
public function showStorelocation(Storelocation $storelocation, Request $request)
public function showStorelocation(Storelocation $storelocation, Request $request): Response
{
$this->denyAccessUnlessGranted('@storelocations.read');
@ -246,7 +246,7 @@ class PartListsController extends AbstractController
*
* @return JsonResponse|Response
*/
public function showSupplier(Supplier $supplier, Request $request)
public function showSupplier(Supplier $supplier, Request $request): Response
{
$this->denyAccessUnlessGranted('@suppliers.read');
@ -268,7 +268,7 @@ class PartListsController extends AbstractController
*
* @return JsonResponse|Response
*/
public function showTag(string $tag, Request $request, DataTableFactory $dataTable)
public function showTag(string $tag, Request $request): Response
{
$tag = trim($tag);
@ -291,6 +291,7 @@ class PartListsController extends AbstractController
$filter->setName($request->query->getBoolean('name', true));
$filter->setCategory($request->query->getBoolean('category', true));
$filter->setDescription($request->query->getBoolean('description', true));
$filter->setMpn($request->query->getBoolean('mpn', true));
$filter->setTags($request->query->getBoolean('tags', true));
$filter->setStorelocation($request->query->getBoolean('storelocation', true));
$filter->setComment($request->query->getBoolean('comment', true));
@ -300,6 +301,7 @@ class PartListsController extends AbstractController
$filter->setManufacturer($request->query->getBoolean('manufacturer', false));
$filter->setFootprint($request->query->getBoolean('footprint', false));
$filter->setRegex($request->query->getBoolean('regex', false));
return $filter;
@ -310,7 +312,7 @@ class PartListsController extends AbstractController
*
* @return JsonResponse|Response
*/
public function showSearch(Request $request, DataTableFactory $dataTable)
public function showSearch(Request $request, DataTableFactory $dataTable): Response
{
$searchFilter = $this->searchRequestToFilter($request);
@ -331,9 +333,9 @@ class PartListsController extends AbstractController
/**
* @Route("/parts", name="parts_show_all")
*
* @return JsonResponse|Response
* @return Response
*/
public function showAll(Request $request, DataTableFactory $dataTable)
public function showAll(Request $request): Response
{
return $this->showListWithFilter($request,'parts/lists/all_list.html.twig');
}

View file

@ -32,10 +32,8 @@ use App\Services\ImportExportSystem\BOMImporter;
use App\Services\ProjectSystem\ProjectBuildHelper;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\EntityManagerInterface;
use League\Csv\Exception;
use League\Csv\SyntaxError;
use Omines\DataTablesBundle\DataTableFactory;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
@ -64,7 +62,7 @@ class ProjectController extends AbstractController
/**
* @Route("/{id}/info", name="project_info", requirements={"id"="\d+"})
*/
public function info(Project $project, Request $request, ProjectBuildHelper $buildHelper)
public function info(Project $project, Request $request, ProjectBuildHelper $buildHelper): Response
{
$this->denyAccessUnlessGranted('read', $project);
@ -114,9 +112,9 @@ class ProjectController extends AbstractController
$request->get('_redirect',
$this->generateUrl('project_info', ['id' => $project->getID()]
)));
} else {
$this->addFlash('error', 'project.build.flash.invalid_input');
}
$this->addFlash('error', 'project.build.flash.invalid_input');
}
return $this->renderForm('projects/build/build.html.twig', [

View file

@ -28,20 +28,17 @@ use function in_array;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class RedirectController extends AbstractController
{
protected string $default_locale;
protected TranslatorInterface $translator;
protected SessionInterface $session;
protected bool $enforce_index_php;
public function __construct(string $default_locale, TranslatorInterface $translator, SessionInterface $session, bool $enforce_index_php)
public function __construct(string $default_locale, TranslatorInterface $translator, bool $enforce_index_php)
{
$this->default_locale = $default_locale;
$this->session = $session;
$this->translator = $translator;
$this->enforce_index_php = $enforce_index_php;
}
@ -52,7 +49,7 @@ class RedirectController extends AbstractController
*/
public function addLocalePart(Request $request): RedirectResponse
{
//By default we use the global default locale
//By default, we use the global default locale
$locale = $this->default_locale;
//Check if a user has set a preferred language setting:
@ -61,7 +58,6 @@ class RedirectController extends AbstractController
$locale = $user->getLanguage();
}
//$new_url = str_replace($request->getPathInfo(), '/' . $locale . $request->getPathInfo(), $request->getUri());
$new_url = $request->getUriForPath('/'.$locale.$request->getPathInfo());
//If either mod_rewrite is not enabled or the index.php version is enforced, add index.php to the string
@ -71,6 +67,9 @@ class RedirectController extends AbstractController
$new_url = $request->getSchemeAndHttpHost().$request->getBaseUrl().'/index.php/'.$locale.$request->getPathInfo();
}
//Add the query string
$new_url .= $request->getQueryString() ? '?'.$request->getQueryString() : '';
return $this->redirect($new_url);
}

View file

@ -22,7 +22,6 @@ namespace App\Controller;
use App\Entity\Base\AbstractNamedDBElement;
use App\Entity\Base\AbstractStructuralDBElement;
use App\Entity\Contracts\NamedElementInterface;
use App\Entity\LabelSystem\LabelProfile;
use App\Entity\Parts\Category;
use App\Entity\Parts\Footprint;
@ -106,7 +105,7 @@ class SelectAPIController extends AbstractController
3 => $this->translator->trans('export.level.full'),
];
return $this->json(array_map(function ($key, $value) {
return $this->json(array_map(static function ($key, $value) {
return [
'text' => $value,
'value' => $key,
@ -198,7 +197,7 @@ class SelectAPIController extends AbstractController
]);
//Remove the data-* prefix for each key
$data = array_combine(
array_map(function ($key) {
array_map(static function ($key) {
if (strpos($key, 'data-') === 0) {
return substr($key, 5);
}

View file

@ -95,7 +95,7 @@ class TypeaheadController extends AbstractController
}
/**
* This functions map the parameter type to the class, so we can access its repository
* This function map the parameter type to the class, so we can access its repository
* @param string $type
* @return class-string
*/

View file

@ -25,7 +25,6 @@ namespace App\Controller;
use App\DataTables\LogDataTable;
use App\Entity\Attachments\UserAttachment;
use App\Entity\Base\AbstractNamedDBElement;
use App\Entity\Parameters\AbstractParameter;
use App\Entity\UserSystem\User;
use App\Events\SecurityEvent;
use App\Events\SecurityEvents;
@ -62,11 +61,11 @@ class UserController extends AdminPages\BaseAdminController
protected function additionalActionEdit(FormInterface $form, AbstractNamedDBElement $entity): bool
{
//Check if we editing a user and if we need to change the password of it
//Check if we're editing a user and if we need to change the password of it
if ($entity instanceof User && !empty($form['new_password']->getData())) {
$password = $this->passwordEncoder->hashPassword($entity, $form['new_password']->getData());
$entity->setPassword($password);
//By default the user must change the password afterwards
//By default, the user must change the password afterward
$entity->setNeedPwChange(true);
$event = new SecurityEvent($entity);
@ -129,9 +128,9 @@ class UserController extends AdminPages\BaseAdminController
//We need to stop the execution here, or our permissions changes will be overwritten by the form values
return $this->redirectToRoute('user_edit', ['id' => $entity->getID()]);
} else {
$this->addFlash('danger', 'csfr_invalid');
}
$this->addFlash('danger', 'csfr_invalid');
}
return $this->_edit($entity, $request, $em, $timestamp);
@ -142,7 +141,7 @@ class UserController extends AdminPages\BaseAdminController
if ($entity instanceof User && !empty($form['new_password']->getData())) {
$password = $this->passwordEncoder->hashPassword($entity, $form['new_password']->getData());
$entity->setPassword($password);
//By default the user must change the password afterwards
//By default, the user must change the password afterward
$entity->setNeedPwChange(true);
}

View file

@ -225,7 +225,7 @@ class UserSettingsController extends AbstractController
*/
public function userSettings(Request $request, EntityManagerInterface $em, UserPasswordHasherInterface $passwordEncoder, GoogleAuthenticator $googleAuthenticator, BackupCodeManager $backupCodeManager, FormFactoryInterface $formFactory, UserAvatarHelper $avatarHelper)
{
/** @var User */
/** @var User $user */
$user = $this->getUser();
$page_need_reload = false;
@ -261,7 +261,7 @@ class UserSettingsController extends AbstractController
$page_need_reload = true;
}
/** @var Form $form We need an form implementation for the next calls */
/** @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) {
@ -327,7 +327,7 @@ class UserSettingsController extends AbstractController
$pw_form->handleRequest($request);
//Check if password if everything was correct, then save it to User and DB
//Check if everything was correct, then save it to User and DB
if (!$this->demo_mode && $pw_form->isSubmitted() && $pw_form->isValid()) {
$password = $passwordEncoder->hashPassword($user, $pw_form['new_password']->getData());
$user->setPassword($password);

View file

@ -20,7 +20,6 @@
namespace App\DataTables\Adapters;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\Tools\Pagination\Paginator;
use Omines\DataTablesBundle\Adapter\Doctrine\FetchJoinORMAdapter;
@ -38,7 +37,7 @@ use Omines\DataTablesBundle\Adapter\Doctrine\FetchJoinORMAdapter;
*/
class CustomFetchJoinORMAdapter extends FetchJoinORMAdapter
{
public function getCount(QueryBuilder $queryBuilder, $identifier)
public function getCount(QueryBuilder $queryBuilder, $identifier): ?int
{
$qb_without_group_by = clone $queryBuilder;

View file

@ -22,9 +22,7 @@ declare(strict_types=1);
namespace App\DataTables\Column;
use App\Entity\Base\AbstractDBElement;
use App\Entity\Base\AbstractNamedDBElement;
use App\Entity\Parts\Part;
use App\Services\EntityURLGenerator;
use Omines\DataTablesBundle\Column\AbstractColumn;
use Symfony\Component\OptionsResolver\Options;

View file

@ -31,7 +31,7 @@ use Omines\DataTablesBundle\Column\AbstractColumn;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* Similar to the built in DateTimeColumn, but the datetime is formatted using a IntlDateFormatter,
* Similar to the built-in DateTimeColumn, but the datetime is formatted using a IntlDateFormatter,
* to get prettier locale based formatting.
*/
class LocaleDateTimeColumn extends AbstractColumn
@ -45,7 +45,9 @@ class LocaleDateTimeColumn extends AbstractColumn
{
if (null === $value) {
return $this->options['nullValue'];
} elseif (!$value instanceof DateTimeInterface) {
}
if (!$value instanceof DateTimeInterface) {
$value = new DateTime((string) $value);
}

View file

@ -41,7 +41,7 @@ class PrettyBoolColumn extends AbstractColumn
return (bool) $value;
}
public function render($value, $context)
public function render($value, $context): string
{
if ($value === true) {
return '<span class="badge bg-success"><i class="fa-solid fa-circle-check fa-fw"></i> '

View file

@ -27,7 +27,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
class RowClassColumn extends AbstractColumn
{
public function configureOptions(OptionsResolver $resolver)
public function configureOptions(OptionsResolver $resolver): self
{
parent::configureOptions($resolver);
@ -48,6 +48,9 @@ class RowClassColumn extends AbstractColumn
parent::initialize('$$rowClass', $index, $options, $dataTable); // TODO: Change the autogenerated stub
}
/**
* @return mixed
*/
public function normalize($value)
{
return $value;

View file

@ -33,7 +33,7 @@ class SIUnitNumberColumn extends AbstractColumn
$this->formatter = $formatter;
}
public function configureOptions(OptionsResolver $resolver)
public function configureOptions(OptionsResolver $resolver): self
{
parent::configureOptions($resolver);
@ -43,7 +43,7 @@ class SIUnitNumberColumn extends AbstractColumn
return $this;
}
public function normalize($value)
public function normalize($value): string
{
//Ignore null values
if ($value === null) {

View file

@ -28,7 +28,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
*/
class SelectColumn extends AbstractColumn
{
public function configureOptions(OptionsResolver $resolver)
public function configureOptions(OptionsResolver $resolver): self
{
parent::configureOptions($resolver);
@ -43,12 +43,15 @@ class SelectColumn extends AbstractColumn
return $this;
}
/**
* @return mixed
*/
public function normalize($value)
{
return $value;
}
public function render($value, $context)
public function render($value, $context): string
{
//Return empty string, as it this column is filled by datatables on client side
return '';

View file

@ -21,7 +21,6 @@
namespace App\DataTables\Filters\Constraints;
use App\DataTables\Filters\FilterInterface;
use Doctrine\ORM\QueryBuilder;
abstract class AbstractConstraint implements FilterInterface
{

View file

@ -20,7 +20,6 @@
namespace App\DataTables\Filters\Constraints;
use App\DataTables\Filters\FilterInterface;
use Doctrine\ORM\QueryBuilder;
class BooleanConstraint extends AbstractConstraint

View file

@ -20,7 +20,6 @@
namespace App\DataTables\Filters\Constraints;
use Doctrine\DBAL\ParameterType;
use Doctrine\ORM\QueryBuilder;
trait FilterTrait
@ -51,7 +50,7 @@ trait FilterTrait
protected function generateParameterIdentifier(string $property): string
{
//Replace all special characters with underscores
$property = preg_replace('/[^a-zA-Z0-9_]/', '_', $property);
$property = preg_replace('/\W/', '_', $property);
//Add a random number to the end of the property name for uniqueness
return $property . '_' . uniqid("", false);
}

View file

@ -98,7 +98,7 @@ class InstanceOfConstraint extends AbstractConstraint
if ($this->operator === 'ANY' || $this->operator === 'NONE') {
foreach($this->value as $value) {
//We cannnot use an paramater here, as this is the only way to pass the FCQN to the query (via binded params, we would need to use ClassMetaData). See: https://github.com/doctrine/orm/issues/4462
//We can not use a parameter here, as this is the only way to pass the FCQN to the query (via binded params, we would need to use ClassMetaData). See: https://github.com/doctrine/orm/issues/4462
$expressions[] = ($queryBuilder->expr()->isInstanceOf($this->property, $value));
}

View file

@ -20,7 +20,6 @@
namespace App\DataTables\Filters\Constraints;
use Doctrine\DBAL\ParameterType;
use Doctrine\ORM\QueryBuilder;
use RuntimeException;
@ -42,7 +41,7 @@ class NumberConstraint extends AbstractConstraint
protected $value2;
/**
* @var string The operator to use
* @var string|null The operator to use
*/
protected ?string $operator;

View file

@ -24,7 +24,6 @@ use App\DataTables\Filters\Constraints\AbstractConstraint;
use App\DataTables\Filters\Constraints\TextConstraint;
use App\Entity\Parameters\PartParameter;
use Doctrine\ORM\QueryBuilder;
use Svg\Tag\Text;
class ParameterConstraint extends AbstractConstraint
{

View file

@ -101,7 +101,7 @@ class TextConstraint extends AbstractConstraint
return;
}
//The CONTAINS, LIKE, STARTS and ENDS operators use the LIKE operator but we have to build the value string differently
//The CONTAINS, LIKE, STARTS and ENDS operators use the LIKE operator, but we have to build the value string differently
$like_value = null;
if ($this->operator === 'LIKE') {
$like_value = $this->value;

View file

@ -38,11 +38,9 @@ use App\Entity\Parts\MeasurementUnit;
use App\Entity\Parts\Storelocation;
use App\Entity\Parts\Supplier;
use App\Entity\UserSystem\User;
use App\Form\Filters\Constraints\UserEntityConstraintType;
use App\Services\Trees\NodesListBuilder;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\QueryBuilder;
use Svg\Tag\Text;
class PartFilter implements FilterInterface
{
@ -148,9 +146,9 @@ class PartFilter implements FilterInterface
/**
* @return BooleanConstraint|false
* @return BooleanConstraint
*/
public function getFavorite()
public function getFavorite(): BooleanConstraint
{
return $this->favorite;
}

View file

@ -96,7 +96,7 @@ class PartSearchFilter implements FilterInterface
$fields_to_search[] = 'orderdetails.supplierpartnr';
}
if($this->mpn) {
$fields_to_search[] = 'part.manufacturer_product_url';
$fields_to_search[] = 'part.manufacturer_product_number';
}
if($this->supplier) {
$fields_to_search[] = 'suppliers.name';

View file

@ -28,7 +28,6 @@ use App\DataTables\Column\LogEntryExtraColumn;
use App\DataTables\Column\LogEntryTargetColumn;
use App\DataTables\Column\RevertLogColumn;
use App\DataTables\Column\RowClassColumn;
use App\DataTables\Filters\AttachmentFilter;
use App\DataTables\Filters\LogFilter;
use App\Entity\Base\AbstractDBElement;
use App\Entity\Contracts\TimeTravelInterface;
@ -60,8 +59,6 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Contracts\Translation\TranslatorInterface;
use function Symfony\Component\Translation\t;
class LogDataTable implements DataTableTypeInterface
{
protected ElementTypeNameGenerator $elementTypeNameGenerator;

View file

@ -36,22 +36,14 @@ use App\DataTables\Column\TagsColumn;
use App\DataTables\Filters\PartFilter;
use App\DataTables\Filters\PartSearchFilter;
use App\DataTables\Helpers\PartDataTableHelper;
use App\Entity\Parts\Category;
use App\Entity\Parts\Footprint;
use App\Entity\Parts\Manufacturer;
use App\Entity\Parts\Part;
use App\Entity\Parts\PartLot;
use App\Entity\Parts\Storelocation;
use App\Entity\Parts\Supplier;
use App\Services\Formatters\AmountFormatter;
use App\Services\Attachments\AttachmentURLGenerator;
use App\Services\Attachments\PartPreviewGenerator;
use App\Services\EntityURLGenerator;
use App\Services\Trees\NodesListBuilder;
use Doctrine\ORM\QueryBuilder;
use Omines\DataTablesBundle\Adapter\Doctrine\FetchJoinORMAdapter;
use Omines\DataTablesBundle\Adapter\Doctrine\ORM\SearchCriteriaProvider;
use Omines\DataTablesBundle\Column\BoolColumn;
use Omines\DataTablesBundle\Column\MapColumn;
use Omines\DataTablesBundle\Column\TextColumn;
use Omines\DataTablesBundle\DataTable;
@ -63,27 +55,19 @@ use Symfony\Contracts\Translation\TranslatorInterface;
final class PartsDataTable implements DataTableTypeInterface
{
private TranslatorInterface $translator;
private NodesListBuilder $treeBuilder;
private AmountFormatter $amountFormatter;
private AttachmentURLGenerator $attachmentURLGenerator;
private Security $security;
private PartDataTableHelper $partDataTableHelper;
/**
* @var EntityURLGenerator
*/
private $urlGenerator;
private EntityURLGenerator $urlGenerator;
public function __construct(EntityURLGenerator $urlGenerator, TranslatorInterface $translator,
NodesListBuilder $treeBuilder, AmountFormatter $amountFormatter,PartDataTableHelper $partDataTableHelper,
AttachmentURLGenerator $attachmentURLGenerator, Security $security)
AmountFormatter $amountFormatter,PartDataTableHelper $partDataTableHelper, Security $security)
{
$this->urlGenerator = $urlGenerator;
$this->translator = $translator;
$this->treeBuilder = $treeBuilder;
$this->amountFormatter = $amountFormatter;
$this->attachmentURLGenerator = $attachmentURLGenerator;
$this->security = $security;
$this->partDataTableHelper = $partDataTableHelper;
}
@ -168,6 +152,7 @@ final class PartsDataTable implements DataTableTypeInterface
if ($this->security->isGranted('@storelocations.read')) {
$dataTable->add('storelocation', TextColumn::class, [
'label' => $this->translator->trans('part.table.storeLocations'),
'orderField' => 'storelocations.name',
'render' => function ($value, Part $context) {
$tmp = [];
foreach ($context->getPartLots() as $lot) {
@ -193,7 +178,22 @@ final class PartsDataTable implements DataTableTypeInterface
$amount = $context->getAmountSum();
$expiredAmount = $context->getExpiredAmountSum();
$ret = htmlspecialchars($this->amountFormatter->format($amount, $context->getPartUnit()));
$ret = '';
if ($context->isAmountUnknown()) {
//When all amounts are unknown, we show a question mark
if ($amount === 0.0) {
$ret .= sprintf('<b class="text-primary" title="%s">?</b>',
$this->translator->trans('part_lots.instock_unknown'));
} else { //Otherwise mark it with greater equal and the (known) amount
$ret .= sprintf('<b class="text-primary" title="%s">≥</b>',
$this->translator->trans('part_lots.instock_unknown')
);
$ret .= htmlspecialchars($this->amountFormatter->format($amount, $context->getPartUnit()));
}
} else {
$ret .= htmlspecialchars($this->amountFormatter->format($amount, $context->getPartUnit()));
}
//If we have expired lots, we show them in parentheses behind
if ($expiredAmount > 0) {

View file

@ -27,7 +27,6 @@ use Doctrine\Common\DataFixtures\Purger\PurgerInterface;
use Doctrine\Common\DataFixtures\Sorter\TopologicalSorter;
use Doctrine\DBAL\Platforms\AbstractMySQLPlatform;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\MySQLPlatform;
use Doctrine\DBAL\Schema\Identifier;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
@ -35,7 +34,6 @@ use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use function array_reverse;
use function array_search;
use function assert;
use function count;
use function is_callable;
@ -53,21 +51,21 @@ class ResetAutoIncrementORMPurger implements PurgerInterface, ORMPurgerInterface
public const PURGE_MODE_TRUNCATE = 2;
/** @var EntityManagerInterface|null */
private $em;
private ?EntityManagerInterface $em;
/**
* If the purge should be done through DELETE or TRUNCATE statements
*
* @var int
*/
private $purgeMode = self::PURGE_MODE_DELETE;
private int $purgeMode = self::PURGE_MODE_DELETE;
/**
* Table/view names to be excluded from purge
*
* @var string[]
*/
private $excluded;
private array $excluded;
/**
* Construct new purger instance.

View file

@ -49,7 +49,7 @@ class SQLiteRegexExtension implements EventSubscriberInterface
}
}
public function getSubscribedEvents()
public function getSubscribedEvents(): array
{
return[
Events::postConnect

View file

@ -24,7 +24,7 @@ use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Driver\Middleware;
/**
* This class wraps the Doctrine DBAL driver and wraps it into an Midleware driver so we can change the SQL mode
* This class wraps the Doctrine DBAL driver and wraps it into a Midleware driver, so we can change the SQL mode
*/
class SetSQLModeMiddlewareWrapper implements Middleware
{

View file

@ -29,17 +29,17 @@ use Doctrine\DBAL\Types\Type;
class TinyIntType extends Type
{
public function getSQLDeclaration(array $column, AbstractPlatform $platform)
public function getSQLDeclaration(array $column, AbstractPlatform $platform): string
{
return 'TINYINT';
}
public function getName()
public function getName(): string
{
return 'tinyint';
}
public function requiresSQLCommentHint(AbstractPlatform $platform)
public function requiresSQLCommentHint(AbstractPlatform $platform): bool
{
//We use the comment, so that doctrine migrations can properly detect, that nothing has changed and no migration is needed.
return true;

View file

@ -59,7 +59,7 @@ abstract class Attachment extends AbstractNamedDBElement
/**
* A list of file extensions, that browsers can show directly as image.
* Based on: https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types
* It will be used to determine if a attachment is a picture and therefore will be shown to user as preview.
* 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',
'svg', 'webp', ];
@ -70,7 +70,7 @@ abstract class Attachment extends AbstractNamedDBElement
public const MODEL_EXTS = ['x3d'];
/**
* When the path begins with one of this placeholders.
* When the path begins with one of the placeholders.
*/
public const INTERNAL_PLACEHOLDER = ['%BASE%', '%MEDIA%', '%SECURE%'];
@ -105,7 +105,7 @@ abstract class Attachment extends AbstractNamedDBElement
protected string $name = '';
/**
* ORM mapping is done in sub classes (like PartAttachment).
* ORM mapping is done in subclasses (like PartAttachment).
*/
protected ?AttachmentContainingDBElement $element = null;
@ -116,7 +116,7 @@ abstract class Attachment extends AbstractNamedDBElement
protected bool $show_in_table = false;
/**
* @var AttachmentType
* @var AttachmentType|null
* @ORM\ManyToOne(targetEntity="AttachmentType", inversedBy="attachments_with_type")
* @ORM\JoinColumn(name="type_id", referencedColumnName="id", nullable=false)
* @Selectable()
@ -153,7 +153,7 @@ abstract class Attachment extends AbstractNamedDBElement
*/
public function isPicture(): bool
{
//We can not check if a external link is a picture, so just assume this is false
//We can not check if an external link is a picture, so just assume this is false
if ($this->isExternal()) {
return true;
}
@ -215,7 +215,7 @@ abstract class Attachment extends AbstractNamedDBElement
* Checks if the attachment file is using a builtin file. (see BUILTIN_PLACEHOLDERS const for possible placeholders)
* If a file is built in, the path is shown to user in url field (no sensitive infos are provided).
*
* @return bool true if the attachment is using an builtin file
* @return bool true if the attachment is using a builtin file
*/
public function isBuiltIn(): bool
{
@ -259,7 +259,7 @@ abstract class Attachment extends AbstractNamedDBElement
}
/**
* The URL to the external file, or the path to the built in file.
* The URL to the external file, or the path to the built-in file.
* Returns null, if the file is not external (and not builtin).
*/
public function getURL(): ?string
@ -455,9 +455,9 @@ abstract class Attachment extends AbstractNamedDBElement
* @param string $string The string which should be checked
* @param bool $path_required If true, the string must contain a path to be valid. (e.g. foo.bar would be invalid, foo.bar/test.php would be valid).
* @param bool $only_http Set this to true, if only HTTPS or HTTP schemata should be allowed.
* *Caution: When this is set to false, a attacker could use the file:// schema, to get internal server files, like /etc/passwd.*
* *Caution: When this is set to false, an attacker could use the file:// schema, to get internal server files, like /etc/passwd.*
*
* @return bool True if the string is a valid URL. False, if the string is not an URL or invalid.
* @return bool True if the string is a valid URL. False, if the string is not a URL or invalid.
*/
public static function isValidURL(string $string, bool $path_required = true, bool $only_http = true): bool
{

View file

@ -46,7 +46,7 @@ abstract class AttachmentContainingDBElement extends AbstractNamedDBElement impl
* Mapping is done in sub classes like part
* @Groups({"full"})
*/
protected $attachments;
protected Collection $attachments;
public function __construct()
{

View file

@ -45,13 +45,13 @@ class AttachmentType extends AbstractStructuralDBElement
* @ORM\OneToMany(targetEntity="AttachmentType", mappedBy="parent", cascade={"persist"})
* @ORM\OrderBy({"name" = "ASC"})
*/
protected $children;
protected Collection $children;
/**
* @ORM\ManyToOne(targetEntity="AttachmentType", inversedBy="children")
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
*/
protected $parent;
protected ?AbstractStructuralDBElement $parent;
/**
* @var string
@ -65,14 +65,14 @@ class AttachmentType extends AbstractStructuralDBElement
* @ORM\OrderBy({"name" = "ASC"})
* @Assert\Valid()
*/
protected $attachments;
protected Collection $attachments;
/** @var Collection<int, AttachmentTypeParameter>
* @ORM\OneToMany(targetEntity="App\Entity\Parameters\AttachmentTypeParameter", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})
* @Assert\Valid()
*/
protected $parameters;
protected Collection $parameters;
/**
* @var Collection<int, Attachment>
@ -99,7 +99,7 @@ class AttachmentType extends AbstractStructuralDBElement
}
/**
* Gets an filter, which file types are allowed for attachment files.
* Gets a filter, which file types are allowed for attachment files.
* Must be in the format of <input type=file> accept attribute
* (See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#Unique_file_type_specifiers).
*/

View file

@ -35,7 +35,7 @@ class AttachmentTypeAttachment extends Attachment
{
public const ALLOWED_ELEMENT_CLASS = AttachmentType::class;
/**
* @var AttachmentType the element this attachment is associated with
* @var AttachmentContainingDBElement|null the element this attachment is associated with
* @ORM\ManyToOne(targetEntity="App\Entity\Attachments\AttachmentType", inversedBy="attachments")
* @ORM\JoinColumn(name="element_id", referencedColumnName="id", nullable=false, onDelete="CASCADE").
*/

View file

@ -27,7 +27,7 @@ use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* A attachment attached to a category element.
* An attachment attached to a category element.
*
* @ORM\Entity()
* @UniqueEntity({"name", "attachment_type", "element"})
@ -36,7 +36,7 @@ class CategoryAttachment extends Attachment
{
public const ALLOWED_ELEMENT_CLASS = Category::class;
/**
* @var Category the element this attachment is associated with
* @var AttachmentContainingDBElement|null the element this attachment is associated with
* @ORM\ManyToOne(targetEntity="App\Entity\Parts\Category", inversedBy="attachments")
* @ORM\JoinColumn(name="element_id", referencedColumnName="id", nullable=false, onDelete="CASCADE").
*/

View file

@ -36,7 +36,7 @@ class CurrencyAttachment extends Attachment
{
public const ALLOWED_ELEMENT_CLASS = Currency::class;
/**
* @var Currency the element this attachment is associated with
* @var Currency|null the element this attachment is associated with
* @ORM\ManyToOne(targetEntity="App\Entity\PriceInformations\Currency", inversedBy="attachments")
* @ORM\JoinColumn(name="element_id", referencedColumnName="id", nullable=false, onDelete="CASCADE").
*/

View file

@ -27,7 +27,7 @@ use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* A attachment attached to a footprint element.
* An attachment attached to a footprint element.
*
* @ORM\Entity()
* @UniqueEntity({"name", "attachment_type", "element"})
@ -36,7 +36,7 @@ class FootprintAttachment extends Attachment
{
public const ALLOWED_ELEMENT_CLASS = Footprint::class;
/**
* @var Footprint the element this attachment is associated with
* @var Footprint|null the element this attachment is associated with
* @ORM\ManyToOne(targetEntity="App\Entity\Parts\Footprint", inversedBy="attachments")
* @ORM\JoinColumn(name="element_id", referencedColumnName="id", nullable=false, onDelete="CASCADE").
*/

View file

@ -27,7 +27,7 @@ use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* A attachment attached to a Group element.
* An attachment attached to a Group element.
*
* @ORM\Entity()
* @UniqueEntity({"name", "attachment_type", "element"})
@ -35,8 +35,9 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
class GroupAttachment extends Attachment
{
public const ALLOWED_ELEMENT_CLASS = Group::class;
/**
* @var Group the element this attachment is associated with
* @var Group|null the element this attachment is associated with
* @ORM\ManyToOne(targetEntity="App\Entity\UserSystem\Group", inversedBy="attachments")
* @ORM\JoinColumn(name="element_id", referencedColumnName="id", nullable=false, onDelete="CASCADE").
*/

View file

@ -27,7 +27,7 @@ use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* A attachment attached to a manufacturer element.
* An attachment attached to a manufacturer element.
*
* @ORM\Entity()
* @UniqueEntity({"name", "attachment_type", "element"})
@ -35,8 +35,9 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
class ManufacturerAttachment extends Attachment
{
public const ALLOWED_ELEMENT_CLASS = Manufacturer::class;
/**
* @var Manufacturer the element this attachment is associated with
* @var Manufacturer|null the element this attachment is associated with
* @ORM\ManyToOne(targetEntity="App\Entity\Parts\Manufacturer", inversedBy="attachments")
* @ORM\JoinColumn(name="element_id", referencedColumnName="id", nullable=false, onDelete="CASCADE").
*/

View file

@ -28,7 +28,7 @@ use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* A attachment attached to a measurement unit element.
* An attachment attached to a measurement unit element.
*
* @ORM\Entity()
* @UniqueEntity({"name", "attachment_type", "element"})
@ -37,7 +37,7 @@ class MeasurementUnitAttachment extends Attachment
{
public const ALLOWED_ELEMENT_CLASS = MeasurementUnit::class;
/**
* @var Manufacturer the element this attachment is associated with
* @var Manufacturer|null the element this attachment is associated with
* @ORM\ManyToOne(targetEntity="App\Entity\Parts\MeasurementUnit", inversedBy="attachments")
* @ORM\JoinColumn(name="element_id", referencedColumnName="id", nullable=false, onDelete="CASCADE").
*/

View file

@ -36,7 +36,7 @@ class ProjectAttachment extends Attachment
{
public const ALLOWED_ELEMENT_CLASS = Project::class;
/**
* @var Project the element this attachment is associated with
* @var Project|null the element this attachment is associated with
* @ORM\ManyToOne(targetEntity="App\Entity\ProjectSystem\Project", inversedBy="attachments")
* @ORM\JoinColumn(name="element_id", referencedColumnName="id", nullable=false, onDelete="CASCADE").
*/

View file

@ -27,7 +27,7 @@ use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* A attachment attached to a measurement unit element.
* An attachment attached to a measurement unit element.
*
* @ORM\Entity()
* @UniqueEntity({"name", "attachment_type", "element"})
@ -35,8 +35,9 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
class StorelocationAttachment extends Attachment
{
public const ALLOWED_ELEMENT_CLASS = Storelocation::class;
/**
* @var Storelocation the element this attachment is associated with
* @var Storelocation|null the element this attachment is associated with
* @ORM\ManyToOne(targetEntity="App\Entity\Parts\Storelocation", inversedBy="attachments")
* @ORM\JoinColumn(name="element_id", referencedColumnName="id", nullable=false, onDelete="CASCADE").
*/

View file

@ -35,8 +35,9 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
class SupplierAttachment extends Attachment
{
public const ALLOWED_ELEMENT_CLASS = Supplier::class;
/**
* @var Supplier the element this attachment is associated with
* @var Supplier|null the element this attachment is associated with
* @ORM\ManyToOne(targetEntity="App\Entity\Parts\Supplier", inversedBy="attachments")
* @ORM\JoinColumn(name="element_id", referencedColumnName="id", nullable=false, onDelete="CASCADE").
*/

View file

@ -27,7 +27,7 @@ use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* A attachment attached to a user element.
* An attachment attached to a user element.
*
* @ORM\Entity()
* @UniqueEntity({"name", "attachment_type", "element"})
@ -35,8 +35,9 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
class UserAttachment extends Attachment
{
public const ALLOWED_ELEMENT_CLASS = User::class;
/**
* @var User the element this attachment is associated with
* @var User|null the element this attachment is associated with
* @ORM\ManyToOne(targetEntity="App\Entity\UserSystem\User", inversedBy="attachments")
* @ORM\JoinColumn(name="element_id", referencedColumnName="id", nullable=false, onDelete="CASCADE").
*/

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
namespace App\Entity\Base;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
@ -33,5 +34,5 @@ use Symfony\Component\Serializer\Annotation\Groups;
abstract class AbstractPartsContainingDBElement extends AbstractStructuralDBElement
{
/** @Groups({"full"}) */
protected $parameters;
protected Collection $parameters;
}

View file

@ -81,22 +81,22 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
protected int $level = 0;
/**
* We can not define the mapping here or we will get an exception. Unfortunately we have to do the mapping in the
* We can not define the mapping here, or we will get an exception. Unfortunately we have to do the mapping in the
* subclasses.
*
* @var AbstractStructuralDBElement[]|Collection
* @Groups({"include_children"})
*/
protected $children;
protected Collection $children;
/**
* @var AbstractStructuralDBElement
* @NoneOfItsChildren()
* @Groups({"include_parents", "import"})
*/
protected $parent = null;
protected ?AbstractStructuralDBElement $parent = null;
/** @var string[] all names of all parent elements as a array of strings,
/** @var string[] all names of all parent elements as an array of strings,
* the last array element is the name of the element itself
*/
private array $full_path_strings = [];
@ -106,6 +106,7 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
parent::__construct();
$this->children = new ArrayCollection();
$this->parameters = new ArrayCollection();
$this->parent = null;
}
public function __clone()
@ -155,10 +156,8 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
if ($this->getParent() === $another_element) {
return true;
}
} else { //If the IDs are defined, we can compare the IDs
if ($this->getParent()->getID() === $another_element->getID()) {
return true;
}
} elseif ($this->getParent()->getID() === $another_element->getID()) {
return true;
}
//Otherwise, check recursively
@ -168,7 +167,7 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
/**
* Checks if this element is an root element (has no parent).
*
* @return bool true if the this element is an root element
* @return bool true if this element is a root element
*/
public function isRoot(): bool
{

View file

@ -27,12 +27,12 @@ use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* A entity with this class has a master attachment, which is used as a preview image for this object.
* An entity with this class has a master attachment, which is used as a preview image for this object.
*/
trait MasterAttachmentTrait
{
/**
* @var Attachment
* @var Attachment|null
* @ORM\ManyToOne(targetEntity="App\Entity\Attachments\Attachment")
* @ORM\JoinColumn(name="id_preview_attachment", referencedColumnName="id", onDelete="SET NULL", nullable=true)
* @Assert\Expression("value == null or value.isPicture()", message="part.master_attachment.must_be_picture")

View file

@ -27,9 +27,9 @@ use DateTime;
interface TimeTravelInterface
{
/**
* Checks if this entry has informations which data has changed.
* Checks if this entry has information which data has changed.
*
* @return bool true if this entry has informations about the changed data
* @return bool true if this entry has information about the changed data
*/
public function hasOldDataInformations(): bool;
@ -39,7 +39,7 @@ interface TimeTravelInterface
public function getOldData(): array;
/**
* Returns the the timestamp associated with this change.
* Returns the timestamp associated with this change.
*/
public function getTimestamp(): DateTime;
}

View file

@ -61,7 +61,7 @@ class LabelProfile extends AttachmentContainingDBElement
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\LabelAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"name" = "ASC"})
*/
protected $attachments;
protected Collection $attachments;
/**
* @var LabelOptions

View file

@ -48,7 +48,7 @@ use InvalidArgumentException;
use Psr\Log\LogLevel;
/**
* This entity describes a entry in the event log.
* This entity describes an entry in the event log.
*
* @ORM\Entity(repositoryClass="App\Repository\LogEntryRepository")
* @ORM\Table("log", indexes={
@ -142,7 +142,7 @@ abstract class AbstractLogEntry extends AbstractDBElement
self::TARGET_TYPE_LABEL_PROFILE => LabelProfile::class,
];
/** @var User The user which has caused this log entry
/** @var User|null The user which has caused this log entry
* @ORM\ManyToOne(targetEntity="App\Entity\UserSystem\User", fetch="EAGER")
* @ORM\JoinColumn(name="id_user", nullable=true, onDelete="SET NULL")
*/
@ -183,7 +183,7 @@ abstract class AbstractLogEntry extends AbstractDBElement
/** @var array The extra data in raw (short form) saved in the DB
* @ORM\Column(name="extra", type="json")
*/
protected $extra = [];
protected array $extra = [];
public function __construct()
{
@ -340,7 +340,7 @@ abstract class AbstractLogEntry extends AbstractDBElement
/**
* Returns the class name of the target element associated with this log entry.
* Returns null, if this log entry is not associated with an log entry.
* Returns null, if this log entry is not associated with a log entry.
*
* @return string|null the class name of the target class
*/
@ -355,7 +355,7 @@ abstract class AbstractLogEntry extends AbstractDBElement
/**
* Returns the ID of the target element associated with this log entry.
* Returns null, if this log entry is not associated with an log entry.
* Returns null, if this log entry is not associated with a log entry.
*
* @return int|null the ID of the associated element
*/
@ -451,7 +451,7 @@ abstract class AbstractLogEntry extends AbstractDBElement
}
/**
* Converts an target type id to an full qualified class name.
* Converts a target type id to a full qualified class name.
*
* @param int $type_id The target type ID
*/

View file

@ -81,13 +81,12 @@ use App\Entity\Parts\Supplier;
use App\Entity\PriceInformations\Currency;
use App\Entity\UserSystem\Group;
use App\Entity\UserSystem\User;
use App\Repository\Parts\ManufacturerRepository;
use Doctrine\ORM\Mapping as ORM;
use InvalidArgumentException;
/**
* @ORM\Entity()
* This log entry is created when an element is deleted, that is used in a collection of an other entity.
* This log entry is created when an element is deleted, that is used in a collection of another entity.
* This is needed to signal time travel, that it has to undelete the deleted entity.
*/
class CollectionElementDeleted extends AbstractLogEntry implements LogWithEventUndoInterface

View file

@ -43,7 +43,7 @@ class DatabaseUpdatedLogEntry extends AbstractLogEntry
*/
public function isSuccessful(): bool
{
//We dont save unsuccessful updates now, so just assume it to save space.
//We don't save unsuccessful updates now, so just assume it to save space.
return $this->extra['s'] ?? true;
}

View file

@ -56,7 +56,7 @@ class LegacyInstockChangedLogEntry extends AbstractLogEntry
}
/**
* Returns the price that has to be payed for the change (in the base currency).
* Returns the price that has to be paid for the change (in the base currency).
*
* @param bool $absolute Set this to true, if you want only get the absolute value of the price (without minus)
*/
@ -92,9 +92,9 @@ class LegacyInstockChangedLogEntry extends AbstractLogEntry
}
/**
* Checks if the Change was an withdrawal of parts.
* Checks if the Change was a withdrawal of parts.
*
* @return bool true if the change was an withdrawal, false if not
* @return bool true if the change was a withdrawal, false if not
*/
public function isWithdrawal(): bool
{

View file

@ -117,7 +117,7 @@ class SecurityEventLogEntry extends AbstractLogEntry
}
/**
* Return the (anonymized) IP address used to login the user.
* Return the (anonymized) IP address used to log in the user.
*/
public function getIPAddress(): string
{
@ -125,9 +125,9 @@ class SecurityEventLogEntry extends AbstractLogEntry
}
/**
* Sets the IP address used to login the user.
* Sets the IP address used to log in the user.
*
* @param string $ip the IP address used to login the user
* @param string $ip the IP address used to log in the user
* @param bool $anonymize Anonymize the IP address (remove last block) to be GPDR compliant
*
* @return $this

View file

@ -42,7 +42,7 @@ class UserLoginLogEntry extends AbstractLogEntry
}
/**
* Return the (anonymized) IP address used to login the user.
* Return the (anonymized) IP address used to log in the user.
*/
public function getIPAddress(): string
{
@ -50,9 +50,9 @@ class UserLoginLogEntry extends AbstractLogEntry
}
/**
* Sets the IP address used to login the user.
* Sets the IP address used to log in the user.
*
* @param string $ip the IP address used to login the user
* @param string $ip the IP address used to log in the user
* @param bool $anonymize Anonymize the IP address (remove last block) to be GPDR compliant
*
* @return $this

View file

@ -40,7 +40,7 @@ class UserLogoutLogEntry extends AbstractLogEntry
}
/**
* Return the (anonymized) IP address used to login the user.
* Return the (anonymized) IP address used to log in the user.
*/
public function getIPAddress(): string
{
@ -48,9 +48,9 @@ class UserLogoutLogEntry extends AbstractLogEntry
}
/**
* Sets the IP address used to login the user.
* Sets the IP address used to log in the user.
*
* @param string $ip the IP address used to login the user
* @param string $ip the IP address used to log in the user
* @param bool $anonymize Anonymize the IP address (remove last block) to be GPDR compliant
*
* @return $this

View file

@ -139,11 +139,11 @@ abstract class AbstractParameter extends AbstractNamedDBElement
protected string $group = '';
/**
* Mapping is done in sub classes.
* Mapping is done in subclasses.
*
* @var AbstractDBElement|null the element to which this parameter belongs to
*/
protected $element;
protected ?AbstractDBElement $element = null;
public function __construct()
{

View file

@ -42,6 +42,7 @@ declare(strict_types=1);
namespace App\Entity\Parameters;
use App\Entity\Attachments\AttachmentType;
use App\Entity\Base\AbstractDBElement;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
@ -57,5 +58,5 @@ class AttachmentTypeParameter extends AbstractParameter
* @ORM\ManyToOne(targetEntity="App\Entity\Attachments\AttachmentType", inversedBy="parameters")
* @ORM\JoinColumn(name="element_id", referencedColumnName="id", nullable=false, onDelete="CASCADE").
*/
protected $element;
protected ?AbstractDBElement $element = null;
}

View file

@ -41,6 +41,7 @@ declare(strict_types=1);
namespace App\Entity\Parameters;
use App\Entity\Base\AbstractDBElement;
use App\Entity\Parts\Category;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
@ -57,5 +58,5 @@ class CategoryParameter extends AbstractParameter
* @ORM\ManyToOne(targetEntity="App\Entity\Parts\Category", inversedBy="parameters")
* @ORM\JoinColumn(name="element_id", referencedColumnName="id", nullable=false, onDelete="CASCADE").
*/
protected $element;
protected ?AbstractDBElement $element = null;
}

View file

@ -41,12 +41,13 @@ declare(strict_types=1);
namespace App\Entity\Parameters;
use App\Entity\Base\AbstractDBElement;
use App\Entity\PriceInformations\Currency;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* A attachment attached to a category element.
* An attachment attached to a category element.
*
* @ORM\Entity(repositoryClass="App\Repository\ParameterRepository")
* @UniqueEntity(fields={"name", "group", "element"})
@ -60,5 +61,5 @@ class CurrencyParameter extends AbstractParameter
* @ORM\ManyToOne(targetEntity="App\Entity\PriceInformations\Currency", inversedBy="parameters")
* @ORM\JoinColumn(name="element_id", referencedColumnName="id", nullable=false, onDelete="CASCADE").
*/
protected $element;
protected ?AbstractDBElement $element = null;
}

View file

@ -41,6 +41,7 @@ declare(strict_types=1);
namespace App\Entity\Parameters;
use App\Entity\Base\AbstractDBElement;
use App\Entity\Parts\Footprint;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
@ -58,5 +59,5 @@ class FootprintParameter extends AbstractParameter
* @ORM\ManyToOne(targetEntity="App\Entity\Parts\Footprint", inversedBy="parameters")
* @ORM\JoinColumn(name="element_id", referencedColumnName="id", nullable=false, onDelete="CASCADE").
*/
protected $element;
protected ?AbstractDBElement $element = null;
}

View file

@ -41,6 +41,7 @@ declare(strict_types=1);
namespace App\Entity\Parameters;
use App\Entity\Base\AbstractDBElement;
use App\Entity\UserSystem\Group;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
@ -58,5 +59,5 @@ class GroupParameter extends AbstractParameter
* @ORM\ManyToOne(targetEntity="App\Entity\UserSystem\Group", inversedBy="parameters")
* @ORM\JoinColumn(name="element_id", referencedColumnName="id", nullable=false, onDelete="CASCADE").
*/
protected $element;
protected ?AbstractDBElement $element = null;
}

View file

@ -41,6 +41,7 @@ declare(strict_types=1);
namespace App\Entity\Parameters;
use App\Entity\Base\AbstractDBElement;
use App\Entity\Parts\Manufacturer;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
@ -58,5 +59,5 @@ class ManufacturerParameter extends AbstractParameter
* @ORM\ManyToOne(targetEntity="App\Entity\Parts\Manufacturer", inversedBy="parameters")
* @ORM\JoinColumn(name="element_id", referencedColumnName="id", nullable=false, onDelete="CASCADE").
*/
protected $element;
protected ?AbstractDBElement $element = null;
}

View file

@ -41,6 +41,7 @@ declare(strict_types=1);
namespace App\Entity\Parameters;
use App\Entity\Base\AbstractDBElement;
use App\Entity\Parts\MeasurementUnit;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
@ -58,5 +59,5 @@ class MeasurementUnitParameter extends AbstractParameter
* @ORM\ManyToOne(targetEntity="App\Entity\Parts\MeasurementUnit", inversedBy="parameters")
* @ORM\JoinColumn(name="element_id", referencedColumnName="id", nullable=false, onDelete="CASCADE").
*/
protected $element;
protected ?AbstractDBElement $element = null;
}

View file

@ -52,7 +52,7 @@ trait ParametersTrait
* @var Collection<int, AbstractParameter>
* @Assert\Valid()
*/
protected $parameters;
protected Collection $parameters;
/**
* Return all associated specifications.

View file

@ -41,6 +41,7 @@ declare(strict_types=1);
namespace App\Entity\Parameters;
use App\Entity\Base\AbstractDBElement;
use App\Entity\Parts\Part;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
@ -58,5 +59,5 @@ class PartParameter extends AbstractParameter
* @ORM\ManyToOne(targetEntity="App\Entity\Parts\Part", inversedBy="parameters")
* @ORM\JoinColumn(name="element_id", referencedColumnName="id", nullable=false, onDelete="CASCADE").
*/
protected $element;
protected ?AbstractDBElement $element = null;
}

View file

@ -41,6 +41,7 @@ declare(strict_types=1);
namespace App\Entity\Parameters;
use App\Entity\Base\AbstractDBElement;
use App\Entity\ProjectSystem\Project;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
@ -58,5 +59,5 @@ class ProjectParameter extends AbstractParameter
* @ORM\ManyToOne(targetEntity="App\Entity\ProjectSystem\Project", inversedBy="parameters")
* @ORM\JoinColumn(name="element_id", referencedColumnName="id", nullable=false, onDelete="CASCADE").
*/
protected $element;
protected ?AbstractDBElement $element = null;
}

View file

@ -41,6 +41,7 @@ declare(strict_types=1);
namespace App\Entity\Parameters;
use App\Entity\Base\AbstractDBElement;
use App\Entity\Parts\Storelocation;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
@ -58,5 +59,5 @@ class StorelocationParameter extends AbstractParameter
* @ORM\ManyToOne(targetEntity="App\Entity\Parts\Storelocation", inversedBy="parameters")
* @ORM\JoinColumn(name="element_id", referencedColumnName="id", nullable=false, onDelete="CASCADE").
*/
protected $element;
protected ?AbstractDBElement $element = null;
}

View file

@ -41,6 +41,7 @@ declare(strict_types=1);
namespace App\Entity\Parameters;
use App\Entity\Base\AbstractDBElement;
use App\Entity\Parts\Supplier;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
@ -58,5 +59,5 @@ class SupplierParameter extends AbstractParameter
* @ORM\ManyToOne(targetEntity="App\Entity\Parts\Supplier", inversedBy="parameters")
* @ORM\JoinColumn(name="element_id", referencedColumnName="id", nullable=false, onDelete="CASCADE").
*/
protected $element;
protected ?AbstractDBElement $element = null;
}

View file

@ -24,6 +24,7 @@ namespace App\Entity\Parts;
use App\Entity\Attachments\CategoryAttachment;
use App\Entity\Base\AbstractPartsContainingDBElement;
use App\Entity\Base\AbstractStructuralDBElement;
use App\Entity\Parameters\CategoryParameter;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
@ -46,13 +47,13 @@ class Category extends AbstractPartsContainingDBElement
* @ORM\OrderBy({"name" = "ASC"})
* @var Collection
*/
protected $children;
protected Collection $children;
/**
* @ORM\ManyToOne(targetEntity="Category", inversedBy="children")
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
*/
protected $parent;
protected ?AbstractStructuralDBElement $parent = null;
/**
* @var string
@ -109,6 +110,7 @@ class Category extends AbstractPartsContainingDBElement
* @Groups({"full", "import"})
*/
protected string $default_comment = '';
/**
* @var Collection<int, CategoryAttachment>
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\CategoryAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
@ -116,7 +118,7 @@ class Category extends AbstractPartsContainingDBElement
* @Assert\Valid()
* @Groups({"full"})
*/
protected $attachments;
protected Collection $attachments;
/** @var Collection<int, CategoryParameter>
* @ORM\OneToMany(targetEntity="App\Entity\Parameters\CategoryParameter", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
@ -124,7 +126,7 @@ class Category extends AbstractPartsContainingDBElement
* @Assert\Valid()
* @Groups({"full"})
*/
protected $parameters;
protected Collection $parameters;
public function getPartnameHint(): string
{

View file

@ -44,14 +44,14 @@ class Footprint extends AbstractPartsContainingDBElement
* @ORM\ManyToOne(targetEntity="Footprint", inversedBy="children")
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
*/
protected $parent;
protected ?\App\Entity\Base\AbstractStructuralDBElement $parent;
/**
* @ORM\OneToMany(targetEntity="Footprint", mappedBy="parent")
* @ORM\OrderBy({"name" = "ASC"})
* @var Collection
*/
protected $children;
protected Collection $children;
/**
* @var Collection<int, FootprintAttachment>
@ -59,7 +59,7 @@ class Footprint extends AbstractPartsContainingDBElement
* @ORM\OrderBy({"name" = "ASC"})
* @Assert\Valid()
*/
protected $attachments;
protected Collection $attachments;
/**
* @var FootprintAttachment|null
@ -73,7 +73,7 @@ class Footprint extends AbstractPartsContainingDBElement
* @ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})
* @Assert\Valid()
*/
protected $parameters;
protected Collection $parameters;
/****************************************
* Getters

View file

@ -44,14 +44,14 @@ class Manufacturer extends AbstractCompany
* @ORM\ManyToOne(targetEntity="Manufacturer", inversedBy="children")
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
*/
protected $parent;
protected ?\App\Entity\Base\AbstractStructuralDBElement $parent;
/**
* @ORM\OneToMany(targetEntity="Manufacturer", mappedBy="parent")
* @ORM\OrderBy({"name" = "ASC"})
* @var Collection
*/
protected $children;
protected Collection $children;
/**
* @var Collection<int, ManufacturerAttachment>
@ -59,12 +59,12 @@ class Manufacturer extends AbstractCompany
* @ORM\OrderBy({"name" = "ASC"})
* @Assert\Valid()
*/
protected $attachments;
protected Collection $attachments;
/** @var Collection<int, ManufacturerParameter>
* @ORM\OneToMany(targetEntity="App\Entity\Parameters\ManufacturerParameter", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})
* @Assert\Valid()
*/
protected $parameters;
protected Collection $parameters;
}

View file

@ -75,13 +75,13 @@ class MeasurementUnit extends AbstractPartsContainingDBElement
* @ORM\OrderBy({"name" = "ASC"})
* @var Collection
*/
protected $children;
protected Collection $children;
/**
* @ORM\ManyToOne(targetEntity="MeasurementUnit", inversedBy="children")
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
*/
protected $parent;
protected ?\App\Entity\Base\AbstractStructuralDBElement $parent;
/**
* @var Collection<int, MeasurementUnitAttachment>
@ -89,14 +89,14 @@ class MeasurementUnit extends AbstractPartsContainingDBElement
* @ORM\OrderBy({"name" = "ASC"})
* @Assert\Valid()
*/
protected $attachments;
protected Collection $attachments;
/** @var Collection<int, MeasurementUnitParameter>
* @ORM\OneToMany(targetEntity="App\Entity\Parameters\MeasurementUnitParameter", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})
* @Assert\Valid()
*/
protected $parameters;
protected Collection $parameters;
/**
* @return string

View file

@ -26,7 +26,6 @@ use App\Entity\Attachments\Attachment;
use App\Entity\Attachments\AttachmentContainingDBElement;
use App\Entity\Attachments\PartAttachment;
use App\Entity\Parts\PartTraits\ProjectTrait;
use App\Entity\ProjectSystem\Project;
use App\Entity\Parameters\ParametersTrait;
use App\Entity\Parameters\PartParameter;
use App\Entity\Parts\PartTraits\AdvancedPropertyTrait;
@ -34,7 +33,6 @@ use App\Entity\Parts\PartTraits\BasicPropertyTrait;
use App\Entity\Parts\PartTraits\InstockTrait;
use App\Entity\Parts\PartTraits\ManufacturerTrait;
use App\Entity\Parts\PartTraits\OrderTrait;
use App\Entity\ProjectSystem\ProjectBOMEntry;
use DateTime;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
@ -48,7 +46,7 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
* Part class.
*
* The class properties are split over various traits in directory PartTraits.
* Otherwise this class would be too big, to be maintained.
* Otherwise, this class would be too big, to be maintained.
*
* @ORM\Entity(repositoryClass="App\Repository\PartRepository")
* @ORM\Table("`parts`", indexes={
@ -75,7 +73,7 @@ class Part extends AttachmentContainingDBElement
* @ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})
* @Groups({"full"})
*/
protected $parameters;
protected Collection $parameters;
/**
* @ORM\Column(type="datetime", name="datetime_added", options={"default":"CURRENT_TIMESTAMP"})
@ -100,16 +98,16 @@ class Part extends AttachmentContainingDBElement
* @Assert\Valid()
* @Groups({"full"})
*/
protected $attachments;
protected Collection $attachments;
/**
* @var DateTime the date when this element was modified the last time
* @var DateTime|null the date when this element was modified the last time
* @ORM\Column(type="datetime", name="last_modified", options={"default":"CURRENT_TIMESTAMP"})
*/
protected ?DateTime $lastModified = null;
/**
* @var Attachment
* @var Attachment|null
* @ORM\ManyToOne(targetEntity="App\Entity\Attachments\Attachment")
* @ORM\JoinColumn(name="id_preview_attachment", referencedColumnName="id", onDelete="SET NULL", nullable=true)
* @Assert\Expression("value == null or value.isPicture()", message="part.master_attachment.must_be_picture")

View file

@ -130,7 +130,7 @@ class PartLot extends AbstractDBElement implements TimeStampableInterface, Named
/**
* Check if the current part lot is expired.
* This is the case, if the expiration date is greater the the current date.
* This is the case, if the expiration date is greater the current date.
*
* @return bool|null True, if the part lot is expired. Returns null, if no expiration date was set.
*
@ -195,7 +195,7 @@ class PartLot extends AbstractDBElement implements TimeStampableInterface, Named
}
/**
* Sets the expiration date for the part lot. Set to null, if the part lot does not expires.
* Sets the expiration date for the part lot. Set to null, if the part lot does not expire.
*
* @param DateTime|null $expiration_date
*

View file

@ -55,7 +55,7 @@ trait AdvancedPropertyTrait
protected ?float $mass = null;
/**
* @var string The internal part number of the part
* @var string|null The internal part number of the part
* @ORM\Column(type="string", length=100, nullable=true, unique=true)
* @Assert\Length(max="100")
* @Groups({"extended", "full", "import"})

View file

@ -46,7 +46,7 @@ trait BasicPropertyTrait
protected string $comment = '';
/**
* @var bool Kept for compatibility (it is not used now, and I dont think it was used in old versions)
* @var bool Kept for compatibility (it is not used now, and I don't think it was used in old versions)
* @ORM\Column(type="boolean")
*/
protected bool $visible = true;
@ -59,7 +59,7 @@ trait BasicPropertyTrait
protected bool $favorite = false;
/**
* @var Category The category this part belongs too (e.g. Resistors). Use tags, for more complex grouping.
* @var Category|null The category this part belongs too (e.g. Resistors). Use tags, for more complex grouping.
* Every part must have a category.
* @ORM\ManyToOne(targetEntity="Category")
* @ORM\JoinColumn(name="id_category", referencedColumnName="id", nullable=false)
@ -136,7 +136,7 @@ trait BasicPropertyTrait
/**
* Gets the Footprint of this part (e.g. DIP8).
*
* @return Footprint|null The footprint of this part. Null if this part should no have a footprint.
* @return Footprint|null The footprint of this part. Null if this part should not have a footprint.
*/
public function getFootprint(): ?Footprint
{

View file

@ -122,7 +122,7 @@ trait InstockTrait
/**
* Get the count of parts which must be in stock at least.
* If a integer-based part unit is selected, the value will be rounded to integers.
* If an integer-based part unit is selected, the value will be rounded to integers.
*
* @return float count of parts which must be in stock at least
*/
@ -160,9 +160,25 @@ trait InstockTrait
return $this->getAmountSum() < $this->getMinAmount();
}
/**
* Returns true, if at least one of the part lots has an unknown amount.
* It is possible that other part lots have a known amount, then getAmountSum() will return sum of all known amounts.
* @return bool True if at least one part lot has an unknown amount.
*/
public function isAmountUnknown(): bool
{
foreach ($this->getPartLots() as $lot) {
if ($lot->isInstockUnknown()) {
return true;
}
}
return false;
}
/**
* Returns the summed amount of this part (over all part lots)
* Part Lots that have unknown value or are expired, are not used for this value.
* Part Lots that have unknown value or are expired, are not used for this value (counted as 0).
*
* @return float The amount of parts given in partUnit
*/
@ -171,7 +187,7 @@ trait InstockTrait
//TODO: Find a method to do this natively in SQL, the current method could be a bit slow
$sum = 0;
foreach ($this->getPartLots() as $lot) {
//Dont use the instock value, if it is unkown
//Don't use the in stock value, if it is unknown
if ($lot->isInstockUnknown() || $lot->isExpired() ?? false) {
continue;
}

View file

@ -59,7 +59,7 @@ trait ManufacturerTrait
protected string $manufacturer_product_number = '';
/**
* @var string The production status of this part. Can be one of the specified ones.
* @var string|null The production status of this part. Can be one of the specified ones.
* @ORM\Column(type="string", length=255, nullable=true)
* @Assert\Choice({"announced", "active", "nrfnd", "eol", "discontinued", ""})
* @Groups({"extended", "full", "import"})

View file

@ -23,7 +23,6 @@ declare(strict_types=1);
namespace App\Entity\Parts\PartTraits;
use App\Entity\PriceInformations\Orderdetail;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
use function count;
@ -57,7 +56,7 @@ trait OrderTrait
protected bool $manual_order = false;
/**
* @var Orderdetail
* @var Orderdetail|null
* @ORM\OneToOne(targetEntity="App\Entity\PriceInformations\Orderdetail")
* @ORM\JoinColumn(name="order_orderdetails_id", referencedColumnName="id")
*/

View file

@ -41,7 +41,7 @@ trait ProjectTrait
}
/**
* Returns the project that this part represents the builds of, or null if it doesnt
* Returns the project that this part represents the builds of, or null if it doesn't
* @return Project|null
*/
public function getBuiltProject(): ?Project

View file

@ -24,6 +24,7 @@ namespace App\Entity\Parts;
use App\Entity\Attachments\StorelocationAttachment;
use App\Entity\Base\AbstractPartsContainingDBElement;
use App\Entity\Base\AbstractStructuralDBElement;
use App\Entity\Parameters\StorelocationParameter;
use App\Entity\UserSystem\User;
use Doctrine\Common\Collections\Collection;
@ -47,13 +48,13 @@ class Storelocation extends AbstractPartsContainingDBElement
* @ORM\OrderBy({"name" = "ASC"})
* @var Collection
*/
protected $children;
protected Collection $children;
/**
* @ORM\ManyToOne(targetEntity="Storelocation", inversedBy="children")
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
*/
protected $parent;
protected ?AbstractStructuralDBElement $parent;
/**
* @var MeasurementUnit|null The measurement unit, which parts can be stored in here
@ -67,7 +68,7 @@ class Storelocation extends AbstractPartsContainingDBElement
* @ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})
* @Assert\Valid()
*/
protected $parameters;
protected Collection $parameters;
/**
* @var bool
@ -109,7 +110,7 @@ class Storelocation extends AbstractPartsContainingDBElement
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\StorelocationAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @Assert\Valid()
*/
protected $attachments;
protected Collection $attachments;
/********************************************************************************
*

View file

@ -24,6 +24,7 @@ namespace App\Entity\Parts;
use App\Entity\Attachments\SupplierAttachment;
use App\Entity\Base\AbstractCompany;
use App\Entity\Base\AbstractStructuralDBElement;
use App\Entity\Parameters\SupplierParameter;
use App\Entity\PriceInformations\Currency;
use App\Validator\Constraints\BigDecimal\BigDecimalPositiveOrZero;
@ -50,18 +51,18 @@ class Supplier extends AbstractCompany
* @ORM\OrderBy({"name" = "ASC"})
* @var Collection
*/
protected $children;
protected Collection $children;
/**
* @ORM\ManyToOne(targetEntity="Supplier", inversedBy="children")
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
*/
protected $parent;
protected ?AbstractStructuralDBElement $parent;
/**
* @ORM\OneToMany(targetEntity="App\Entity\PriceInformations\Orderdetail", mappedBy="supplier")
*/
protected $orderdetails;
protected Collection $orderdetails;
/**
* @var Currency|null The currency that should be used by default for order informations with this supplier.
@ -86,14 +87,14 @@ class Supplier extends AbstractCompany
* @ORM\OrderBy({"name" = "ASC"})
* @Assert\Valid()
*/
protected $attachments;
protected Collection $attachments;
/** @var Collection<int, SupplierParameter>
* @ORM\OneToMany(targetEntity="App\Entity\Parameters\SupplierParameter", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})
* @Assert\Valid()
*/
protected $parameters;
protected Collection $parameters;
/**
* Gets the currency that should be used by default, when creating a orderdetail with this supplier.

View file

@ -69,13 +69,13 @@ class Currency extends AbstractStructuralDBElement
* @ORM\OneToMany(targetEntity="Currency", mappedBy="parent", cascade={"persist"})
* @ORM\OrderBy({"name" = "ASC"})
*/
protected $children;
protected Collection $children;
/**
* @ORM\ManyToOne(targetEntity="Currency", inversedBy="children")
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
*/
protected $parent;
protected ?AbstractStructuralDBElement $parent;
/**
* @var Collection<int, CurrencyAttachment>
@ -83,19 +83,19 @@ class Currency extends AbstractStructuralDBElement
* @ORM\OrderBy({"name" = "ASC"})
* @Assert\Valid()
*/
protected $attachments;
protected Collection $attachments;
/** @var Collection<int, CurrencyParameter>
* @ORM\OneToMany(targetEntity="App\Entity\Parameters\CurrencyParameter", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})
* @Assert\Valid()
*/
protected $parameters;
protected Collection $parameters;
/** @var Collection<int, Pricedetail>
* @ORM\OneToMany(targetEntity="App\Entity\PriceInformations\Pricedetail", mappedBy="currency")
*/
protected $pricedetails;
protected Collection $pricedetails;
public function __construct()
{

View file

@ -57,7 +57,7 @@ class Orderdetail extends AbstractDBElement implements TimeStampableInterface, N
* @ORM\OrderBy({"min_discount_quantity" = "ASC"})
* @Groups({"extended", "full", "import"})
*/
protected $pricedetails;
protected Collection $pricedetails;
/**
* @var string
@ -82,7 +82,7 @@ class Orderdetail extends AbstractDBElement implements TimeStampableInterface, N
protected string $supplier_product_url = '';
/**
* @var Part
* @var Part|null
* @ORM\ManyToOne(targetEntity="App\Entity\Parts\Part", inversedBy="orderdetails")
* @ORM\JoinColumn(name="part_id", referencedColumnName="id", nullable=false, onDelete="CASCADE")
* @Assert\NotNull()
@ -90,7 +90,7 @@ class Orderdetail extends AbstractDBElement implements TimeStampableInterface, N
protected ?Part $part = null;
/**
* @var Supplier
* @var Supplier|null
* @ORM\ManyToOne(targetEntity="App\Entity\Parts\Supplier", inversedBy="orderdetails")
* @ORM\JoinColumn(name="id_supplier", referencedColumnName="id")
* @Assert\NotNull(message="validator.orderdetail.supplier_must_not_be_null")

View file

@ -266,9 +266,9 @@ class Pricedetail extends AbstractDBElement implements TimeStampableInterface
*
* @param BigDecimal $new_price the new price as a float number
*
* * This is the price for "price_related_quantity" parts!!
* * Example: if "price_related_quantity" is '10',
* you have to set here the price for 10 parts!
* This is the price for "price_related_quantity" parts!!
* Example: if "price_related_quantity" is 10,
* you have to set here the price for 10 parts!
*
* @return $this
*/

View file

@ -47,20 +47,20 @@ class Project extends AbstractStructuralDBElement
* @ORM\OrderBy({"name" = "ASC"})
* @var Collection
*/
protected $children;
protected Collection $children;
/**
* @ORM\ManyToOne(targetEntity="Project", inversedBy="children")
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
*/
protected $parent;
protected ?AbstractStructuralDBElement $parent;
/**
* @ORM\OneToMany(targetEntity="ProjectBOMEntry", mappedBy="project", cascade={"persist", "remove"}, orphanRemoval=true)
* @Assert\Valid()
* @Groups({"extended", "full"})
*/
protected $bom_entries;
protected Collection $bom_entries;
/**
* @ORM\Column(type="integer")
@ -68,7 +68,7 @@ class Project extends AbstractStructuralDBElement
protected int $order_quantity = 0;
/**
* @var string The current status of the project
* @var string|null The current status of the project
* @ORM\Column(type="string", length=64, nullable=true)
* @Assert\Choice({"draft","planning","in_production","finished","archived"})
* @Groups({"extended", "full"})
@ -98,13 +98,13 @@ class Project extends AbstractStructuralDBElement
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\ProjectAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"name" = "ASC"})
*/
protected $attachments;
protected Collection $attachments;
/** @var Collection<int, ProjectParameter>
* @ORM\OneToMany(targetEntity="App\Entity\Parameters\ProjectParameter", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})
*/
protected $parameters;
protected Collection $parameters;
/********************************************************************************
*
@ -116,6 +116,7 @@ class Project extends AbstractStructuralDBElement
{
parent::__construct();
$this->bom_entries = new ArrayCollection();
$this->children = new ArrayCollection();
}
public function __clone()

View file

@ -61,7 +61,7 @@ class ProjectBOMEntry extends AbstractDBElement
protected string $mountnames = '';
/**
* @var string An optional name describing this BOM entry (useful for non-part entries)
* @var string|null An optional name describing this BOM entry (useful for non-part entries)
* @ORM\Column(type="string", nullable=true)
* @Assert\Expression(
* "this.getPart() !== null or this.getName() !== null",
@ -77,7 +77,7 @@ class ProjectBOMEntry extends AbstractDBElement
protected string $comment;
/**
* @var Project
* @var Project|null
* @ORM\ManyToOne(targetEntity="Project", inversedBy="bom_entries")
* @ORM\JoinColumn(name="id_device", referencedColumnName="id")
*/
@ -91,7 +91,7 @@ class ProjectBOMEntry extends AbstractDBElement
protected ?Part $part = null;
/**
* @var BigDecimal The price of this non-part BOM entry
* @var BigDecimal|null The price of this non-part BOM entry
* @ORM\Column(type="big_decimal", precision=11, scale=5, nullable=true)
* @Assert\AtLeastOneOf({
* @BigDecimalPositive(),

View file

@ -34,7 +34,7 @@ use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
/**
* This entity represents an user group.
* This entity represents a user group.
*
* @ORM\Entity()
* @ORM\Table("`groups`", indexes={
@ -47,35 +47,35 @@ class Group extends AbstractStructuralDBElement implements HasPermissionsInterfa
/**
* @ORM\OneToMany(targetEntity="Group", mappedBy="parent")
* @ORM\OrderBy({"name" = "ASC"})
* @var Collection
* @var Collection<int, self>
*/
protected $children;
protected Collection $children;
/**
* @ORM\ManyToOne(targetEntity="Group", inversedBy="children")
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
*/
protected $parent;
protected ?AbstractStructuralDBElement $parent;
/**
* @ORM\OneToMany(targetEntity="User", mappedBy="group")
* @var Collection<User>
* @var Collection<int, User>
*/
protected $users;
protected Collection $users;
/**
* @var bool If true all users associated with this group must have enabled some kind of 2 factor authentication
* @var bool If true all users associated with this group must have enabled some kind of two-factor authentication
* @ORM\Column(type="boolean", name="enforce_2fa")
* @Groups({"extended", "full", "import"})
*/
protected $enforce2FA = false;
protected bool $enforce2FA = false;
/**
* @var Collection<int, GroupAttachment>
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\GroupAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"name" = "ASC"})
* @Assert\Valid()
*/
protected $attachments;
protected Collection $attachments;
/**
* @var PermissionData|null
@ -90,13 +90,14 @@ class Group extends AbstractStructuralDBElement implements HasPermissionsInterfa
* @ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})
* @Assert\Valid()
*/
protected $parameters;
protected Collection $parameters;
public function __construct()
{
parent::__construct();
$this->permissions = new PermissionData();
$this->users = new ArrayCollection();
$this->children = new ArrayCollection();
}
/**

Some files were not shown because too many files have changed in this diff Show more