Added basic label generation dialog.

This commit is contained in:
Jan Böhmer 2020-04-16 19:56:30 +02:00
parent ea0d72bfbb
commit a4e1a17b4a
12 changed files with 230 additions and 5 deletions

View file

@ -21,12 +21,21 @@
namespace App\Controller; namespace App\Controller;
use App\Entity\Base\AbstractDBElement;
use App\Entity\Contracts\NamedElementInterface;
use App\Entity\LabelSystem\LabelOptions;
use App\Entity\LabelSystem\LabelProfile; use App\Entity\LabelSystem\LabelProfile;
use App\Entity\Parts\Part; use App\Entity\Parts\Part;
use App\Form\LabelOptionsType;
use App\Form\LabelSystem\LabelDialogType;
use App\Helpers\LabelResponse; use App\Helpers\LabelResponse;
use App\Services\ElementTypeNameGenerator;
use App\Services\LabelSystem\LabelGenerator; use App\Services\LabelSystem\LabelGenerator;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\SubmitButton;
use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag; use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
@ -38,10 +47,14 @@ use Symfony\Component\Routing\Annotation\Route;
class LabelController extends AbstractController class LabelController extends AbstractController
{ {
protected $labelGenerator; protected $labelGenerator;
protected $em;
protected $elementTypeNameGenerator;
public function __construct(LabelGenerator $labelGenerator) public function __construct(LabelGenerator $labelGenerator, EntityManagerInterface $em, ElementTypeNameGenerator $elementTypeNameGenerator)
{ {
$this->labelGenerator = $labelGenerator; $this->labelGenerator = $labelGenerator;
$this->em = $em;
$this->elementTypeNameGenerator = $elementTypeNameGenerator;
} }
/** /**
@ -56,4 +69,68 @@ class LabelController extends AbstractController
return $response; return $response;
} }
/**
* @Route("/dialog", name="label_dialog")
* @Route("/{profile}/dialog")
*/
public function generator(Request $request, ?LabelProfile $profile = null)
{
if ($profile) {
$label_options = $profile->getOptions();
} else {
$label_options = new LabelOptions();
}
$form = $this->createForm(LabelDialogType::class);
//Try to parse given target_type and target_id
$target_type = $request->query->get('target_type', null);
$target_id = $request->query->get('target_id', null);
if ($profile === null && is_string($target_type)) {
$label_options->setSupportedElement($target_type);
}
if (is_numeric($target_id)) {
$form['target_id']->setData((int) $target_id);
}
$form['options']->setData($label_options);
$form->handleRequest($request);
/** @var LabelOptions $form_options */
$form_options = $form['options']->getData();
$pdf_data = null;
$filename = 'invalid.pdf';
if ($form->isSubmitted() && $form->isValid()) {
$target_id = (int) $form->get('target_id')->getData();
$target = $this->findObject($form_options->getSupportedElement(), $target_id);
$pdf_data = $this->labelGenerator->generateLabel($form_options, $target);
$filename = $this->getLabelName($target, $profile);
}
return $this->render('LabelSystem/dialog.html.twig', [
'form' => $form->createView(),
'pdf_data' => $pdf_data,
'filename' => $filename,
]);
}
protected function getLabelName(AbstractDBElement $element, ?LabelProfile $profile = null): string
{
$ret = 'label_' . $this->elementTypeNameGenerator->getLocalizedTypeLabel($element);
$ret .= $element->getID();
return $ret . '.pdf';
}
protected function findObject(string $type, int $id): object
{
if(!isset(LabelGenerator::CLASS_SUPPORT_MAPPING[$type])) {
throw new \InvalidArgumentException('The given type is not known and can not be mapped to a class!');
}
return $this->em->find(LabelGenerator::CLASS_SUPPORT_MAPPING[$type], $id);
}
} }

View file

