Added an PHP CS fixer config file and applied it to files.

We now use the same the same style as the symfony project, and it allows us to simply fix the style by executing php_cs_fixer fix in the project root.
This commit is contained in:
Jan Böhmer 2019-11-09 00:47:20 +01:00
parent 89258bc102
commit e557bdedd5
210 changed files with 2099 additions and 2742 deletions

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,19 +17,16 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services;
use App\Entity\Parts\MeasurementUnit;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* This service formats an part amout using a Measurement Unit.
* @package App\Services
*/
class AmountFormatter
{
@ -44,31 +41,37 @@ class AmountFormatter
{
$resolver->setDefaults([
'show_prefix' => function (Options $options) {
if ($options['measurement_unit'] !== null) {
if (null !== $options['measurement_unit']) {
/** @var MeasurementUnit $unit */
$unit = $options['measurement_unit'];
return $unit->isUseSIPrefix();
}
return false;
},
'is_integer' => function (Options $options) {
if ($options['measurement_unit'] !== null) {
if (null !== $options['measurement_unit']) {
/** @var MeasurementUnit $unit */
$unit = $options['measurement_unit'];
return $unit->isInteger();
}
return true;
},
'unit' => function (Options $options) {
if ($options['measurement_unit'] !== null) {
if (null !== $options['measurement_unit']) {
/** @var MeasurementUnit $unit */
$unit = $options['measurement_unit'];
return $unit->getUnit();
}
return '';
},
'decimals' => 2,
'error_mapping' => [ '.' => 'value']
'error_mapping' => ['.' => 'value'],
]);
$resolver->setAllowedTypes('decimals', 'int');
@ -78,17 +81,20 @@ class AmountFormatter
if ($options['is_integer']) {
return 0;
}
return $value;
});
}
/**
* Formats the given value using the measurement unit and options.
*
* @param $value float|int The value that should be formatted. Must be numeric.
* @param MeasurementUnit|null $unit The measurement unit, whose unit symbol should be used for formatting.
* If set to null, it is assumed that the part amount is measured in pieces.
* @param array $options
* If set to null, it is assumed that the part amount is measured in pieces.
*
* @return string The formatted string
*
* @throws \InvalidArgumentException Thrown if $value is not numeric.
*/
public function format($value, ?MeasurementUnit $unit = null, array $options = [])
@ -116,10 +122,11 @@ class AmountFormatter
//Otherwise just output it
if (!empty($options['unit'])) {
$format_string = '%.' . $options['decimals'] . 'f ' . $options['unit'];
$format_string = '%.'.$options['decimals'].'f '.$options['unit'];
} else { //Dont add space after number if no unit was specified
$format_string = '%.' . $options['decimals'] . 'f';
$format_string = '%.'.$options['decimals'].'f';
}
return sprintf($format_string, $value);
}
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,29 +17,11 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services\Attachments;
use App\Entity\Attachments\Attachment;
use App\Entity\Attachments\AttachmentContainingDBElement;
use App\Entity\Attachments\AttachmentTypeAttachment;
use App\Entity\Attachments\CategoryAttachment;
use App\Entity\Attachments\CurrencyAttachment;
use App\Entity\Attachments\DeviceAttachment;
use App\Entity\Attachments\FootprintAttachment;
use App\Entity\Attachments\GroupAttachment;
use App\Entity\Attachments\ManufacturerAttachment;
use App\Entity\Attachments\MeasurementUnitAttachment;
use App\Entity\Attachments\PartAttachment;
use App\Entity\Attachments\StorelocationAttachment;
use App\Entity\Attachments\SupplierAttachment;
use App\Entity\Attachments\UserAttachment;
use App\Services\Attachments\AttachmentPathResolver;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* This service contains basic commonly used functions to work with attachments.
@ -47,11 +29,9 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
* (like filesize or if a file is existing).
*
* Special operations like getting attachment urls or handling file uploading/downloading are in their own services.
* @package App\Services
*/
class AttachmentManager
{
protected $pathResolver;
public function __construct(AttachmentPathResolver $pathResolver)
@ -61,11 +41,13 @@ class AttachmentManager
/**
* Gets an SPLFileInfo object representing the file associated with the attachment.
*
* @param Attachment $attachment The attachment for which the file should be generated
*
* @return \SplFileInfo|null The fileinfo for the attachment file. Null, if the attachment is external or has
* invalid file.
* invalid file.
*/
public function attachmentToFile(Attachment $attachment) : ?\SplFileInfo
public function attachmentToFile(Attachment $attachment): ?\SplFileInfo
{
if ($attachment->isExternal() || !$this->isFileExisting($attachment)) {
return null;
@ -77,7 +59,9 @@ class AttachmentManager
/**
* Returns the absolute filepath of the attachment. Null is returned, if the attachment is externally saved,
* or is not existing.
*
* @param Attachment $attachment The attachment for which the filepath should be determined
*
* @return string|null
*/
public function toAbsoluteFilePath(Attachment $attachment): ?string
@ -93,15 +77,16 @@ class AttachmentManager
$path = $this->pathResolver->placeholderToRealPath($attachment->getPath());
//realpath does not work with null as argument
if ($path === null) {
if (null === $path) {
return null;
}
$tmp = realpath($path);
//If path is not existing realpath returns false.
if ($tmp === false) {
if (false === $tmp) {
return null;
}
return $tmp;
}
@ -127,6 +112,7 @@ class AttachmentManager
* For external attachments or not existing attachments, null is returned.
*
* @param Attachment $attachment The filesize for which the filesize should be calculated.
*
* @return int|null
*/
public function getFileSize(Attachment $attachment): ?int
@ -140,22 +126,23 @@ class AttachmentManager
}
$tmp = filesize($this->toAbsoluteFilePath($attachment));
return $tmp !== false ? $tmp : null;
return false !== $tmp ? $tmp : null;
}
/**
* Returns a human readable version of the attachment file size.
* For external attachments, null is returned.
*
* @param Attachment $attachment
* @param int $decimals The number of decimals numbers that should be printed
*
* @return string|null A string like 1.3M
*/
public function getHumanFileSize(Attachment $attachment, $decimals = 2): ?string
{
$bytes = $this->getFileSize($attachment);
if ($bytes == null) {
if (null == $bytes) {
return null;
}
@ -163,7 +150,8 @@ class AttachmentManager
//Taken from: https://www.php.net/manual/de/function.filesize.php#106569 and slightly modified
$sz = 'BKMGTP';
$factor = (int) floor((strlen($bytes) - 1) / 3);
return sprintf("%.{$decimals}f", $bytes / 1024 ** $factor) . @$sz[$factor];
$factor = (int) floor((\strlen($bytes) - 1) / 3);
return sprintf("%.{$decimals}f", $bytes / 1024 ** $factor).@$sz[$factor];
}
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,19 +17,15 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services\Attachments;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpKernel\KernelInterface;
/**
* This service converts the relative pathes for attachments saved in database (like %MEDIA%/img.jpg) to real pathes
* an vice versa.
* @package App\Services\Attachments
*/
class AttachmentPathResolver
{
@ -47,11 +43,12 @@ class AttachmentPathResolver
/**
* AttachmentPathResolver constructor.
* @param string $project_dir The kernel that should be used to resolve the project dir.
* @param string $media_path The path where uploaded attachments should be stored.
*
* @param string $project_dir The kernel that should be used to resolve the project dir.
* @param string $media_path The path where uploaded attachments should be stored.
* @param string|null $footprints_path The path where builtin attachments are stored.
* Set to null if this ressource should be disabled.
* @param string|null $models_path Set to null if this ressource should be disabled.
* Set to null if this ressource should be disabled.
* @param string|null $models_path Set to null if this ressource should be disabled.
*/
public function __construct(string $project_dir, string $media_path, string $secure_path, ?string $footprints_path, ?string $models_path)
{
@ -69,7 +66,7 @@ class AttachmentPathResolver
//Remove all disabled placeholders
foreach ($this->pathes as $key => $path) {
if ($path === null) {
if (null === $path) {
unset($this->placeholders[$key], $this->pathes[$key]);
}
}
@ -82,13 +79,16 @@ class AttachmentPathResolver
/**
* Converts a path passed by parameter from services.yaml (which can be an absolute path or relative to project dir)
* to an absolute path. When a relative path is passed, the directory must exist or null is returned.
*
* @internal
*
* @param string|null $param_path The parameter value that should be converted to a absolute path
*
* @return string|null
*/
public function parameterToAbsolutePath(?string $param_path) : ?string
public function parameterToAbsolutePath(?string $param_path): ?string
{
if ($param_path === null) {
if (null === $param_path) {
return null;
}
@ -97,17 +97,18 @@ class AttachmentPathResolver
if ($fs->isAbsolutePath($param_path)) {
$tmp = realpath($param_path);
//Disable ressource if path is not existing
if ($tmp === false) {
if (false === $tmp) {
return null;
}
return $tmp;
}
//Otherwise prepend the project path
$tmp = realpath($this->project_dir . DIRECTORY_SEPARATOR . $param_path);
$tmp = realpath($this->project_dir.\DIRECTORY_SEPARATOR.$param_path);
//If path does not exist then disable the placeholder
if ($tmp === false) {
if (false === $tmp) {
return null;
}
@ -119,38 +120,39 @@ class AttachmentPathResolver
* Create an array usable for preg_replace out of an array of placeholders or pathes.
* Slashes and other chars become escaped.
* For example: '%TEST%' becomes '/^%TEST%/'.
* @param array $array
*
* @return array
*/
protected function arrayToRegexArray(array $array) : array
protected function arrayToRegexArray(array $array): array
{
$ret = [];
foreach ($array as $item) {
$item = str_replace(['\\'], ['/'], $item);
$ret[] = '/' . preg_quote($item, '/') . '/';
$ret[] = '/'.preg_quote($item, '/').'/';
}
return $ret;
}
/**
* Converts an relative placeholder filepath (with %MEDIA% or older %BASE%) to an absolute filepath on disk.
* The directory separator is always /. Relative pathes are not realy possible (.. is striped)
* The directory separator is always /. Relative pathes are not realy possible (.. is striped).
*
* @param string $placeholder_path The filepath with placeholder for which the real path should be determined.
*
* @return string|null The absolute real path of the file, or null if the placeholder path is invalid
*/
public function placeholderToRealPath(string $placeholder_path) : ?string
public function placeholderToRealPath(string $placeholder_path): ?string
{
//The new attachments use %MEDIA% as placeholders, which is the directory set in media_directory
//Older path entries are given via %BASE% which was the project root
$count = 0;
$placeholder_path = preg_replace($this->placeholders_regex, $this->pathes, $placeholder_path,-1,$count);
$placeholder_path = preg_replace($this->placeholders_regex, $this->pathes, $placeholder_path, -1, $count);
//A valid placeholder can have only one
if ($count !== 1) {
if (1 !== $count) {
return null;
}
@ -160,7 +162,7 @@ class AttachmentPathResolver
}
//Path is invalid if path is directory traversal
if (strpos($placeholder_path, '..') !== false) {
if (false !== strpos($placeholder_path, '..')) {
return null;
}
@ -172,12 +174,14 @@ class AttachmentPathResolver
/**
* Converts an real absolute filepath to a placeholder version.
* @param string $real_path The absolute path, for which the placeholder version should be generated.
* @param bool $old_version By default the %MEDIA% placeholder is used, which is directly replaced with the
* media directory. If set to true, the old version with %BASE% will be used, which is the project directory.
*
* @param string $real_path The absolute path, for which the placeholder version should be generated.
* @param bool $old_version By default the %MEDIA% placeholder is used, which is directly replaced with the
* media directory. If set to true, the old version with %BASE% will be used, which is the project directory.
*
* @return string The placeholder version of the filepath
*/
public function realPathToPlaceholder(string $real_path, bool $old_version = false) : ?string
public function realPathToPlaceholder(string $real_path, bool $old_version = false): ?string
{
$count = 0;
@ -194,7 +198,7 @@ class AttachmentPathResolver
$real_path = preg_replace($this->pathes_regex, $this->placeholders, $real_path, -1, $count);
}
if ($count !== 1) {
if (1 !== $count) {
return null;
}
@ -208,9 +212,10 @@ class AttachmentPathResolver
/**
* The path where uploaded attachments is stored.
*
* @return string The absolute path to the media folder.
*/
public function getMediaPath() : string
public function getMediaPath(): string
{
return $this->media_path;
}
@ -218,28 +223,31 @@ class AttachmentPathResolver
/**
* The path where secured attachments are stored. Must not be located in public/ folder, so it can only be accessed
* via the attachment controller.
*
* @return string The absolute path to the secure path.
*/
public function getSecurePath() : string
public function getSecurePath(): string
{
return $this->secure_path;
}
/**
* The string where the builtin footprints are stored
* The string where the builtin footprints are stored.
*
* @return string|null The absolute path to the footprints folder. Null if built footprints were disabled.
*/
public function getFootprintsPath() : ?string
public function getFootprintsPath(): ?string
{
return $this->footprints_path;
}
/**
* The string where the builtin 3D models are stored
* The string where the builtin 3D models are stored.
*
* @return string|null The absolute path to the models folder. Null if builtin models were disabled.
*/
public function getModelsPath() : ?string
public function getModelsPath(): ?string
{
return $this->models_path;
}
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,14 +17,11 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services\Attachments;
use App\Entity\Attachments\Attachment;
use App\Services\Attachments\AttachmentPathResolver;
use App\Services\Attachments\AttachmentURLGenerator;
use Doctrine\ORM\EntityManagerInterface;
use Liip\ImagineBundle\Imagine\Cache\CacheManager;
use Symfony\Component\Filesystem\Filesystem;
@ -32,7 +29,6 @@ use Symfony\Component\HttpFoundation\File\File;
/**
* This service provides functions to find attachments via an reverse search based on a file.
* @package App\Services
*/
class AttachmentReverseSearch
{
@ -51,11 +47,13 @@ class AttachmentReverseSearch
}
/**
* Find all attachments that use the given file
* Find all attachments that use the given file.
*
* @param \SplFileInfo $file The file for which is searched
*
* @return Attachment[] An list of attachments that use the given file.
*/
public function findAttachmentsByFile(\SplFileInfo $file) : array
public function findAttachmentsByFile(\SplFileInfo $file): array
{
//Path with %MEDIA%
$relative_path_new = $this->pathResolver->realPathToPlaceholder($file->getPathname());
@ -63,20 +61,22 @@ class AttachmentReverseSearch
$relative_path_old = $this->pathResolver->realPathToPlaceholder($file->getPathname(), true);
$repo = $this->em->getRepository(Attachment::class);
return $repo->findBy(['path' => [$relative_path_new, $relative_path_old]]);
}
/**
* Deletes the given file if it is not used by more than $threshold attachments
* @param \SplFileInfo $file The file that should be removed
* @param int $threshold The threshold used, to determine if a file should be deleted or not.
* Deletes the given file if it is not used by more than $threshold attachments.
*
* @param \SplFileInfo $file The file that should be removed
* @param int $threshold The threshold used, to determine if a file should be deleted or not.
*
* @return bool True, if the file was delete. False if not.
*/
public function deleteIfNotUsed(\SplFileInfo $file, int $threshold = 1) : bool
public function deleteIfNotUsed(\SplFileInfo $file, int $threshold = 1): bool
{
/* When the file is used more then $threshold times, don't delete it */
if (count($this->findAttachmentsByFile($file)) > $threshold) {
if (\count($this->findAttachmentsByFile($file)) > $threshold) {
return false;
}
@ -86,8 +86,6 @@ class AttachmentReverseSearch
$fs = new Filesystem();
$fs->remove($file);
return true;
}
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,12 +17,10 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services\Attachments;
use App\Entity\Attachments\Attachment;
use App\Entity\Attachments\AttachmentContainingDBElement;
use App\Entity\Attachments\AttachmentTypeAttachment;
@ -38,14 +36,8 @@ use App\Entity\Attachments\StorelocationAttachment;
use App\Entity\Attachments\SupplierAttachment;
use App\Entity\Attachments\UserAttachment;
use App\Exceptions\AttachmentDownloadException;
use App\Services\Attachments\AttachmentManager;
use Doctrine\Common\Annotations\IndexedReader;
use Nyholm\Psr7\Request;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Mime\MimeTypeGuesserInterface;
use Symfony\Component\Mime\MimeTypes;
use Symfony\Component\Mime\MimeTypesInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
@ -53,7 +45,6 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
/**
* This service handles the form submitting of an attachment and handles things like file uploading and downloading.
* @package App\Services\Attachments
*/
class AttachmentSubmitHandler
{
@ -63,7 +54,7 @@ class AttachmentSubmitHandler
protected $httpClient;
protected $mimeTypes;
public function __construct (AttachmentPathResolver $pathResolver, bool $allow_attachments_downloads,
public function __construct(AttachmentPathResolver $pathResolver, bool $allow_attachments_downloads,
HttpClientInterface $httpClient, MimeTypesInterface $mimeTypes)
{
$this->pathResolver = $pathResolver;
@ -77,10 +68,10 @@ class AttachmentSubmitHandler
DeviceAttachment::class => 'device', FootprintAttachment::class => 'footprint',
GroupAttachment::class => 'group', ManufacturerAttachment::class => 'manufacturer',
MeasurementUnitAttachment::class => 'measurement_unit', StorelocationAttachment::class => 'storelocation',
SupplierAttachment::class => 'supplier', UserAttachment::class => 'user'];
SupplierAttachment::class => 'supplier', UserAttachment::class => 'user', ];
}
protected function configureOptions(OptionsResolver $resolver) : void
protected function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
//If no preview image was set yet, the new uploaded file will become the preview image
@ -94,11 +85,13 @@ class AttachmentSubmitHandler
/**
* Generates a filename for the given attachment and extension.
* The filename contains a random id, so every time this function is called you get an unique name.
*
* @param Attachment $attachment The attachment that should be used for generating an attachment
* @param string $extension The extension that the new file should have (must only contain chars allowed in pathes)
* @param string $extension The extension that the new file should have (must only contain chars allowed in pathes)
*
* @return string The new filename.
*/
public function generateAttachmentFilename(Attachment $attachment, string $extension) : string
public function generateAttachmentFilename(Attachment $attachment, string $extension): string
{
//Normalize extension
$extension = transliterator_transliterate(
@ -112,16 +105,18 @@ class AttachmentSubmitHandler
$attachment->getName()
);
return $safeName . '-' . uniqid('', false) . '.' . $extension;
return $safeName.'-'.uniqid('', false).'.'.$extension;
}
/**
* Generates an (absolute) path to a folder where the given attachment should be stored.
* @param Attachment $attachment The attachment that should be used for
* @param bool $secure_upload True if the file path should be located in a safe location
*
* @param Attachment $attachment The attachment that should be used for
* @param bool $secure_upload True if the file path should be located in a safe location
*
* @return string The absolute path for the attachment folder.
*/
public function generateAttachmentPath(Attachment $attachment, bool $secure_upload = false) : string
public function generateAttachmentPath(Attachment $attachment, bool $secure_upload = false): string
{
if ($secure_upload) {
$base_path = $this->pathResolver->getSecurePath();
@ -130,34 +125,32 @@ class AttachmentSubmitHandler
}
//Ensure the given attachment class is known to mapping
if (!isset($this->folder_mapping[get_class($attachment)])) {
throw new \InvalidArgumentException(
'The given attachment class is not known! The passed class was: ' . get_class($attachment)
);
if (!isset($this->folder_mapping[\get_class($attachment)])) {
throw new \InvalidArgumentException('The given attachment class is not known! The passed class was: '.\get_class($attachment));
}
//Ensure the attachment has an assigned element
if ($attachment->getElement() === null) {
throw new \InvalidArgumentException(
'The given attachment is not assigned to an element! An element is needed to generate a path!'
);
if (null === $attachment->getElement()) {
throw new \InvalidArgumentException('The given attachment is not assigned to an element! An element is needed to generate a path!');
}
//Build path
return
$base_path . DIRECTORY_SEPARATOR //Base path
. $this->folder_mapping[get_class($attachment)] . DIRECTORY_SEPARATOR . $attachment->getElement()->getID();
$base_path.\DIRECTORY_SEPARATOR //Base path
.$this->folder_mapping[\get_class($attachment)].\DIRECTORY_SEPARATOR.$attachment->getElement()->getID();
}
/**
* Handle the submit of an attachment form.
* This function will move the uploaded file or download the URL file to server, if needed.
* @param Attachment $attachment The attachment that should be used for handling.
* @param UploadedFile|null $file If given, that file will be moved to the right location
* @param array $options The options to use with the upload. Here you can specify that an URL should be downloaded,
* or an file should be moved to a secure location.
*
* @param Attachment $attachment The attachment that should be used for handling.
* @param UploadedFile|null $file If given, that file will be moved to the right location
* @param array $options The options to use with the upload. Here you can specify that an URL should be downloaded,
* or an file should be moved to a secure location.
*
* @return Attachment The attachment with the new filename (same instance as passed $attachment)
*/
public function handleFormSubmit(Attachment $attachment, ?UploadedFile $file, array $options = []) : Attachment
public function handleFormSubmit(Attachment $attachment, ?UploadedFile $file, array $options = []): Attachment
{
$resolver = new OptionsResolver();
$this->configureOptions($resolver);
@ -175,9 +168,9 @@ class AttachmentSubmitHandler
//Check if we should assign this attachment to master picture
//this is only possible if the attachment is new (not yet persisted to DB)
if ($options['become_preview_if_empty'] && $attachment->getID() === null && $attachment->isPicture()) {
if ($options['become_preview_if_empty'] && null === $attachment->getID() && $attachment->isPicture()) {
$element = $attachment->getElement();
if ($element instanceof AttachmentContainingDBElement && $element->getMasterPictureAttachment() === null) {
if ($element instanceof AttachmentContainingDBElement && null === $element->getMasterPictureAttachment()) {
$element->setMasterPictureAttachment($attachment);
}
}
@ -187,11 +180,13 @@ class AttachmentSubmitHandler
/**
* Move the given attachment to secure location (or back to public folder) if needed.
* @param Attachment $attachment The attachment for which the file should be moved.
* @param bool $secure_location This value determines, if the attachment is moved to the secure or public folder.
*
* @param Attachment $attachment The attachment for which the file should be moved.
* @param bool $secure_location This value determines, if the attachment is moved to the secure or public folder.
*
* @return Attachment The attachment with the updated filepath
*/
protected function moveFile(Attachment $attachment, bool $secure_location) : Attachment
protected function moveFile(Attachment $attachment, bool $secure_location): Attachment
{
//We can not do anything on builtins or external ressources
if ($attachment->isBuiltIn() || $attachment->isExternal()) {
@ -218,7 +213,7 @@ class AttachmentSubmitHandler
$ext = pathinfo($filename, PATHINFO_EXTENSION);
$new_path = $this->generateAttachmentPath($attachment, $secure_location)
. DIRECTORY_SEPARATOR . $this->generateAttachmentFilename($attachment, $ext);
.\DIRECTORY_SEPARATOR.$this->generateAttachmentFilename($attachment, $ext);
//Move file to new directory
$fs = new Filesystem();
@ -232,12 +227,13 @@ class AttachmentSubmitHandler
}
/**
* Download the URL set in the attachment and save it on the server
* @param Attachment $attachment
* Download the URL set in the attachment and save it on the server.
*
* @param array $options The options from the handleFormSubmit function
*
* @return Attachment The attachment with the new filepath
*/
protected function downloadURL(Attachment $attachment, array $options) : Attachment
protected function downloadURL(Attachment $attachment, array $options): Attachment
{
//Check if we are allowed to download files
if (!$this->allow_attachments_downloads) {
@ -248,7 +244,7 @@ class AttachmentSubmitHandler
$fs = new Filesystem();
$attachment_folder = $this->generateAttachmentPath($attachment, $options['secure_attachment']);
$tmp_path = $attachment_folder . DIRECTORY_SEPARATOR . $this->generateAttachmentFilename($attachment, 'tmp');
$tmp_path = $attachment_folder.\DIRECTORY_SEPARATOR.$this->generateAttachmentFilename($attachment, 'tmp');
try {
$response = $this->httpClient->request('GET', $url, [
@ -256,7 +252,7 @@ class AttachmentSubmitHandler
]);
if (200 !== $response->getStatusCode()) {
throw new AttachmentDownloadException('Status code: ' . $response->getStatusCode());
throw new AttachmentDownloadException('Status code: '.$response->getStatusCode());
}
//Open a temporary file in the attachment folder
@ -271,7 +267,7 @@ class AttachmentSubmitHandler
//File download should be finished here, so determine the new filename and extension
$headers = $response->getHeaders();
//Try to determine an filename
$filename = "";
$filename = '';
//If an content disposition header was set try to extract the filename out of it
if (isset($headers['content-disposition'])) {
@ -281,7 +277,7 @@ class AttachmentSubmitHandler
}
//If we dont know filename yet, try to determine it out of url
if ($filename === "") {
if ('' === $filename) {
$filename = basename(parse_url($url, PHP_URL_PATH));
}
@ -297,14 +293,13 @@ class AttachmentSubmitHandler
}
//Rename the file to its new name and save path to attachment entity
$new_path = $attachment_folder . DIRECTORY_SEPARATOR . $this->generateAttachmentFilename($attachment, $new_ext);
$new_path = $attachment_folder.\DIRECTORY_SEPARATOR.$this->generateAttachmentFilename($attachment, $new_ext);
$fs->rename($tmp_path, $new_path);
//Make our file path relative to %BASE%
$new_path = $this->pathResolver->realPathToPlaceholder($new_path);
//Save the path to the attachment
$attachment->setPath($new_path);
} catch (TransportExceptionInterface $exception) {
throw new AttachmentDownloadException('Transport error!');
}
@ -313,13 +308,15 @@ class AttachmentSubmitHandler
}
/**
* Moves the given uploaded file to a permanent place and saves it into the attachment
* @param Attachment $attachment The attachment in which the file should be saved
* @param UploadedFile $file The file which was uploaded
* @param array $options The options from the handleFormSubmit function
* Moves the given uploaded file to a permanent place and saves it into the attachment.
*
* @param Attachment $attachment The attachment in which the file should be saved
* @param UploadedFile $file The file which was uploaded
* @param array $options The options from the handleFormSubmit function
*
* @return Attachment The attachment with the new filepath
*/
protected function upload(Attachment $attachment, UploadedFile $file, array $options) : Attachment
protected function upload(Attachment $attachment, UploadedFile $file, array $options): Attachment
{
//Move our temporay attachment to its final location
$file_path = $file->move(
@ -336,4 +333,4 @@ class AttachmentSubmitHandler
return $attachment;
}
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,16 +17,12 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services\Attachments;
use App\Entity\Attachments\Attachment;
use App\Services\Attachments\AttachmentManager;
use Liip\ImagineBundle\Service\FilterService;
use Symfony\Component\Asset\Package;
use Symfony\Component\Asset\Packages;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
@ -49,7 +45,6 @@ class AttachmentURLGenerator
$this->attachmentHelper = $attachmentHelper;
$this->filterService = $filterService;
//Determine a normalized path to the public folder (assets are relative to this folder)
$this->public_path = $this->pathResolver->parameterToAbsolutePath('public');
}
@ -57,46 +52,46 @@ class AttachmentURLGenerator
/**
* Converts the absolute file path to a version relative to the public folder, that can be passed to asset
* Asset Component functions.
* @param string $absolute_path The absolute path that should be converted.
* @param string|null $public_path The public path to which the relative pathes should be created.
* The path must NOT have a trailing slash!
* If this is set to null, the global public/ folder is used.
*
* @param string $absolute_path The absolute path that should be converted.
* @param string|null $public_path The public path to which the relative pathes should be created.
* The path must NOT have a trailing slash!
* If this is set to null, the global public/ folder is used.
*
* @return string|null The relative version of the string. Null if the absolute path was not a child folder
* of public path
* of public path
*/
public function absolutePathToAssetPath(string $absolute_path, ?string $public_path = null) : ?string
public function absolutePathToAssetPath(string $absolute_path, ?string $public_path = null): ?string
{
if ($public_path === null) {
if (null === $public_path) {
$public_path = $this->public_path;
}
//Our absolute path must begin with public path or we can not use it for asset pathes.
if (strpos($absolute_path, $public_path) !== 0) {
if (0 !== strpos($absolute_path, $public_path)) {
return null;
}
//Return the part relative after public path.
return substr($absolute_path, strlen($public_path) + 1);
return substr($absolute_path, \strlen($public_path) + 1);
}
/**
* Returns a URL under which the attachment file can be viewed.
* @param Attachment $attachment
*
* @return string
*/
public function getViewURL(Attachment $attachment) : string
public function getViewURL(Attachment $attachment): string
{
$absolute_path = $this->attachmentHelper->toAbsoluteFilePath($attachment);
if ($absolute_path === null) {
throw new \RuntimeException(
'The given attachment is external or has no valid file, so no URL can get generated for it!
Use Attachment::getURL() to get the external URL!'
);
if (null === $absolute_path) {
throw new \RuntimeException('The given attachment is external or has no valid file, so no URL can get generated for it!
Use Attachment::getURL() to get the external URL!');
}
$asset_path = $this->absolutePathToAssetPath($absolute_path);
//If path is not relative to public path or marked as secure, serve it via controller
if ($asset_path === null || $attachment->isSecure()) {
if (null === $asset_path || $attachment->isSecure()) {
return $this->urlGenerator->generate('attachment_view', ['id' => $attachment->getID()]);
}
@ -106,11 +101,10 @@ class AttachmentURLGenerator
/**
* Returns a URL to an thumbnail of the attachment file.
* @param Attachment $attachment
* @param string $filter_name
*
* @return string
*/
public function getThumbnailURL(Attachment $attachment, string $filter_name = 'thumbnail_sm') : string
public function getThumbnailURL(Attachment $attachment, string $filter_name = 'thumbnail_sm'): string
{
if (!$attachment->isPicture()) {
throw new \InvalidArgumentException('Thumbnail creation only works for picture attachments!');
@ -121,21 +115,19 @@ class AttachmentURLGenerator
}
$absolute_path = $this->attachmentHelper->toAbsoluteFilePath($attachment);
if ($absolute_path === null) {
throw new \RuntimeException(
'The given attachment is external or has no valid file, so no URL can get generated for it!'
);
if (null === $absolute_path) {
throw new \RuntimeException('The given attachment is external or has no valid file, so no URL can get generated for it!');
}
$asset_path = $this->absolutePathToAssetPath($absolute_path);
//If path is not relative to public path or marked as secure, serve it via controller
if ($asset_path === null || $attachment->isSecure()) {
if (null === $asset_path || $attachment->isSecure()) {
return $this->urlGenerator->generate('attachment_view', ['id' => $attachment->getID()]);
}
//For builtin ressources it is not useful to create a thumbnail
//because the footprints images are small and highly optimized already.
if ($filter_name === 'thumbnail_md' && $attachment->isBuiltIn()) {
if ('thumbnail_md' === $filter_name && $attachment->isBuiltIn()) {
return $this->assets->getUrl($asset_path);
}
@ -144,13 +136,13 @@ class AttachmentURLGenerator
}
/**
* Returns a download link to the file associated with the attachment
* @param Attachment $attachment
* Returns a download link to the file associated with the attachment.
*
* @return string
*/
public function getDownloadURL(Attachment $attachment) : string
public function getDownloadURL(Attachment $attachment): string
{
//Redirect always to download controller, which sets the correct headers for downloading:
return $this->urlGenerator->generate('attachment_download', ['id' => $attachment->getID()]);
}
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,21 +17,17 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services\Attachments;
use App\Entity\Attachments\Attachment;
use App\Services\Attachments\AttachmentPathResolver;
use Symfony\Component\Finder\Finder;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Contracts\Cache\CacheInterface;
/**
* This service is used to find builtin attachment ressources
* @package App\Services
* This service is used to find builtin attachment ressources.
*/
class BuiltinAttachmentsFinder
{
@ -50,7 +46,7 @@ class BuiltinAttachmentsFinder
'limit' => 15, //Given only 15 entries
//'allowed_extensions' => [], //Filter the filenames. For example ['jpg', 'jpeg'] to only get jpegs.
//'placeholders' => Attachment::BUILTIN_PLACEHOLDER, //By default use all builtin ressources,
'empty_returns_all' => false //Return the whole list of ressources when empty keyword is given
'empty_returns_all' => false, //Return the whole list of ressources when empty keyword is given
]);
}
@ -58,9 +54,10 @@ class BuiltinAttachmentsFinder
* Returns a list of all builtin ressources.
* The array is a list of the relative filenames using the %PLACEHOLDERS%.
* The list contains the files from all configured valid ressoureces.
*
* @return array The list of the ressources, or an empty array if an error happened.
*/
public function getListOfRessources() : array
public function getListOfRessources(): array
{
try {
return $this->cache->get('attachment_builtin_ressources', function () {
@ -73,7 +70,7 @@ class BuiltinAttachmentsFinder
foreach (Attachment::BUILTIN_PLACEHOLDER as $placeholder) {
$tmp = $this->pathResolver->placeholderToRealPath($placeholder);
//Ignore invalid/deactivated placeholders:
if ($tmp !== null) {
if (null !== $tmp) {
$finder->in($tmp);
}
}
@ -93,13 +90,15 @@ class BuiltinAttachmentsFinder
}
/**
* Find all ressources which are matching the given keyword and the specified options
* @param string $keyword The keyword you want to search for.
* @param array $options Here you can specify some options (see configureOptions for list of options)
* Find all ressources which are matching the given keyword and the specified options.
*
* @param string $keyword The keyword you want to search for.
* @param array $options Here you can specify some options (see configureOptions for list of options)
* @param array|null $base_list The list from which should be used as base for filtering.
*
* @return array The list of the results matching the specified keyword and options
*/
public function find(string $keyword, array $options = [], ?array $base_list = []) : array
public function find(string $keyword, array $options = [], ?array $base_list = []): array
{
if (empty($base_list)) {
$base_list = $this->getListOfRessources();
@ -109,14 +108,12 @@ class BuiltinAttachmentsFinder
$this->configureOptions($resolver);
$options = $resolver->resolve($options);
/*
if (empty($options['placeholders'])) {
return [];
} */
if ($keyword === '') {
if ('' === $keyword) {
if ($options['empty_returns_all']) {
$keyword = '.*';
} else {
@ -127,7 +124,7 @@ class BuiltinAttachmentsFinder
$keyword = preg_quote($keyword, '/');
}
/*TODO: Implement placheolder and extension filter */
/*TODO: Implement placheolder and extension filter */
/* if (!empty($options['allowed_extensions'])) {
$keyword .= "\.(";
foreach ($options['allowed_extensions'] as $extension) {
@ -137,9 +134,8 @@ class BuiltinAttachmentsFinder
} */
//Ignore case
$regex = '/.*' . $keyword . '.*/i';
$regex = '/.*'.$keyword.'.*/i';
return preg_grep($regex, $base_list);
}
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,7 +17,6 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services\Attachments;
@ -31,11 +30,9 @@ use Symfony\Contracts\Cache\ItemInterface;
* An servive that helps working with filetype filters (based on the format <input type=file> accept uses.
* See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#Unique_file_type_specifiers for
* more details.
* @package App\Services\Attachments
*/
class FileTypeFilterTools
{
//The file extensions that will be used for the 'video/*', 'image/*', 'audio/*' placeholders
//These file formats can be directly played in common browesers
//Source: https://www.chromium.org/audio-video
@ -53,17 +50,18 @@ class FileTypeFilterTools
$this->cache = $cache;
}
/**
* Check if a filetype filter string is valid.
*
* @param string $filter The filter string that should be validated.
*
* @return bool Returns true, if the string is valid.
*/
public function validateFilterString(string $filter) : bool
public function validateFilterString(string $filter): bool
{
$filter = trim($filter);
//An empty filter is valid (means no filter applied)
if ($filter === '') {
if ('' === $filter) {
return true;
}
@ -73,7 +71,7 @@ class FileTypeFilterTools
$element = trim($element);
if (!preg_match('/^\.\w+$/', $element) // .ext is allowed
&& !preg_match('/^[-\w.]+\/[-\w.]+/', $element) //Explicit MIME type is allowed
&& !in_array($element, static::ALLOWED_MIME_PLACEHOLDERS, false)) { //image/* is allowed
&& !\in_array($element, static::ALLOWED_MIME_PLACEHOLDERS, false)) { //image/* is allowed
return false;
}
}
@ -85,10 +83,12 @@ class FileTypeFilterTools
/**
* Normalize a filter string. All extensions are converted to lowercase, too much whitespaces are removed.
* The filter string is not validated.
*
* @param string $filter The filter string that should be normalized.
*
* @return string The normalized filter string
*/
public function normalizeFilterString(string $filter) : string
public function normalizeFilterString(string $filter): string
{
$filter = trim($filter);
//Replace other separators, with , so we can split it properly
@ -101,75 +101,80 @@ class FileTypeFilterTools
foreach ($elements as $key => &$element) {
$element = trim($element);
//Remove empty elements
if ($element === '') {
if ('' === $element) {
unset($elements[$key]);
}
//Convert *.jpg to .jpg
if (strpos($element, '*.') === 0) {
if (0 === strpos($element, '*.')) {
$element = str_replace('*.', '.', $element);
}
//Convert image to image/*
if ($element === 'image' || $element === 'image/') {
if ('image' === $element || 'image/' === $element) {
$element = 'image/*';
} elseif ($element === 'video' || $element === 'video/') {
} elseif ('video' === $element || 'video/' === $element) {
$element = 'video/*';
} elseif ($element === 'audio' || $element === 'audio/') {
} elseif ('audio' === $element || 'audio/' === $element) {
$element = 'audio/*';
} elseif (!preg_match('/^[-\w.]+\/[-\w.*]+/', $element) && strpos($element, '.') !== 0) {
} elseif (!preg_match('/^[-\w.]+\/[-\w.*]+/', $element) && 0 !== strpos($element, '.')) {
//Convert jpg to .jpg
$element = '.' . $element;
$element = '.'.$element;
}
}
$elements = array_unique($elements);
return implode($elements, ',');
return implode(',', $elements);
}
/**
* Get a list of all file extensions that matches the given filter string
* Get a list of all file extensions that matches the given filter string.
*
* @param string $filter A valid filetype filter string.
*
* @return string[] An array of allowed extensions ['txt', 'csv', 'gif']
*/
public function resolveFileExtensions(string $filter) : array
public function resolveFileExtensions(string $filter): array
{
$filter = trim($filter);
return $this->cache->get('filter_exts_' . md5($filter), function (ItemInterface $item) use ($filter) {
return $this->cache->get('filter_exts_'.md5($filter), function (ItemInterface $item) use ($filter) {
$elements = explode(',', $filter);
$extensions = [];
foreach ($elements as $element) {
$element = trim($element);
if (strpos($element, '.') === 0) {
if (0 === strpos($element, '.')) {
//We found an explicit specified file extension -> add it to list
$extensions[] = substr($element, 1);
} elseif ($element === 'image/*') {
} elseif ('image/*' === $element) {
$extensions = array_merge($extensions, static::IMAGE_EXTS);
} elseif ($element === 'audio/*') {
} elseif ('audio/*' === $element) {
$extensions = array_merge($extensions, static::AUDIO_EXTS);
} elseif ($element === 'image/*') {
} elseif ('image/*' === $element) {
$extensions = array_merge($extensions, static::VIDEO_EXTS);
} elseif (preg_match('/^[-\w.]+\/[-\w.*]+/', $element)) {
$extensions = array_merge($extensions, $this->mimeTypes->getExtensions($element));
}
}
return array_unique($extensions);
});
}
/**
* Check if the given extension matches the filter.
* @param string $filter The filter which should be used for checking.
*
* @param string $filter The filter which should be used for checking.
* @param string $extension The extension that should be checked.
*
* @return bool Returns true, if the extension is allowed with the given filter.
*/
public function isExtensionAllowed(string $filter, string $extension) : bool
public function isExtensionAllowed(string $filter, string $extension): bool
{
$extension = strtolower($extension);
return empty($filter) || in_array($extension, $this->resolveFileExtensions($filter), false);
return empty($filter) || \in_array($extension, $this->resolveFileExtensions($filter), false);
}
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,19 +17,13 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services\Attachments;
use App\Entity\Attachments\Attachment;
use App\Entity\Parts\Part;
use App\Services\Attachments\AttachmentManager;
/**
* @package App\Services\Attachments
*/
class PartPreviewGenerator
{
protected $attachmentHelper;
@ -42,11 +36,13 @@ class PartPreviewGenerator
/**
* Returns a list of attachments that can be used for previewing the part ordered by priority.
* The priority is: Part MasterAttachment -> Footprint MasterAttachment -> Category MasterAttachment
* -> Storelocation Attachment -> MeasurementUnit Attachment -> ManufacturerAttachment
* -> Storelocation Attachment -> MeasurementUnit Attachment -> ManufacturerAttachment.
*
* @param Part $part The part for which the attachments should be determined.
*
* @return Attachment[]
*/
public function getPreviewAttachments(Part $part) : array
public function getPreviewAttachments(Part $part): array
{
$list = [];
@ -56,14 +52,14 @@ class PartPreviewGenerator
$list[] = $attachment;
}
if ($part->getFootprint() !== null) {
if (null !== $part->getFootprint()) {
$attachment = $part->getFootprint()->getMasterPictureAttachment();
if ($this->isAttachmentValidPicture($attachment)) {
$list[] = $attachment;
}
}
if ($part->getCategory() !== null) {
if (null !== $part->getCategory()) {
$attachment = $part->getCategory()->getMasterPictureAttachment();
if ($this->isAttachmentValidPicture($attachment)) {
$list[] = $attachment;
@ -71,7 +67,7 @@ class PartPreviewGenerator
}
foreach ($part->getPartLots() as $lot) {
if ($lot->getStorageLocation() !== null) {
if (null !== $lot->getStorageLocation()) {
$attachment = $lot->getStorageLocation()->getMasterPictureAttachment();
if ($this->isAttachmentValidPicture($attachment)) {
$list[] = $attachment;
@ -79,14 +75,14 @@ class PartPreviewGenerator
}
}
if ($part->getPartUnit() !== null) {
if (null !== $part->getPartUnit()) {
$attachment = $part->getPartUnit()->getMasterPictureAttachment();
if ($this->isAttachmentValidPicture($attachment)) {
$list[] = $attachment;
}
}
if ($part->getManufacturer() !== null) {
if (null !== $part->getManufacturer()) {
$attachment = $part->getManufacturer()->getMasterPictureAttachment();
if ($this->isAttachmentValidPicture($attachment)) {
$list[] = $attachment;
@ -99,10 +95,12 @@ class PartPreviewGenerator
/**
* Determines what attachment should be used for previewing a part (especially in part table).
* The returned attachment is guaranteed to be existing and be a picture.
*
* @param Part $part The part for which the attachment should be determined
*
* @return Attachment|null
*/
public function getTablePreviewAttachment(Part $part) : ?Attachment
public function getTablePreviewAttachment(Part $part): ?Attachment
{
//First of all we check if the master attachment of the part is set (and a picture)
$attachment = $part->getMasterPictureAttachment();
@ -111,7 +109,7 @@ class PartPreviewGenerator
}
//Otherwise check if the part has a footprint with a valid masterattachment
if ($part->getFootprint() !== null) {
if (null !== $part->getFootprint()) {
$attachment = $part->getFootprint()->getMasterPictureAttachment();
if ($this->isAttachmentValidPicture($attachment)) {
return $attachment;
@ -124,13 +122,15 @@ class PartPreviewGenerator
/**
* Checks if a attachment is exising and a valid picture.
*
* @param Attachment|null $attachment The attachment that should be checked.
*
* @return bool True if the attachment is valid.
*/
protected function isAttachmentValidPicture(?Attachment $attachment) : bool
protected function isAttachmentValidPicture(?Attachment $attachment): bool
{
return $attachment !== null
return null !== $attachment
&& $attachment->isPicture()
&& $this->attachmentHelper->isFileExisting($attachment);
}
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,12 +17,10 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services;
use App\Entity\Attachments\Attachment;
use App\Entity\Attachments\AttachmentType;
use App\Entity\Base\DBElement;
@ -42,7 +40,6 @@ use App\Entity\UserSystem\Group;
use App\Entity\UserSystem\User;
use App\Exceptions\EntityNotSupportedException;
use Proxies\__CG__\App\Entity\Parts\Supplier;
use Symfony\Component\Form\CallbackTransformer;
use Symfony\Contracts\Translation\TranslatorInterface;
class ElementTypeNameGenerator
@ -80,15 +77,18 @@ class ElementTypeNameGenerator
* A part element becomes "Part" ("Bauteil" in german) and a category object becomes "Category".
* Useful when the type should be shown to user.
* Throws an exception if the class is not supported.
*
* @param DBElement $entity The element for which the label should be generated
*
* @return string The locatlized label for the entity type.
*
* @throws EntityNotSupportedException When the passed entity is not supported.
*/
public function getLocalizedTypeLabel(DBElement $entity) : string
public function getLocalizedTypeLabel(DBElement $entity): string
{
//Check if we have an direct array entry for our entity class, then we can use it
if (isset($this->mapping[get_class($entity)])) {
return $this->mapping[get_class($entity)];
if (isset($this->mapping[\get_class($entity)])) {
return $this->mapping[\get_class($entity)];
}
//Otherwise iterate over array and check for inheritance (needed when the proxy element from doctrine are passed)
@ -99,25 +99,26 @@ class ElementTypeNameGenerator
}
//When nothing was found throw an exception
throw new EntityNotSupportedException(
sprintf('No localized label for the element with type %s was found!', get_class($entity))
);
throw new EntityNotSupportedException(sprintf('No localized label for the element with type %s was found!', \get_class($entity)));
}
/**
* Returns a string like in the format ElementType: ElementName.
* For example this could be something like: "Part: BC547".
* It uses getLocalizedLabel to determine the type.
* @param NamedDBElement $entity The entity for which the string should be generated.
* @param bool $use_html If set to true, a html string is returned, where the type is set italic
*
* @param NamedDBElement $entity The entity for which the string should be generated.
* @param bool $use_html If set to true, a html string is returned, where the type is set italic
*
* @return string The localized string
*/
public function getTypeNameCombination(NamedDBElement $entity, bool $use_html = false) : string
public function getTypeNameCombination(NamedDBElement $entity, bool $use_html = false): string
{
$type = $this->getLocalizedTypeLabel($entity);
if ($use_html) {
return '<i>' . $type . ':</i> ' . $entity->getName();
return '<i>'.$type.':</i> '.$entity->getName();
}
return $type . ": " . htmlspecialchars($entity->getName());
return $type.': '.htmlspecialchars($entity->getName());
}
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,12 +17,10 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services;
use App\Entity\Base\NamedDBElement;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@ -31,7 +29,6 @@ use Symfony\Component\Serializer\SerializerInterface;
/**
* Use this class to export an entity to multiple file formats.
* @package App\Services
*/
class EntityExporter
{
@ -47,21 +44,23 @@ class EntityExporter
*
* @param $entity NamedDBElement|NamedDBElement[] The element/elements[] that should be exported
* @param Request $request The request that should be used for option resolving.
*
* @return Response The generated response containing the exported data.
*
* @throws \ReflectionException
*/
public function exportEntityFromRequest($entity, Request $request) : Response
public function exportEntityFromRequest($entity, Request $request): Response
{
$format = $request->get('format') ?? "json";
$format = $request->get('format') ?? 'json';
//Check if we have one of the supported formats
if (!in_array($format, ['json', 'csv', 'yaml', 'xml'])) {
throw new \InvalidArgumentException("Given format is not supported!");
if (!\in_array($format, ['json', 'csv', 'yaml', 'xml'])) {
throw new \InvalidArgumentException('Given format is not supported!');
}
//Check export verbosity level
$level = $request->get('level') ?? 'extended';
if (!in_array($level, ['simple', 'extended', 'full'])) {
if (!\in_array($level, ['simple', 'extended', 'full'])) {
throw new \InvalidArgumentException('Given level is not supported!');
}
@ -69,26 +68,26 @@ class EntityExporter
$include_children = $request->get('include_children') ?? false;
//Check which groups we need to export, based on level and include_children
$groups = array($level);
$groups = [$level];
if ($include_children) {
$groups[] = 'include_children';
}
//Plain text should work for all types
$content_type = "text/plain";
$content_type = 'text/plain';
//Try to use better content types based on the format
switch ($format) {
case 'xml':
$content_type = "application/xml";
$content_type = 'application/xml';
break;
case 'json':
$content_type = "application/json";
$content_type = 'application/json';
break;
}
//Ensure that we always serialize an array. This makes it easier to import the data again.
if(is_array($entity)) {
if (\is_array($entity)) {
$entity_array = $entity;
} else {
$entity_array = [$entity];
@ -99,7 +98,7 @@ class EntityExporter
'groups' => $groups,
'as_collection' => true,
'csv_delimiter' => ';', //Better for Excel
'xml_root_node_name' => 'PartDBExport'
'xml_root_node_name' => 'PartDBExport',
]));
$response->headers->set('Content-Type', $content_type);
@ -108,7 +107,7 @@ class EntityExporter
if (!$request->get('view')) {
if ($entity instanceof NamedDBElement) {
$entity_name = $entity->getName();
} elseif (is_array($entity)) {
} elseif (\is_array($entity)) {
if (empty($entity)) {
throw new \InvalidArgumentException('$entity must not be empty!');
}
@ -120,8 +119,7 @@ class EntityExporter
throw new \InvalidArgumentException('$entity type is not supported!');
}
$filename = "export_" . $entity_name . "_" . $level . "." . $format;
$filename = 'export_'.$entity_name.'_'.$level.'.'.$format;
// Create the disposition of the file
$disposition = $response->headers->makeDisposition(
@ -134,4 +132,4 @@ class EntityExporter
return $response;
}
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,16 +17,12 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services;
use App\Entity\Base\NamedDBElement;
use App\Entity\Base\StructuralDBElement;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\MakerBundle\Str;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Serializer\SerializerInterface;
@ -34,7 +30,6 @@ use Symfony\Component\Validator\Validator\ValidatorInterface;
class EntityImporter
{
protected $serializer;
protected $em;
protected $validator;
@ -53,25 +48,26 @@ class EntityImporter
'format' => 'json',
'preserve_children' => true,
'parent' => null,
'abort_on_validation_error' => true
'abort_on_validation_error' => true,
]);
}
/**
* Creates many entries at once, based on a (text) list of names.
*
* @param string $lines The list of names seperated by \n
* @param string $class_name The name of the class for which the entities should be created
* @param StructuralDBElement|null $parent The element which will be used as parent element for new elements.
* @param string $lines The list of names seperated by \n
* @param string $class_name The name of the class for which the entities should be created
* @param StructuralDBElement|null $parent The element which will be used as parent element for new elements.
*
* @return array An associative array containing an ConstraintViolationList and the entity name as key are returned,
* if an error happened during validation. When everything was successfull, the array should be empty.
* if an error happened during validation. When everything was successfull, the array should be empty.
*/
public function massCreation(string $lines, string $class_name, ?StructuralDBElement $parent) : array
public function massCreation(string $lines, string $class_name, ?StructuralDBElement $parent): array
{
//Expand every line to a single entry:
$names = explode("\n", $lines);
$errors = array();
$errors = [];
foreach ($names as $name) {
$name = trim($name);
@ -84,7 +80,7 @@ class EntityImporter
//Validate entity
$tmp = $this->validator->validate($entity);
//If no error occured, write entry to DB:
if (count($tmp) === 0) {
if (0 === \count($tmp)) {
$this->em->persist($entity);
} else { //Otherwise log error
dump($tmp);
@ -101,27 +97,28 @@ class EntityImporter
/**
* This methods deserializes the given file and saves it database.
* The imported elements will be checked (validated) before written to database.
* @param File $file The file that should be used for importing.
*
* @param File $file The file that should be used for importing.
* @param string $class_name The class name of the enitity that should be imported.
* @param array $options Options for the import process.
* @param array $options Options for the import process.
*
* @return array An associative array containing an ConstraintViolationList and the entity name as key are returned,
* if an error happened during validation. When everything was successfull, the array should be empty.
* if an error happened during validation. When everything was successfull, the array should be empty.
*/
public function fileToDBEntities(File $file, string $class_name, array $options = []) : array
public function fileToDBEntities(File $file, string $class_name, array $options = []): array
{
$resolver = new OptionsResolver();
$this->configureOptions($resolver);
$options = $resolver->resolve($options);
$entities = $this->fileToEntityArray($file, $class_name, $options);
$errors = array();
$errors = [];
//Iterate over each $entity write it to DB.
foreach ($entities as $entity) {
/** @var StructuralDBElement $entity */
/* @var StructuralDBElement $entity */
//Move every imported entity to the selected parent
$entity->setParent($options['parent']);
@ -129,7 +126,7 @@ class EntityImporter
$tmp = $this->validator->validate($entity);
//When no validation error occured, persist entity to database (cascade must be set in entity)
if (count($errors) === 0) {
if (0 === \count($errors)) {
$this->em->persist($entity);
} else { //Log validation errors to global log.
$errors[$entity->getFullPath()] = $tmp;
@ -137,7 +134,7 @@ class EntityImporter
}
//Save changes to database, when no error happened, or we should continue on error.
if (empty($errors) || $options['abort_on_validation_error'] == false) {
if (empty($errors) || false == $options['abort_on_validation_error']) {
$this->em->flush();
}
@ -148,12 +145,14 @@ class EntityImporter
* This method converts (deserialize) a (uploaded) file to an array of entities with the given class.
*
* The imported elements will NOT be validated. If you want to use the result array, you have to validate it by yourself.
* @param File $file The file that should be used for importing.
*
* @param File $file The file that should be used for importing.
* @param string $class_name The class name of the enitity that should be imported.
* @param array $options Options for the import process.
* @param array $options Options for the import process.
*
* @return array An array containing the deserialized elements.
*/
public function fileToEntityArray(File $file, string $class_name, array $options = []) : array
public function fileToEntityArray(File $file, string $class_name, array $options = []): array
{
$resolver = new OptionsResolver();
$this->configureOptions($resolver);
@ -170,11 +169,11 @@ class EntityImporter
}
//The [] behind class_name denotes that we expect an array.
$entities = $this->serializer->deserialize($content, $class_name . '[]', $options['format'],
$entities = $this->serializer->deserialize($content, $class_name.'[]', $options['format'],
['groups' => $groups, 'csv_delimiter' => $options['csv_separator']]);
//Ensure we have an array of entitity elements.
if(!is_array($entities)) {
if (!\is_array($entities)) {
$entities = [$entities];
}
@ -188,16 +187,17 @@ class EntityImporter
/**
* This functions corrects the parent setting based on the children value of the parent.
*
* @param iterable $entities The list of entities that should be fixed.
* @param null $parent The parent, to which the entity should be set.
* @param null $parent The parent, to which the entity should be set.
*/
protected function correctParentEntites(iterable $entities, $parent = null)
{
foreach ($entities as $entity) {
/** @var $entity StructuralDBElement */
/* @var $entity StructuralDBElement */
$entity->setParent($parent);
//Do the same for the children of entity
$this->correctParentEntites($entity->getChildren(), $entity);
}
}
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,7 +17,6 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services;
@ -25,11 +24,10 @@ namespace App\Services;
use App\Entity\Attachments\Attachment;
use App\Entity\Attachments\AttachmentType;
use App\Entity\Base\DBElement;
use App\Entity\Parts\Category;
use App\Entity\Devices\Device;
use App\Entity\Parts\Category;
use App\Entity\Parts\Footprint;
use App\Entity\Parts\Manufacturer;
use App\Entity\Base\NamedDBElement;
use App\Entity\Parts\MeasurementUnit;
use App\Entity\Parts\Part;
use App\Entity\Parts\Storelocation;
@ -39,14 +37,12 @@ use App\Entity\UserSystem\Group;
use App\Entity\UserSystem\User;
use App\Exceptions\EntityNotSupportedException;
use App\Services\Attachments\AttachmentURLGenerator;
use Symfony\Component\HttpKernel\HttpCache\Store;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
/**
* This service can be used to generate links to controllers for different aspects of an entity
* (like info, edit, delete, etc.)
* Useful for Twig, where you can generate a link to an entity using a filter.
* @package App\Services
*/
class EntityURLGenerator
{
@ -65,17 +61,20 @@ class EntityURLGenerator
/**
* Finds the controller name for the class of the entity using the given map.
* Throws an exception if the entity class is not known to the map.
*
* @param array $map The map that should be used for determing the controller
* @param $entity mixed The entity for which the controller name should be determined.
*
* @return string The name of the controller fitting the entity class
*
* @throws EntityNotSupportedException
*/
protected function mapToController(array $map, $entity): string
{
$class = get_class($entity);
$class = \get_class($entity);
//Check if we have an direct mapping for the given class
if (!array_key_exists($class, $map)) {
if (!\array_key_exists($class, $map)) {
//Check if we need to check inheritance by looping through our map
foreach ($map as $key => $value) {
if (is_a($entity, $key)) {
@ -83,10 +82,7 @@ class EntityURLGenerator
}
}
throw new EntityNotSupportedException(sprintf(
'The given entity is not supported yet! Passed class type: %s',
get_class($entity)
));
throw new EntityNotSupportedException(sprintf('The given entity is not supported yet! Passed class type: %s', \get_class($entity)));
}
return $map[$class];
@ -99,9 +95,11 @@ class EntityURLGenerator
*
* @param $entity mixed The element for which the page should be generated.
* @param string $type The page type. Currently supported: 'info', 'edit', 'create', 'clone', 'list'/'list_parts'
*
* @return string The link to the desired page.
*
* @throws EntityNotSupportedException Thrown if the entity is not supported for the given type.
* @throws \InvalidArgumentException Thrown if the givent type is not existing.
* @throws \InvalidArgumentException Thrown if the givent type is not existing.
*/
public function getURL($entity, string $type)
{
@ -148,21 +146,21 @@ class EntityURLGenerator
if ($entity->isExternal()) { //For external attachments, return the link to external path
return $entity->getURL();
}
return $this->attachmentURLGenerator->getDownloadURL($entity);
}
//Otherwise throw an error
throw new EntityNotSupportedException(sprintf(
'The given entity is not supported yet! Passed class type: %s',
get_class($entity)
));
throw new EntityNotSupportedException(sprintf('The given entity is not supported yet! Passed class type: %s', \get_class($entity)));
}
/**
* Generates an URL to a page, where info about this entity can be viewed.
*
* @param $entity mixed The entity for which the info should be generated.
*
* @return string The URL to the info page
*
* @throws EntityNotSupportedException If the method is not supported for the given Entity
*/
public function infoURL(DBElement $entity): string
@ -181,7 +179,7 @@ class EntityURLGenerator
User::class => 'user_edit',
Currency::class => 'currency_edit',
MeasurementUnit::class => 'measurement_unit_edit',
Group::class => 'group_edit'
Group::class => 'group_edit',
];
return $this->urlGenerator->generate($this->mapToController($map, $entity), ['id' => $entity->getID()]);
@ -191,7 +189,9 @@ class EntityURLGenerator
* Generates an URL to a page, where this entity can be edited.
*
* @param $entity mixed The entity for which the edit link should be generated.
*
* @return string The URL to the edit page.
*
* @throws EntityNotSupportedException If the method is not supported for the given Entity
*/
public function editURL($entity): string
@ -208,7 +208,7 @@ class EntityURLGenerator
User::class => 'user_edit',
Currency::class => 'currency_edit',
MeasurementUnit::class => 'measurement_unit_edit',
Group::class => 'group_edit'
Group::class => 'group_edit',
];
return $this->urlGenerator->generate($this->mapToController($map, $entity), ['id' => $entity->getID()]);
@ -218,7 +218,9 @@ class EntityURLGenerator
* Generates an URL to a page, where a entity of this type can be created.
*
* @param $entity mixed The entity for which the link should be generated.
*
* @return string The URL to the page.
*
* @throws EntityNotSupportedException If the method is not supported for the given Entity
*/
public function createURL($entity): string
@ -235,7 +237,7 @@ class EntityURLGenerator
User::class => 'user_new',
Currency::class => 'currency_new',
MeasurementUnit::class => 'measurement_unit_new',
Group::class => 'group_new'
Group::class => 'group_new',
];
return $this->urlGenerator->generate($this->mapToController($map, $entity));
@ -243,16 +245,18 @@ class EntityURLGenerator
/**
* Generates an URL to a page, where a new entity can be created, that has the same informations as the
* given entity (element cloning)
* given entity (element cloning).
*
* @param $entity mixed The entity for which the link should be generated.
*
* @return string The URL to the page.
*
* @throws EntityNotSupportedException If the method is not supported for the given Entity
*/
public function cloneURL(DBElement $entity): string
{
$map = [
Part::class => 'part_clone'
Part::class => 'part_clone',
];
return $this->urlGenerator->generate($this->mapToController($map, $entity), ['id' => $entity->getID()]);
@ -262,7 +266,9 @@ class EntityURLGenerator
* Generates an URL to a page, where all parts are listed, which are contained in the given element.
*
* @param $entity mixed The entity for which the link should be generated.
*
* @return string The URL to the page.
*
* @throws EntityNotSupportedException If the method is not supported for the given Entity
*/
public function listPartsURL(DBElement $entity): string
@ -272,7 +278,7 @@ class EntityURLGenerator
Footprint::class => 'part_list_footprint',
Manufacturer::class => 'part_list_manufacturer',
Supplier::class => 'part_list_supplier',
Storelocation::class => 'part_list_store_location'
Storelocation::class => 'part_list_store_location',
];
return $this->urlGenerator->generate($this->mapToController($map, $entity), ['id' => $entity->getID()]);
@ -292,7 +298,7 @@ class EntityURLGenerator
User::class => 'user_delete',
Currency::class => 'currency_delete',
MeasurementUnit::class => 'measurement_unit_delete',
Group::class => 'group_delete'
Group::class => 'group_delete',
];
return $this->urlGenerator->generate($this->mapToController($map, $entity), ['id' => $entity->getID()]);

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,12 +17,10 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services;
use Symfony\Component\HttpKernel\KernelInterface;
class GitVersionInfo
@ -35,33 +33,41 @@ class GitVersionInfo
}
/**
* Get the Git branch name of the installed system
* @return string|null The current git branch name. Null, if this is no Git installation
* Get the Git branch name of the installed system.
*
* @return string|null The current git branch name. Null, if this is no Git installation
*/
public function getGitBranchName()
{
if (file_exists($this->project_dir . '/.git/HEAD')) {
$git = file($this->project_dir . '/.git/HEAD');
if (file_exists($this->project_dir.'/.git/HEAD')) {
$git = file($this->project_dir.'/.git/HEAD');
$head = explode('/', $git[0], 3);
return trim($head[2]);
}
return null; // this is not a Git installation
}
/**
* Get hash of the last git commit (on remote "origin"!)
* Get hash of the last git commit (on remote "origin"!).
*
* @note If this method does not work, try to make a "git pull" first!
* @param integer $length if this is smaller than 40, only the first $length characters will be returned
* @return string|null The hash of the last commit, null If this is no Git installation
*
* @param int $length if this is smaller than 40, only the first $length characters will be returned
*
* @return string|null The hash of the last commit, null If this is no Git installation
*/
public function getGitCommitHash(int $length = 7)
{
$filename = $this->project_dir . '/.git/refs/remotes/origin/' . $this->getGitBranchName();
$filename = $this->project_dir.'/.git/refs/remotes/origin/'.$this->getGitBranchName();
if (file_exists($filename)) {
$head = file($filename);
$hash = $head[0];
return substr($hash, 0, $length);
}
return null; // this is not a Git installation
}
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,7 +17,6 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services;
@ -26,7 +25,6 @@ use Symfony\Contracts\Translation\TranslatorInterface;
/**
* This class allows you to convert markdown text to HTML.
* @package App\Services
*/
class MarkdownParser
{
@ -39,12 +37,14 @@ class MarkdownParser
/**
* Mark the markdown for rendering.
* The rendering of markdown is done on client side
* @param string $markdown The markdown text that should be parsed to html.
* @param bool $inline_mode Only allow inline markdown codes like (*bold* or **italic**), not something like tables
* The rendering of markdown is done on client side.
*
* @param string $markdown The markdown text that should be parsed to html.
* @param bool $inline_mode Only allow inline markdown codes like (*bold* or **italic**), not something like tables
*
* @return string The markdown in a version that can be parsed on client side.
*/
public function markForRendering(string $markdown, bool $inline_mode = false) : string
public function markForRendering(string $markdown, bool $inline_mode = false): string
{
return sprintf(
'<div class="markdown" data-markdown="%s">%s</div>',
@ -52,4 +52,4 @@ class MarkdownParser
$this->translator->trans('markdown.loading')
);
}
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,18 +17,15 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services;
use App\Entity\PriceInformations\Currency;
use Locale;
class MoneyFormatter
{
protected $base_currency;
protected $locale;
@ -39,17 +36,19 @@ class MoneyFormatter
}
/**
* Format the the given value in the given currency
* @param string|float $value The value that should be formatted.
* @param Currency|null $currency The currency that should be used for formatting. If null the global one is used
* @param int $decimals The number of decimals that should be shown.
* @param bool $show_all_digits If set to true, all digits are shown, even if they are null.
* Format the the given value in the given currency.
*
* @param string|float $value The value that should be formatted.
* @param Currency|null $currency The currency that should be used for formatting. If null the global one is used
* @param int $decimals The number of decimals that should be shown.
* @param bool $show_all_digits If set to true, all digits are shown, even if they are null.
*
* @return string
*/
public function format($value, ?Currency $currency = null, $decimals = 5, bool $show_all_digits = false)
{
$iso_code = $this->base_currency;
if ($currency !== null && !empty($currency->getIsoCode())) {
if (null !== $currency && !empty($currency->getIsoCode())) {
$iso_code = $currency->getIsoCode();
}
@ -62,5 +61,4 @@ class MoneyFormatter
return $number_formatter->formatCurrency((float) $value, $iso_code);
}
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,7 +17,6 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services;
@ -41,8 +40,6 @@ class PermissionResolver
/**
* PermissionResolver constructor.
*
* @param ParameterBagInterface $params
*/
public function __construct(ParameterBagInterface $params, ContainerInterface $container)
{
@ -51,21 +48,18 @@ class PermissionResolver
$this->cache_file = $cache_dir.'/permissions.php.cache';
$this->is_debug = $container->getParameter('kernel.debug');
$this->permission_structure = $this->generatePermissionStructure();
//dump($this->permission_structure);
}
public function getPermissionStructure() : array
public function getPermissionStructure(): array
{
return $this->permission_structure;
}
protected function generatePermissionStructure()
{
$cache = new ConfigCache($this->cache_file, $this->is_debug);
//Check if the cache is fresh, else regenerate it.
@ -88,7 +82,7 @@ class PermissionResolver
);
//Permission file is our file resource (it is used to invalidate cache)
$resources = array();
$resources = [];
$resources[] = new FileResource($permission_file);
//Var export the structure and write it to cache file.
@ -101,7 +95,6 @@ class PermissionResolver
return require $this->cache_file;
}
/**
* Check if a user/group is allowed to do the specified operation for the permission.
*
@ -165,13 +158,14 @@ class PermissionResolver
}
/**
* Sets the new value for the operation
* @param HasPermissionsInterface $user The user or group for which the value should be changed.
* @param string $permission The name of the permission that should be changed.
* @param string $operation The name of the operation that should be changed.
* @param bool|null $new_val The new value for the permission. true = ALLOW, false = DISALLOW, null = INHERIT
* Sets the new value for the operation.
*
* @param HasPermissionsInterface $user The user or group for which the value should be changed.
* @param string $permission The name of the permission that should be changed.
* @param string $operation The name of the operation that should be changed.
* @param bool|null $new_val The new value for the permission. true = ALLOW, false = DISALLOW, null = INHERIT
*/
public function setPermission(HasPermissionsInterface $user, string $permission, string $operation, ?bool $new_val) : void
public function setPermission(HasPermissionsInterface $user, string $permission, string $operation, ?bool $new_val): void
{
//Get the permissions from the user
$perm_list = $user->getPermissions();
@ -195,12 +189,11 @@ class PermissionResolver
*/
public function listOperationsForPermission(string $permission): array
{
if(!$this->isValidPermission($permission)) {
if (!$this->isValidPermission($permission)) {
throw new \InvalidArgumentException(sprintf('A permission with that name is not existing! Got %s.', $permission));
}
$operations = $this->permission_structure['perms'][$permission]['operations'];
return array_keys($operations);
}

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,7 +17,6 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services;
@ -25,7 +24,6 @@ namespace App\Services;
use App\Entity\Parts\Part;
use App\Entity\PriceInformations\Currency;
use App\Entity\PriceInformations\Pricedetail;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\PersistentCollection;
use Locale;
@ -43,10 +41,10 @@ class PricedetailHelper
/**
* Determines the highest amount, for which you get additional discount.
* This function determines the highest min_discount_quantity for the given part.
* @param Part $part
*
* @return float|null
*/
public function getMaxDiscountAmount(Part $part) : ?float
public function getMaxDiscountAmount(Part $part): ?float
{
$orderdetails = $part->getOrderdetails(true);
@ -55,7 +53,7 @@ class PricedetailHelper
foreach ($orderdetails as $orderdetail) {
$pricedetails = $orderdetail->getPricedetails();
//The orderdetail must have pricedetails, otherwise this will not work!
if (count($pricedetails) === 0) {
if (0 === \count($pricedetails)) {
continue;
}
@ -74,7 +72,6 @@ class PricedetailHelper
$max_amount = end($array);
}
if ($max_amount > $max) {
$max = $max_amount;
}
@ -88,11 +85,13 @@ class PricedetailHelper
}
/**
* Determines the minimum amount of the part that can be ordered
* Determines the minimum amount of the part that can be ordered.
*
* @param Part $part The part for which the minimum order amount should be determined.
*
* @return float
*/
public function getMinOrderAmount(Part $part) : ?float
public function getMinOrderAmount(Part $part): ?float
{
$orderdetails = $part->getOrderdetails(true);
@ -101,7 +100,7 @@ class PricedetailHelper
foreach ($orderdetails as $orderdetail) {
$pricedetails = $orderdetail->getPricedetails();
//The orderdetail must have pricedetails, otherwise this will not work!
if (count($pricedetails) === 0) {
if (0 === \count($pricedetails)) {
continue;
}
@ -123,26 +122,28 @@ class PricedetailHelper
/**
* Calculates the average price of a part, when ordering the amount $amount.
* @param Part $part The part for which the average price should be calculated.
* @param float $amount The order amount for which the average price should be calculated.
* If set to null, the mininmum order amount for the part is used.
*
* @param Part $part The part for which the average price should be calculated.
* @param float $amount The order amount for which the average price should be calculated.
* If set to null, the mininmum order amount for the part is used.
* @param Currency|null $currency The currency in which the average price should be calculated
*
* @return string|null The Average price as bcmath string. Returns null, if it was not possible to calculate the
* price for the given
* price for the given
*/
public function calculateAvgPrice(Part $part, ?float $amount = null, ?Currency $currency = null) : ?string
public function calculateAvgPrice(Part $part, ?float $amount = null, ?Currency $currency = null): ?string
{
if ($amount === null) {
if (null === $amount) {
$amount = $this->getMinOrderAmount($part);
}
if ($amount === null) {
if (null === $amount) {
return null;
}
$orderdetails = $part->getOrderdetails(true);
$avg = "0";
$avg = '0';
$count = 0;
//Find the price for the amount, for the given
@ -150,15 +151,15 @@ class PricedetailHelper
$pricedetail = $orderdetail->findPriceForQty($amount);
//When we dont have informations about this amount, ignore it
if ($pricedetail === null) {
if (null === $pricedetail) {
continue;
}
$avg = bcadd($avg, $this->convertMoneyToCurrency($pricedetail->getPricePerUnit(), $pricedetail->getCurrency(), $currency), Pricedetail::PRICE_PRECISION);
$count++;
++$count;
}
if ($count === 0) {
if (0 === $count) {
return null;
}
@ -166,16 +167,18 @@ class PricedetailHelper
}
/**
* Converts the given value in origin currency to the choosen target currency
* Converts the given value in origin currency to the choosen target currency.
*
* @param $value float|string The value that should be converted
* @param Currency|null $originCurrency The currency the $value is given in.
* Set to null, to use global base currency.
* Set to null, to use global base currency.
* @param Currency|null $targetCurrency The target currency, to which $value should be converted.
* Set to null, to use global base currency.
* Set to null, to use global base currency.
*
* @return string|null The value in $targetCurrency given as bcmath string.
* Returns null, if it was not possible to convert between both values (e.g. when the exchange rates are missing)
* Returns null, if it was not possible to convert between both values (e.g. when the exchange rates are missing)
*/
public function convertMoneyToCurrency($value, ?Currency $originCurrency = null, ?Currency $targetCurrency = null) : ?string
public function convertMoneyToCurrency($value, ?Currency $originCurrency = null, ?Currency $targetCurrency = null): ?string
{
//Skip conversion, if both currencies are same
if ($originCurrency === $targetCurrency) {
@ -186,9 +189,9 @@ class PricedetailHelper
//Convert value to base currency
$val_base = $value;
if ($originCurrency !== null) {
if (null !== $originCurrency) {
//Without an exchange rate we can not calculate the exchange rate
if ((float) $originCurrency->getExchangeRate() === 0) {
if (0 === (float) $originCurrency->getExchangeRate()) {
return null;
}
@ -197,9 +200,9 @@ class PricedetailHelper
//Convert value in base currency to target currency
$val_target = $val_base;
if ($targetCurrency !== null) {
if (null !== $targetCurrency) {
//Without an exchange rate we can not calculate the exchange rate
if ($targetCurrency->getExchangeRate() === null) {
if (null === $targetCurrency->getExchangeRate()) {
return null;
}
@ -208,4 +211,4 @@ class PricedetailHelper
return $val_target;
}
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,37 +17,39 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services;
/**
* A service that helps you to format values using the SI prefixes.
* @package App\Services
*/
class SIFormatter
{
/**
* Returns the magnitude of a value (the count of decimal place of the highest decimal place).
* For example, for 100 (=10^2) this function returns 2. For -2500 (=-2.5*10^3) this function returns 3.
*
* @param float $value The value of which the magnitude should be determined.
*
* @return int The magnitude of the value
*/
public function getMagnitude(float $value) : int
public function getMagnitude(float $value): int
{
return (int) floor(log10(abs($value)));
}
/**
* Returns the best SI prefix (and its corresponding divisor) for the given magnitude.
*
* @param int $magnitude The magnitude for which the prefix should be determined.
*
* @return array A array, containing the divisor in first element, and the prefix symbol in second. For example, [1000, "k"].
*/
public function getPrefixByMagnitude(int $magnitude) : array
public function getPrefixByMagnitude(int $magnitude): array
{
$prefixes_pos = ['' ,'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'];
$prefixes_neg = ['' ,'m', 'μ', 'n', 'p', 'f', 'a', 'z', 'y'];
$prefixes_pos = ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'];
$prefixes_neg = ['', 'm', 'μ', 'n', 'p', 'f', 'a', 'z', 'y'];
if ($magnitude >= 0) {
$nearest = (int) floor(abs($magnitude) / 3);
@ -65,43 +67,42 @@ class SIFormatter
}
/**
*
* @param float $value
* @return array
*/
public function convertValue(float $value) : array
public function convertValue(float $value): array
{
//Choose the prefix to use
$tmp = $this->getPrefixByMagnitude($this->getMagnitude($value));
$ret = array(
$ret = [
'value' => $value / $tmp[0],
'prefix_magnitude' => log10($tmp[0]),
'prefix' => $tmp[1]
);
'prefix' => $tmp[1],
];
return $ret;
}
/**
* Formats the given value to a string, using the given options
* @param float $value The value that should be converted
* @param string $unit The unit that should be appended after the prefix
* @param int $decimals The number of decimals (after decimal dot) that should be outputed.
* Formats the given value to a string, using the given options.
*
* @param float $value The value that should be converted
* @param string $unit The unit that should be appended after the prefix
* @param int $decimals The number of decimals (after decimal dot) that should be outputed.
*
* @return string
*/
public function format(float $value, string $unit = '', int $decimals = 2) : string
public function format(float $value, string $unit = '', int $decimals = 2): string
{
[$divisor, $symbol] = $this->getPrefixByMagnitude($this->getMagnitude($value));
$value /= $divisor;
//Build the format string, e.g.: %.2d km
if ($unit !== '' || $symbol !== '') {
$format_string = '%.' . $decimals . 'f ' . $symbol . $unit;
if ('' !== $unit || '' !== $symbol) {
$format_string = '%.'.$decimals.'f '.$symbol.$unit;
} else {
$format_string = '%.' . $decimals . 'f';
$format_string = '%.'.$decimals.'f';
}
return sprintf($format_string, $value);
}
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,18 +17,15 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services;
use App\Entity\Base\StructuralDBElement;
use Doctrine\ORM\EntityManagerInterface;
class StructuralElementRecursionHelper
{
protected $em;
public function __construct(EntityManagerInterface $em)
@ -39,18 +36,18 @@ class StructuralElementRecursionHelper
/**
* Executes an function (callable) recursivly for $element and every of its children.
*
* @param StructuralDBElement $element The element on which the func should be executed
* @param callable $func The function which should be executed for each element.
* $func has the signature function(StructuralDBElement $element) : void
* @param int $max_depth The maximum depth for which should be recursivly called. So if this is set to 5, after the
* 5th level the execution is stopped.
* @param bool $call_from_bottom If set to true the bottom elements (elements with high level) will be called first.
* Set to false if you want to call the top elements first.
* @param StructuralDBElement $element The element on which the func should be executed
* @param callable $func The function which should be executed for each element.
* $func has the signature function(StructuralDBElement $element) : void
* @param int $max_depth The maximum depth for which should be recursivly called. So if this is set to 5, after the
* 5th level the execution is stopped.
* @param bool $call_from_bottom If set to true the bottom elements (elements with high level) will be called first.
* Set to false if you want to call the top elements first.
*/
public function execute(StructuralDBElement $element, callable $func, int $max_depth = -1, $call_from_bottom = true) : void
public function execute(StructuralDBElement $element, callable $func, int $max_depth = -1, $call_from_bottom = true): void
{
//Cancel if we reached our maximal allowed level. Must be zero because -1 is infinity levels
if ($max_depth == 0) {
if (0 == $max_depth) {
return;
}
@ -74,20 +71,21 @@ class StructuralElementRecursionHelper
/**
* Deletes the $element and all its subelements recursivly.
*
* @param StructuralDBElement $element The element which should be deleted.
* @param bool $flush When set to true the changes will also be flushed to DB. Set to false if you want to flush
* later.
* @param bool $flush When set to true the changes will also be flushed to DB. Set to false if you want to flush
* later.
*/
public function delete(StructuralDBElement $element, bool $flush = true) : void
public function delete(StructuralDBElement $element, bool $flush = true): void
{
$em = $this->em;
$this->execute($element, static function(StructuralDBElement $element) use ($em) {
$this->execute($element, static function (StructuralDBElement $element) use ($em) {
$em->remove($element);
});
if($flush) {
if ($flush) {
$em->flush();
}
}
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,19 +17,16 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services;
use App\Entity\Parts\Part;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* A service related for searching for tags. Mostly useful for autocomplete reasons.
* @package App\Services
*/
class TagFinder
{
@ -45,20 +42,22 @@ class TagFinder
$resolver->setDefaults([
'query_limit' => 75,
'return_limit' => 25,
'min_keyword_length' => 3
'min_keyword_length' => 3,
]);
}
/**
* Search tags that begins with the certain keyword.
*
* @param string $keyword The keyword the tag must begin with
* @param array $options Some options specifying the search behavior. See configureOptions for possible options.
* @param array $options Some options specifying the search behavior. See configureOptions for possible options.
*
* @return string[] An array containing the tags that match the given keyword.
*/
public function searchTags(string $keyword, array $options = [])
{
$results = [];
$keyword_regex = '/^' . preg_quote($keyword, '/') . '/';
$keyword_regex = '/^'.preg_quote($keyword, '/').'/';
$resolver = new OptionsResolver();
$this->configureOptions($resolver);
@ -75,10 +74,10 @@ class TagFinder
$qb->select('p.tags')
->from(Part::class, 'p')
->where("p.tags LIKE ?1")
->where('p.tags LIKE ?1')
->setMaxResults($options['query_limit'])
//->orderBy('RAND()')
->setParameter(1, '%' . $keyword . '%');
->setParameter(1, '%'.$keyword.'%');
$possible_tags = $qb->getQuery()->getArrayResult();
@ -90,6 +89,6 @@ class TagFinder
$results = array_unique($results);
//Limit the returned tag count to specified value.
return array_slice($results, 0, $options['return_limit']);
return \array_slice($results, 0, $options['return_limit']);
}
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,7 +17,6 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services;
@ -45,11 +44,9 @@ use Symfony\Contracts\Translation\TranslatorInterface;
/**
* This Service generates the tree structure for the tools.
* Whenever you change something here, you has to clear the cache, because the results are cached for performance reasons.
* @package App\Services
*/
class ToolsTreeBuilder
{
protected $translator;
protected $urlGenerator;
protected $keyGenerator;
@ -73,31 +70,34 @@ class ToolsTreeBuilder
/**
* Generates the tree for the tools menu.
* The result is cached.
*
* @return TreeViewNode[] The array containing all Nodes for the tools menu.
*/
public function getTree() : array
public function getTree(): array
{
$key = "tree_tools_" . $this->keyGenerator->generateKey();
$key = 'tree_tools_'.$this->keyGenerator->generateKey();
return $this->cache->get($key, function (ItemInterface $item) {
//Invalidate tree, whenever group or the user changes
$item->tag(["tree_tools", "groups", $this->keyGenerator->generateKey()]);
$item->tag(['tree_tools', 'groups', $this->keyGenerator->generateKey()]);
$tree = array();
$tree = [];
$tree[] = new TreeViewNode($this->translator->trans('tree.tools.edit'), null, $this->getEditNodes());
$tree[] = new TreeViewNode($this->translator->trans('tree.tools.show'), null, $this->getShowNodes());
$tree[] = new TreeViewNode($this->translator->trans('tree.tools.system'), null, $this->getSystemNodes());
return $tree;
});
}
/**
* This functions creates a tree entries for the "edit" node of the tool's tree
* This functions creates a tree entries for the "edit" node of the tool's tree.
*
* @return TreeViewNode[]
*/
protected function getEditNodes() : array
protected function getEditNodes(): array
{
$nodes = array();
$nodes = [];
if ($this->security->isGranted('read', new AttachmentType())) {
$nodes[] = new TreeViewNode(
@ -164,12 +164,13 @@ class ToolsTreeBuilder
}
/**
* This function creates the tree entries for the "show" node of the tools tree
* This function creates the tree entries for the "show" node of the tools tree.
*
* @return TreeViewNode[]
*/
protected function getShowNodes() : array
protected function getShowNodes(): array
{
$show_nodes = array();
$show_nodes = [];
$show_nodes[] = new TreeViewNode(
$this->translator->trans('tree.tools.show.all_parts'),
$this->urlGenerator->generate('parts_show_all')
@ -187,16 +188,17 @@ class ToolsTreeBuilder
/**
* This function creates the tree entries for the "system" node of the tools tree.
*
* @return array
*/
protected function getSystemNodes() : array
protected function getSystemNodes(): array
{
$nodes = array();
$nodes = [];
if ($this->security->isGranted('read', new User())) {
$nodes[] = new TreeViewNode(
$this->translator->trans('tree.tools.system.users'),
$this->urlGenerator->generate("user_new")
$this->urlGenerator->generate('user_new')
);
}
if ($this->security->isGranted('read', new Group())) {

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,12 +17,10 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services\TranslationExtractor;
use App\Services\PermissionResolver;
use Symfony\Component\Translation\Extractor\ExtractorInterface;
use Symfony\Component\Translation\MessageCatalogue;
@ -30,7 +28,6 @@ use Symfony\Component\Translation\MessageCatalogue;
/**
* The purpose of this class is to extract label attributes out of our permissions.yaml structure,
* so they can be translated.
* @package App\Services\TranslationExtractor
*/
class PermissionExtractor implements ExtractorInterface
{
@ -45,7 +42,7 @@ class PermissionExtractor implements ExtractorInterface
/**
* Extracts translation messages from files, a file or a directory to the catalogue.
*
* @param string|array $resource Files, a file or a directory
* @param string|array $resource Files, a file or a directory
* @param MessageCatalogue $catalogue The catalogue
*/
public function extract($resource, MessageCatalogue $catalogue)
@ -55,7 +52,7 @@ class PermissionExtractor implements ExtractorInterface
foreach ($this->permission_structure['groups'] as $group) {
if (isset($group['label'])) {
$catalogue->add([
$group['label'] => '__' . $group['label']
$group['label'] => '__'.$group['label'],
]);
}
}
@ -64,7 +61,7 @@ class PermissionExtractor implements ExtractorInterface
foreach ($this->permission_structure['perms'] as $perm) {
if (isset($perm['label'])) {
$catalogue->add([
$perm['label'] => '__' . $perm['label']
$perm['label'] => '__'.$perm['label'],
]);
}
@ -72,13 +69,12 @@ class PermissionExtractor implements ExtractorInterface
foreach ($perm['operations'] as $op) {
if (isset($op['label'])) {
$catalogue->add([
$op['label'] => '__' . $op['label']
$op['label'] => '__'.$op['label'],
]);
}
}
}
$this->finished = true;
}
}
@ -92,4 +88,4 @@ class PermissionExtractor implements ExtractorInterface
{
return '';
}
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,7 +17,6 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services;
@ -28,22 +27,12 @@ use App\Entity\Base\StructuralDBElement;
use App\Helpers\TreeViewNode;
use App\Repository\StructuralDBElementRepository;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Bundle\MakerBundle\Str;
use Symfony\Component\Cache\Adapter\AdapterInterface;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
use Symfony\Component\Cache\Adapter\TagAwareAdapterInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;
use Symfony\Contracts\Cache\TagAwareCacheInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* This service gives you multiple possibilities to generate trees.
*
* @package App\Controller
*/
class TreeBuilder
{
@ -65,15 +54,18 @@ class TreeBuilder
/**
* Generates a tree for the given Element. The given element is the top node, all children are child nodes.
* @param StructuralDBElement $element The element for which the tree should be generated.
* @param string $href_type The type of the links that should be used for the links. Set to null, to disable links.
* See EntityURLGenerator::getURL for possible types.
* @param DBElement|null $selectedElement When a element is given here, its tree node will be marked as selected in
* the resulting tree. When $selectedElement is not existing in the tree, then nothing happens.
*
* @param StructuralDBElement $element The element for which the tree should be generated.
* @param string $href_type The type of the links that should be used for the links. Set to null, to disable links.
* See EntityURLGenerator::getURL for possible types.
* @param DBElement|null $selectedElement When a element is given here, its tree node will be marked as selected in
* the resulting tree. When $selectedElement is not existing in the tree, then nothing happens.
*
* @return TreeViewNode The Node for the given Element.
*
* @throws \App\Exceptions\EntityNotSupportedException
*/
public function elementToTreeNode(NamedDBElement $element, ?string $href_type = 'list_parts', DBElement $selectedElement = null) : TreeViewNode
public function elementToTreeNode(NamedDBElement $element, ?string $href_type = 'list_parts', DBElement $selectedElement = null): TreeViewNode
{
$children_nodes = null;
@ -93,12 +85,12 @@ class TreeBuilder
$tree_node = new TreeViewNode($element->__toString(), $href, $children_nodes);
if($children_nodes != null) {
$tree_node->addTag((string) count($children_nodes));
if (null != $children_nodes) {
$tree_node->addTag((string) \count($children_nodes));
}
//Check if we need to select the current part
if ($selectedElement !== null && $element->getID() === $selectedElement->getID()) {
if (null !== $selectedElement && $element->getID() === $selectedElement->getID()) {
$tree_node->setSelected(true);
}
@ -106,20 +98,23 @@ class TreeBuilder
}
/**
* Generates a tree for all elements of the given type
* @param StructuralDBElement $class_name The class name of the StructuralDBElement class for which the tree should
* be generated.
* @param string $href_type The type of the links that should be used for the links. Set to null, to disable links.
* See EntityURLGenerator::getURL for possible types.
* @param DBElement|null $selectedElement When a element is given here, its tree node will be marked as selected in
* the resulting tree. When $selectedElement is not existing in the tree, then nothing happens.
* Generates a tree for all elements of the given type.
*
* @param StructuralDBElement $class_name The class name of the StructuralDBElement class for which the tree should
* be generated.
* @param string $href_type The type of the links that should be used for the links. Set to null, to disable links.
* See EntityURLGenerator::getURL for possible types.
* @param DBElement|null $selectedElement When a element is given here, its tree node will be marked as selected in
* the resulting tree. When $selectedElement is not existing in the tree, then nothing happens.
*
* @return TreeViewNode[] Returns an array, containing all nodes. It is empty if the given class has no elements.
*
* @throws \App\Exceptions\EntityNotSupportedException
*/
public function typeToTree(string $class_name, ?string $href_type = 'list_parts', DBElement $selectedElement = null) : array
public function typeToTree(string $class_name, ?string $href_type = 'list_parts', DBElement $selectedElement = null): array
{
/**
* @var $repo StructuralDBElementRepository
* @var StructuralDBElementRepository
*/
$repo = $this->em->getRepository($class_name);
@ -129,15 +124,15 @@ class TreeBuilder
$root_nodes = $repo->findAll();
}
$array = array();
$array = [];
//When we use the newEdit type, add the New Element node.
if ($href_type === 'newEdit') {
if ('newEdit' === $href_type) {
//Generate the url for the new node
$href = $this->url_generator->createURL(new $class_name());
$new_node = new TreeViewNode($this->translator->trans('entity.tree.new'), $href);
//When the id of the selected element is null, then we have a new element, and we need to select "new" node
if ($selectedElement != null && $selectedElement->getID() == null) {
if (null != $selectedElement && null == $selectedElement->getID()) {
$new_node->setSelected(true);
}
$array[] = $new_node;
@ -145,7 +140,7 @@ class TreeBuilder
$array[] = (new TreeViewNode(''))->setDisabled(true);
//Every other treeNode will be used for edit
$href_type = "edit";
$href_type = 'edit';
}
foreach ($root_nodes as $node) {
@ -158,22 +153,24 @@ class TreeBuilder
/**
* Gets a flattened hierachical tree. Useful for generating option lists.
* In difference to the Repository Function, the results here are cached.
* @param string $class_name The class name of the entity you want to retrieve.
* @param StructuralDBElement|null $parent This entity will be used as root element. Set to null, to use global root
*
* @param string $class_name The class name of the entity you want to retrieve.
* @param StructuralDBElement|null $parent This entity will be used as root element. Set to null, to use global root
*
* @return StructuralDBElement[] A flattened list containing the tree elements.
*/
public function typeToNodesList(string $class_name, ?StructuralDBElement $parent = null): array
{
$parent_id = $parent != null ? $parent->getID() : "0";
$parent_id = null != $parent ? $parent->getID() : '0';
// Backslashes are not allowed in cache keys
$secure_class_name = str_replace("\\", '_', $class_name);
$key = "list_" . $this->keyGenerator->generateKey() . "_" . $secure_class_name . $parent_id;
$secure_class_name = str_replace('\\', '_', $class_name);
$key = 'list_'.$this->keyGenerator->generateKey().'_'.$secure_class_name.$parent_id;
$ret = $this->cache->get($key, function (ItemInterface $item) use ($class_name, $parent, $secure_class_name) {
// Invalidate when groups, a element with the class or the user changes
$item->tag(['groups', 'tree_list', $this->keyGenerator->generateKey(), $secure_class_name]);
/**
* @var $repo StructuralDBElementRepository
* @var StructuralDBElementRepository
*/
$repo = $this->em->getRepository($class_name);

View file

@ -1,6 +1,6 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony)
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
*
@ -17,21 +17,15 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Services;
use App\Entity\UserSystem\User;
use Nyholm\Psr7\Request;
use Symfony\Component\Intl\Locale\Locale;
use Symfony\Component\Intl\Locales;
use Symfony\Component\Security\Core\Security;
/**
* Purpose of this service is to generate a key unique for a user, to use in Cache keys and tags.
* @package App\Services
*/
class UserCacheKeyGenerator
{
@ -44,26 +38,28 @@ class UserCacheKeyGenerator
/**
* Generates a key for the given user.
*
* @param User|null $user The user for which the key should be generated. When set to null, the currently logged in
* user is used.
* user is used.
*
* @return string
*/
public function generateKey(User $user = null) : string
public function generateKey(User $user = null): string
{
$locale = \Locale::getDefault();
//If no user was specified, use the currently used one.
if ($user === null) {
if (null === $user) {
$user = $this->security->getUser();
}
//If the user is null, then treat it as anonymous user.
//When the anonymous user is passed as user then use this path too.
if ($user === null || $user->getID() === User::ID_ANONYMOUS) {
return 'user$_' . User::ID_ANONYMOUS;
if (null === $user || User::ID_ANONYMOUS === $user->getID()) {
return 'user$_'.User::ID_ANONYMOUS;
}
//In the most cases we can just use the username (its unique)
return "user_" . $user->getUsername() . '_' . $locale;
return 'user_'.$user->getUsername().'_'.$locale;
}
}
}