Moved extension to fa-icon logic to a service.

That way we can use it from inside PHP code and the logic is more testable.
This commit is contained in:
Jan Böhmer 2019-11-10 18:19:06 +01:00
parent bf8455fa42
commit 8b80f31b1e
5 changed files with 170 additions and 31 deletions

View file

@ -33,6 +33,7 @@ use App\Services\AmountFormatter;
use App\Services\Attachments\AttachmentURLGenerator;
use App\Services\Attachments\PartPreviewGenerator;
use App\Services\EntityURLGenerator;
use App\Services\FAIconGenerator;
use App\Services\TreeBuilder;
use Doctrine\ORM\QueryBuilder;
use Omines\DataTablesBundle\Adapter\Doctrine\ORM\SearchCriteriaProvider;
@ -58,7 +59,8 @@ class PartsDataTable implements DataTableTypeInterface
public function __construct(EntityURLGenerator $urlGenerator, TranslatorInterface $translator,
TreeBuilder $treeBuilder, AmountFormatter $amountFormatter,
PartPreviewGenerator $previewGenerator, AttachmentURLGenerator $attachmentURLGenerator)
PartPreviewGenerator $previewGenerator, AttachmentURLGenerator $attachmentURLGenerator,
FAIconGenerator $FAIconGenerator)
{
$this->urlGenerator = $urlGenerator;
$this->translator = $translator;

View file

@ -0,0 +1,88 @@
<?php
/**
* 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)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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;
class FAIconGenerator
{
protected const EXT_MAPPING = [
'fa-file-pdf' => ['pdf'],
'fa-file-image' => Attachment::PICTURE_EXTS,
'fa-file-alt' => ['txt', 'md', 'rtf', 'log', 'rst', 'tex'],
'fa-file-csv' => ['csv'],
'fa-file-word' => ['doc', 'docx', 'odt'],
'fa-file-archive' => ['zip', 'rar', 'bz2', 'tar', '7z', 'gz'],
'fa-file-audio' => ['mp3', 'wav', 'aac', 'm4a', 'wma'],
'fa-file-powerpoint' => ['ppt', 'pptx', 'odp', 'pps', 'key'],
'fa-file-excel' => ['xls', 'xlr', 'xlsx', 'ods'],
'fa-file-code' => ['php', 'xml', 'html', 'js', 'ts', 'htm', 'c', 'cpp'],
'fa-file-video' => ['webm', 'avi', 'mp4', 'mkv', 'wmv'],
];
/**
* Gets the Font awesome icon class for a file with the specified extension.
* For example 'pdf' gives you 'fa-file-pdf'
* @param string $extension The file extension (without dot). Must be ASCII chars only!
* @return string The fontawesome class with leading 'fa-'
*/
public function fileExtensionToFAType(string $extension) : string
{
if ($extension === '') {
throw new \InvalidArgumentException('You must specify an extension!');
}
//Normalize file extension
$extension = strtolower($extension);
foreach (self::EXT_MAPPING as $fa => $exts) {
if (in_array($extension, $exts, true)) {
return $fa;
}
}
// When the extension is not found in the mapping array, we return the generic icon
return 'fa-file';
}
/**
* Returns HTML code to show the given fontawesome icon.
* E.g. <i class="fas fa-file-text"></i>
* @param string $icon_class The icon which should be shown (e.g. fa-file-text)
* @param string $style The style of the icon 'fas'
* @param string $options Any other css class attributes like size, etc.
* @return string The final html
*/
public function generateIconHTML(string $icon_class, string $style = 'fas', string $options = '') : string
{
//XSS protection
$icon_class = htmlspecialchars($icon_class);
$style = htmlspecialchars($style);
$options = htmlspecialchars($options);
return sprintf(
'<i class="%s %s %s"></i>',
$style,
$icon_class,
$options
);
}
}

View file