@ -29,7 +29,7 @@ use Symfony\Component\Validator\Constraints as Assert;
class LabelOptions class LabelOptions
{ {
public const BARCODE_TYPES = ['none', /*'ean8',*/ 'qr', 'code39']; public const BARCODE_TYPES = ['none', /*'ean8',*/ 'qr', 'code39'];
public const SUPPORTED_ELEMENTS = ['part']; public const SUPPORTED_ELEMENTS = ['part', 'part_lot'];
public const PICTURE_TYPES = ['none', 'element_picture', 'main_attachment']; public const PICTURE_TYPES = ['none', 'element_picture', 'main_attachment'];
public const POSITIONS = ['left', 'right', 'top', 'bottom']; public const POSITIONS = ['left', 'right', 'top', 'bottom'];
public const FONTS = ['default']; public const FONTS = ['default'];

View file

@ -52,6 +52,14 @@ class LabelOptionsType extends AbstractType
] ]
]); ]);
$builder->add('supported_element', ChoiceType::class, [
'label' => 'label_options.supported_elements.label',
'choices' => [
'part.label' => 'part',
'part_lot.label' => 'part_lot'
]
]);
$builder->add('barcode_type', ChoiceType::class, [ $builder->add('barcode_type', ChoiceType::class, [
'label' => 'label_options.barcode_type.label', 'label' => 'label_options.barcode_type.label',
'empty_data' => 'none', 'empty_data' => 'none',

View file

@ -0,0 +1,56 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2020 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 Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace App\Form\LabelSystem;
use App\Form\LabelOptionsType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Type;
class LabelDialogType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('target_id', NumberType::class, [
'html5' => true,
'required' => true,
'label' => 'label_generator.target_id.label'
]);
$builder->add('options', LabelOptionsType::class, [
'label' => false,
]);
$builder->add('update', SubmitType::class, [
]);
}
public function configureOptions(OptionsResolver $resolver)
{
parent::configureOptions($resolver);
$resolver->setDefault('mapped', 'false');
}
}

View file

@ -24,14 +24,16 @@ namespace App\Services\LabelSystem;
use App\Entity\Contracts\NamedElementInterface; use App\Entity\Contracts\NamedElementInterface;
use App\Entity\LabelSystem\LabelOptions; use App\Entity\LabelSystem\LabelOptions;
use App\Entity\Parts\Part; use App\Entity\Parts\Part;
use App\Entity\Parts\PartLot;
use App\Services\ElementTypeNameGenerator; use App\Services\ElementTypeNameGenerator;
use Dompdf\Dompdf; use Dompdf\Dompdf;
use Twig\Environment; use Twig\Environment;
class LabelGenerator class LabelGenerator
{ {
protected const CLASS_SUPPORT_MAPPING = [ public const CLASS_SUPPORT_MAPPING = [
'part' => Part::class, 'part' => Part::class,
'part_lot' => PartLot::class,
]; ];
public const MM_TO_POINTS_FACTOR = 2.83465; public const MM_TO_POINTS_FACTOR = 2.83465;

View file

@ -40,7 +40,7 @@ class LabelHTMLGenerator
public function getLabelHTML(LabelOptions $options, object $element): string public function getLabelHTML(LabelOptions $options, object $element): string
{ {
return $this->twig->render('labels/base_label.html.twig', [ return $this->twig->render('LabelSystem/labels/base_label.html.twig', [
'meta_title' => $this->getPDFTitle($options, $element), 'meta_title' => $this->getPDFTitle($options, $element),
'lines' => $this->replacer->replace($options->getLines(), $element), 'lines' => $this->replacer->replace($options->getLines(), $element),
]); ]);

View file

@ -104,6 +104,7 @@ class ToolsTreeBuilder
$item->tag(['tree_tools', 'groups', $this->keyGenerator->generateKey()]); $item->tag(['tree_tools', 'groups', $this->keyGenerator->generateKey()]);
$tree = []; $tree = [];
$tree[] = new TreeViewNode($this->translator->trans('tree.tools.tools'), null, $this->getToolsNode());
$tree[] = new TreeViewNode($this->translator->trans('tree.tools.edit'), null, $this->getEditNodes()); $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.show'), null, $this->getShowNodes());
$tree[] = new TreeViewNode($this->translator->trans('tree.tools.system'), null, $this->getSystemNodes()); $tree[] = new TreeViewNode($this->translator->trans('tree.tools.system'), null, $this->getSystemNodes());
@ -112,6 +113,18 @@ class ToolsTreeBuilder
}); });
} }
protected function getToolsNode(): array
{
$nodes = [];
$nodes[] = new TreeViewNode(
$this->translator->trans('tree.tools.tools.label_dialog'),
$this->urlGenerator->generate('label_dialog')
);
return $nodes;
}
/** /**
* 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.
* *

View file

@ -0,0 +1,40 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2020 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 Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace App\Twig;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
class DataInlinerExtension extends AbstractExtension
{
public function getFunctions()
{
return [
new TwigFunction('inlineData', [$this, 'inlineData'])
];
}
public function inlineData(string $data, string $mime_type)
{
return 'data:' . $mime_type . ';base64,' . base64_encode($data);
}
}

View file

@ -47,6 +47,7 @@
{% endblock %} {% endblock %}
{% block label_options_widget %} {% block label_options_widget %}
{{ form_row(form.supported_element) }}
<div class="form-group row"> <div class="form-group row">
{{ form_label(form.width) }} {{ form_label(form.width) }}
<div class="input-group col-9"> <div class="input-group col-9">

View file

@ -0,0 +1,28 @@
{% extends 'main_card.html.twig' %}
{% block card_title %}<i class="fas fa-qrcode fa-fw"></i> {% trans %}label_generator.title{% endtrans %}{% endblock %}
{% block card_content %}
{{ form_start(form) }}
{{ form_row(form.target_id) }}
{{ form_widget(form.options) }}
{{ form_end(form) }}
{% if pdf_data %}
<div class="row">
<div class="col-sm-9 offset-sm-3">
<a data-no-ajax class="btn btn-secondary" href="#" onclick="this.href = document.getElementById('pdf_preview').data" download="{{ filename ?? '' }}">
{% trans %}label_generator.download{% endtrans %}
</a>
</div>
</div>
{% endif %}
{% endblock %}
{% block additional_content %}
{% if pdf_data %}
<div class="card mt-2 p-1 border-secondary" style="resize: vertical; overflow: scroll; height: 250px">
<object id="pdf_preview" data="{{ inlineData(pdf_data, 'application/pdf') | escape('html_attr') }}"style="height: inherit">
</object>
</div>
{% endif %}
{% endblock %}

View file

@ -7,7 +7,7 @@
<meta name="description" content="Label for {{ meta_title }}"> <meta name="description" content="Label for {{ meta_title }}">
<meta name="keywords" content="Part-DB, Label, Barcode"> <meta name="keywords" content="Part-DB, Label, Barcode">
<style> <style>
{% include("labels/label_style.css.twig") %} {% include("LabelSystem/labels/label_style.css.twig") %}
</style> </style>
</head> </head>
<body> <body>