@ -27,6 +27,7 @@ use App\Entity\PriceInformations\Currency;
use App\Services\AmountFormatter;
use App\Services\Attachments\AttachmentURLGenerator;
use App\Services\EntityURLGenerator;
use App\Services\FAIconGenerator;
use App\Services\MarkdownParser;
use App\Services\MoneyFormatter;
use App\Services\SIFormatter;
@ -47,12 +48,14 @@ class AppExtension extends AbstractExtension
protected $siformatter;
protected $amountFormatter;
protected $attachmentURLGenerator;
protected $FAIconGenerator;
public function __construct(EntityURLGenerator $entityURLGenerator, MarkdownParser $markdownParser,
SerializerInterface $serializer, TreeBuilder $treeBuilder,
MoneyFormatter $moneyFormatter,
SIFormatter $SIFormatter, AmountFormatter $amountFormatter,
AttachmentURLGenerator $attachmentURLGenerator)
AttachmentURLGenerator $attachmentURLGenerator,
FAIconGenerator $FAIconGenerator)
{
$this->entityURLGenerator = $entityURLGenerator;
$this->markdownParser = $markdownParser;
@ -62,6 +65,7 @@ class AppExtension extends AbstractExtension
$this->siformatter = $SIFormatter;
$this->amountFormatter = $amountFormatter;
$this->attachmentURLGenerator = $attachmentURLGenerator;
$this->FAIconGenerator = $FAIconGenerator;
}
public function getFilters()
@ -90,6 +94,7 @@ class AppExtension extends AbstractExtension
return [
new TwigFunction('generateTreeData', [$this, 'treeData']),
new TwigFunction('attachment_thumbnail', [$this->attachmentURLGenerator, 'getThumbnailURL']),
new TwigFunction('ext_to_fa_icon', [$this->FAIconGenerator, 'fileExtensionToFAType']),
];
}

View file

@ -6,41 +6,13 @@
{% endif %}
{% endmacro %}
{% macro file_extension_to_fa_icon(ext) %}
{% if ext in ['jpeg', 'jpg', 'gif', 'png', 'tiff', 'tif', 'webp', 'bmp', 'svg'] %} {# Images #}
fa-file-image
{% elseif ext in ['pdf'] %} {# PDFs #}
fa-file-pdf
{% elseif ext in ['txt', 'md', 'rtf'] %} {# Text files #}
fa-file-alt
{% elseif ext in ['csv'] %} {# CSV files #}
fa-file-csv
{% elseif ext in ['doc', 'docx', 'odt'] %} {# Documents #}
fa-file-word
{% elseif ext in ['zip', 'rar', 'bz2', 'tar', '7z', 'gz'] %}
fa-file-archive
{% elseif ext in ['mp3', 'wav', 'aac', 'm4a', 'wma'] %}
fa-file-audio
{% elseif ext in ['ppt', 'pptx', 'odp'] %}
fa-file-powerpoint
{% elseif ext in ['xls', 'xlsx', 'ods'] %}
fa-file-excel
{% elseif ext in ['php', 'xml', 'html', 'js', 'ts', 'htm', 'c', 'cpp'] %}
fa-file-code
{% elseif ext in ['webm', 'avi', 'mp4', 'mkv', 'wmv'] %} {# Videos#}
fa-file-video
{% else %}
fa-file
{% endif %}
{% endmacro %}
{% macro attachment_icon(attachment, attachment_helper, class = "fa-fw fas fa-3x", link = true) %}
{% if not attachment_helper or attachment_helper.fileExisting(attachment) %}
<a target="_blank" data-no-ajax rel="noopener" href="{% if link %}{{ attachment|entityURL('file_view') }}{% endif %}">
{% if attachment.picture %}
<img class="hoverpic" src="{{ attachment|entityURL('file_view') }}">
{% else %}
<i class="text-dark {{ class }} {{ _self.file_extension_to_fa_icon(attachment.extension) }}"></i>
<i class="text-dark {{ class }} {{ ext_to_fa_icon(attachment.extension) }}"></i>
{% endif %}
</a>
{% elseif not attachment_helper.fileExisting(attachment) %}

View file

@ -0,0 +1,72 @@
<?php
/**
* 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)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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\Tests\Services;
use App\Services\FAIconGenerator;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class FAIconGeneratorTest extends WebTestCase
{
/**
* @var AmountFormatter
*/
protected $service;
public function setUp()
{
parent::setUp(); // TODO: Change the autogenerated stub
//Get an service instance.
self::bootKernel();
$this->service = self::$container->get(FAIconGenerator::class);
}
public function fileExtensionDataProvider() : array
{
return [
['pdf', 'fa-file-pdf'],
['jpeg', 'fa-file-image'],
['txt', 'fa-file-alt'],
['doc', 'fa-file-word'],
['zip', 'fa-file-archive'],
['php', 'fa-file-code'],
['tmp', 'fa-file'],
['fgd', 'fa-file'],
];
}
/**
* @dataProvider fileExtensionDataProvider
*/
public function testFileExtensionToFAType(string $ext, string $expected)
{
$this->assertEquals($expected, $this->service->fileExtensionToFAType($ext));
}
public function testGenerateIconHTML()
{
$this->assertEquals('<i class="fas fa-file "></i>', $this->service->generateIconHTML('fa-file'));
$this->assertEquals('<i class="far fa-file "></i>', $this->service->generateIconHTML('fa-file', 'far'));
$this->assertEquals('<i class="far fa-file fa-2x"></i>', $this->service->generateIconHTML('fa-file', 'far', 'fa-2x'));
}
}