From 504e8755af9917b92baf1f9a5d2801c62db15ef1 Mon Sep 17 00:00:00 2001 From: martinyde Date: Tue, 18 Feb 2025 12:48:35 +0100 Subject: [PATCH 1/3] Updated qr code and added config type --- src/Controller/Admin/Field/ConfigField.php | 28 ++++++ src/Controller/Admin/QrCrudController.php | 12 ++- src/Controller/QrCodePreviewController.php | 4 - src/Entity/Qr.php | 38 ++++++++ src/Form/Type/ConfigType.php | 107 +++++++++++++++++++++ templates/fields/config/config.html.twig | 1 + templates/fields/link/link.html.twig | 6 +- 7 files changed, 184 insertions(+), 12 deletions(-) create mode 100644 src/Controller/Admin/Field/ConfigField.php create mode 100644 src/Form/Type/ConfigType.php create mode 100644 templates/fields/config/config.html.twig diff --git a/src/Controller/Admin/Field/ConfigField.php b/src/Controller/Admin/Field/ConfigField.php new file mode 100644 index 0000000..c6f2694 --- /dev/null +++ b/src/Controller/Admin/Field/ConfigField.php @@ -0,0 +1,28 @@ +setProperty($propertyName) + ->setLabel($label) + + ->setTemplatePath('fields/config/config.html.twig') + + ->setFormType(ConfigType::class) + ; + } +} \ No newline at end of file diff --git a/src/Controller/Admin/QrCrudController.php b/src/Controller/Admin/QrCrudController.php index daefb98..5b7d03d 100644 --- a/src/Controller/Admin/QrCrudController.php +++ b/src/Controller/Admin/QrCrudController.php @@ -2,6 +2,7 @@ namespace App\Controller\Admin; +use App\Controller\Admin\Field\ConfigField; use App\Entity\Qr; use App\Form\Type\UrlsType; use App\Helper\DownloadHelper; @@ -13,6 +14,7 @@ use EasyCorp\Bundle\EasyAdminBundle\Contracts\Controller\CrudControllerInterface; use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController; use EasyCorp\Bundle\EasyAdminBundle\Dto\BatchActionDto; +use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField; use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField; use EasyCorp\Bundle\EasyAdminBundle\Field\CollectionField; use EasyCorp\Bundle\EasyAdminBundle\Field\Field; @@ -64,11 +66,9 @@ public function configureFields(string $pageName): iterable return [ TextField::new('title', new TranslatableMessage('Title')), TextEditorField::new('description', new TranslatableMessage('Description')), - CollectionField::new('urls', new TranslatableMessage('URLs')) - ->setFormTypeOption('entry_type', UrlsType::class) - ->allowAdd() - ->allowDelete() - ->renderExpanded(), + AssociationField::new('urls') + ->setFormTypeOptions(['by_reference' => false]) + ->setTemplatePath('fields/url/urls.html.twig'), ChoiceField::new('mode', new TranslatableMessage('Mode')) ->renderAsNativeWidget(), TextField::new('author', new TranslatableMessage('Author')) @@ -76,6 +76,7 @@ public function configureFields(string $pageName): iterable Field::new('customUrlButton', new TranslatableMessage('Open Resource')) ->setTemplatePath('fields/link/link.html.twig') ->hideOnForm(), + ConfigField::new('config', new TranslatableMessage('Configuration')) ]; } @@ -96,6 +97,7 @@ public function configureFields(string $pageName): iterable TextField::new('author', new TranslatableMessage('Author')) ->setDisabled() ->hideOnForm(), + ConfigField::new('config', new TranslatableMessage('Configuration')) ]; } diff --git a/src/Controller/QrCodePreviewController.php b/src/Controller/QrCodePreviewController.php index 40ac8c2..b6579e1 100644 --- a/src/Controller/QrCodePreviewController.php +++ b/src/Controller/QrCodePreviewController.php @@ -45,9 +45,6 @@ public function generateQrCode(Request $request): JsonResponse $logo = null; } - // Build the data you want encoded in the QR code - $qrString = 'https://www.google.dk'; - // Get QR code settings or use defaults $size = (int) min(400, $downloadSettings['size'] ?? 400); $margin = (int) ($downloadSettings['margin'] ?? 0); @@ -69,7 +66,6 @@ public function generateQrCode(Request $request): JsonResponse // Generate the QR Code using Endroid QR Code Builder $builder = new Builder(); $result = $builder->build( - data: $qrString, encoding: new Encoding('UTF-8'), errorCorrectionLevel: $errorCorrectionLevel, size: $size, diff --git a/src/Entity/Qr.php b/src/Entity/Qr.php index a38aa3b..ba27856 100644 --- a/src/Entity/Qr.php +++ b/src/Entity/Qr.php @@ -7,6 +7,7 @@ use ApiPlatform\Metadata\ApiFilter; use ApiPlatform\Metadata\ApiResource; use App\Enum\QrModeEnum; +use App\QrConfig\Config; use App\Repository\QrRepository; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; @@ -59,6 +60,9 @@ class Qr #[ORM\Column(type: 'datetime_immutable')] private \DateTimeImmutable $updatedAt; + #[ORM\Column(type: 'json')] + private ?array $config = null; + public function __construct() { $this->urls = new ArrayCollection(); @@ -218,4 +222,38 @@ public function removeAllUrls(): void $this->removeUrl($url); } } + + public function getConfig(): Config + { + $config = $this->config; + + return new Config( + $config['size'], + $config['margin'], + $config['code_background'], + $config['code_color'], + $config['text'], + $config['text_color'], + $config['text_margin_top'], + $config['text_margin_bottom'], + $config['error_correction_level'], + ); + } + + public function setConfig(Config $config): static + { + $this->config = [ + 'size' => $config->getSize(), + 'margin' => $config->getMargin(), + 'code_background' => $config->getCodeBackground(), + 'code_color' => $config->getCodeColor(), + 'text' => $config->getText(), + 'text_color' => $config->getTextColor(), + 'text_margin_top' => $config->getTextMarginTop(), + 'text_margin_bottom' => $config->getTextMarginBottom(), + 'error_correction_level' => $config->getErrorCorrectionLevel() + ]; + + return $this; + } } diff --git a/src/Form/Type/ConfigType.php b/src/Form/Type/ConfigType.php new file mode 100644 index 0000000..d92ddfb --- /dev/null +++ b/src/Form/Type/ConfigType.php @@ -0,0 +1,107 @@ +add('size', TextType::class, [ + 'required' => false, + 'empty_data' => '', + ]) + ->add('margin', TextType::class, [ + 'required' => false, + 'empty_data' => '', + ]) + ->add('code_background', TextType::class, [ + 'required' => false, + 'empty_data' => '', + ]) + ->add('code_color', TextType::class, [ + 'required' => false, + 'empty_data' => '', + ]) + ->add('text', TextType::class, [ + 'required' => false, + 'empty_data' => '', + ]) + ->add('text_color', TextType::class, [ + 'required' => false, + 'empty_data' => '', + ]) + ->add('text_margin_top', TextType::class, [ + 'required' => false, + 'empty_data' => '', + ]) + ->add('text_margin_bottom', TextType::class, [ + 'required' => false, + 'empty_data' => '', + ]) + ->add('error_correction_level', TextType::class, [ + 'required' => false, + 'empty_data' => '', + ]) + ->setDataMapper($this) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefault('empty_data', null); + } + + public function mapDataToForms(mixed $viewData, \Traversable $forms): void { + // there is no data yet, so nothing to prepopulate + if (null === $viewData) { + return; + } + + // invalid data type + if (!$viewData instanceof Config) { + throw new UnexpectedTypeException($viewData, Config::class); + } + + /** @var FormInterface[] $forms */ + $forms = iterator_to_array($forms); + + // initialize form field values + $forms['size']->setData($viewData->getSize()); + $forms['margin']->setData($viewData->getMargin()); + $forms['code_background']->setData($viewData->getCodeBackground()); + $forms['code_color']->setData($viewData->getCodeColor()); + $forms['text']->setData($viewData->getText()); + $forms['text_color']->setData($viewData->getTextColor()); + $forms['text_margin_top']->setData($viewData->getTextMarginTop()); + $forms['text_margin_bottom']->setData($viewData->getTextMarginBottom()); + $forms['error_correction_level']->setData($viewData->getErrorCorrectionLevel()); + } + + public function mapFormsToData(\Traversable $forms, mixed &$viewData): void { + /** @var FormInterface[] $forms */ + $forms = iterator_to_array($forms); + + $viewData = new Config( + $forms['size']->getData(), + $forms['margin']->getData(), + $forms['code_background']->getData(), + $forms['code_color']->getData(), + $forms['text']->getData(), + $forms['text_color']->getData(), + $forms['text_margin_top']->getData(), + $forms['text_margin_bottom']->getData(), + $forms['error_correction_level']->getData(), + ); + } + +} diff --git a/templates/fields/config/config.html.twig b/templates/fields/config/config.html.twig new file mode 100644 index 0000000..72943a1 --- /dev/null +++ b/templates/fields/config/config.html.twig @@ -0,0 +1 @@ +aaa diff --git a/templates/fields/link/link.html.twig b/templates/fields/link/link.html.twig index e0c594f..c115782 100644 --- a/templates/fields/link/link.html.twig +++ b/templates/fields/link/link.html.twig @@ -1,9 +1,9 @@ -{% set generate_qr_url = app_base_generate_path ~ app_base_redirect_path ~ entity.instance.uuid %} +{% set generate_qr_url = app_base_redirect_path ~ entity.instance.uuid %} - + View - Generated Image + Generated Image From 9cff45baefdf9a9c4247f0ed02bad1f742f41056 Mon Sep 17 00:00:00 2001 From: martinyde Date: Tue, 18 Feb 2025 12:49:42 +0100 Subject: [PATCH 2/3] Removed config field --- src/Entity/Qr.php | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/src/Entity/Qr.php b/src/Entity/Qr.php index ba27856..c4ece1c 100644 --- a/src/Entity/Qr.php +++ b/src/Entity/Qr.php @@ -222,38 +222,4 @@ public function removeAllUrls(): void $this->removeUrl($url); } } - - public function getConfig(): Config - { - $config = $this->config; - - return new Config( - $config['size'], - $config['margin'], - $config['code_background'], - $config['code_color'], - $config['text'], - $config['text_color'], - $config['text_margin_top'], - $config['text_margin_bottom'], - $config['error_correction_level'], - ); - } - - public function setConfig(Config $config): static - { - $this->config = [ - 'size' => $config->getSize(), - 'margin' => $config->getMargin(), - 'code_background' => $config->getCodeBackground(), - 'code_color' => $config->getCodeColor(), - 'text' => $config->getText(), - 'text_color' => $config->getTextColor(), - 'text_margin_top' => $config->getTextMarginTop(), - 'text_margin_bottom' => $config->getTextMarginBottom(), - 'error_correction_level' => $config->getErrorCorrectionLevel() - ]; - - return $this; - } } From b504574f77ef8ff4779331b54e21c281393dd631 Mon Sep 17 00:00:00 2001 From: martinyde Date: Wed, 19 Feb 2025 08:46:47 +0100 Subject: [PATCH 3/3] Added config entity --- migrations/Version20250218134959.php | 33 +++++ src/Controller/Admin/QrCrudController.php | 2 +- src/Entity/Qr.php | 16 ++- src/Entity/QrConfig.php | 145 ++++++++++++++++++++++ src/Form/Type/ConfigType.php | 64 +--------- src/Repository/QrConfigRepository.php | 43 +++++++ 6 files changed, 240 insertions(+), 63 deletions(-) create mode 100644 migrations/Version20250218134959.php create mode 100644 src/Entity/QrConfig.php create mode 100644 src/Repository/QrConfigRepository.php diff --git a/migrations/Version20250218134959.php b/migrations/Version20250218134959.php new file mode 100644 index 0000000..dcf2f4a --- /dev/null +++ b/migrations/Version20250218134959.php @@ -0,0 +1,33 @@ +addSql('ALTER TABLE qr ADD qr_config_size VARCHAR(255) DEFAULT NULL, ADD qr_config_margin VARCHAR(255) DEFAULT NULL, ADD qr_config_code_background VARCHAR(255) DEFAULT NULL, ADD qr_config_code_color VARCHAR(255) DEFAULT NULL, ADD qr_config_text VARCHAR(255) DEFAULT NULL, ADD qr_config_text_color VARCHAR(255) DEFAULT NULL, ADD qr_config_text_margin_top VARCHAR(255) DEFAULT NULL, ADD qr_config_text_margin_bottom VARCHAR(255) DEFAULT NULL, ADD qr_config_error_correction_level VARCHAR(255) DEFAULT NULL, CHANGE created_at created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', CHANGE updated_at updated_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\''); + $this->addSql('ALTER TABLE url CHANGE qr_id qr_id INT DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE url CHANGE qr_id qr_id INT NOT NULL'); + $this->addSql('ALTER TABLE qr DROP qr_config_size, DROP qr_config_margin, DROP qr_config_code_background, DROP qr_config_code_color, DROP qr_config_text, DROP qr_config_text_color, DROP qr_config_text_margin_top, DROP qr_config_text_margin_bottom, DROP qr_config_error_correction_level, CHANGE created_at created_at DATETIME NOT NULL, CHANGE updated_at updated_at DATETIME NOT NULL'); + } +} diff --git a/src/Controller/Admin/QrCrudController.php b/src/Controller/Admin/QrCrudController.php index 5b7d03d..08247a6 100644 --- a/src/Controller/Admin/QrCrudController.php +++ b/src/Controller/Admin/QrCrudController.php @@ -97,7 +97,7 @@ public function configureFields(string $pageName): iterable TextField::new('author', new TranslatableMessage('Author')) ->setDisabled() ->hideOnForm(), - ConfigField::new('config', new TranslatableMessage('Configuration')) + ConfigField::new('qrConfig', new TranslatableMessage('Configuration')) ]; } diff --git a/src/Entity/Qr.php b/src/Entity/Qr.php index c4ece1c..0872c1a 100644 --- a/src/Entity/Qr.php +++ b/src/Entity/Qr.php @@ -7,11 +7,11 @@ use ApiPlatform\Metadata\ApiFilter; use ApiPlatform\Metadata\ApiResource; use App\Enum\QrModeEnum; -use App\QrConfig\Config; use App\Repository\QrRepository; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; +use Doctrine\ORM\Mapping\Embedded; use Symfony\Component\Uid\Uuid; use Symfony\Component\Uid\UuidV7; use Symfony\Component\Validator\Constraints as Assert; @@ -60,8 +60,8 @@ class Qr #[ORM\Column(type: 'datetime_immutable')] private \DateTimeImmutable $updatedAt; - #[ORM\Column(type: 'json')] - private ?array $config = null; + #[Embedded(class: QrConfig::class)] + private QrConfig $qrConfig; public function __construct() { @@ -202,6 +202,16 @@ public function setUpdatedAt(\DateTimeImmutable $updatedAt): self return $this; } + public function setQrConfig(QrConfig $qrConfig): void + { + $this->qrConfig = $qrConfig; + } + + public function getQrConfig(): QrConfig + { + return $this->qrConfig; + } + #[ORM\PrePersist] public function onPrePersist(): void { diff --git a/src/Entity/QrConfig.php b/src/Entity/QrConfig.php new file mode 100644 index 0000000..6e2cb13 --- /dev/null +++ b/src/Entity/QrConfig.php @@ -0,0 +1,145 @@ +size; + } + + public function setSize(?string $size): static + { + $this->size = $size; + + return $this; + } + + public function getMargin(): ?string + { + return $this->margin; + } + + public function setMargin(?string $margin): static + { + $this->margin = $margin; + + return $this; + } + + public function getCodeBackground(): ?string + { + return $this->codeBackground; + } + + public function setCodeBackground(?string $codeBackground): static + { + $this->codeBackground = $codeBackground; + + return $this; + } + + public function getCodeColor(): ?string + { + return $this->codeColor; + } + + public function setCodeColor(?string $codeColor): static + { + $this->codeColor = $codeColor; + + return $this; + } + + public function getText(): ?string + { + return $this->text; + } + + public function setText(?string $text): static + { + $this->text = $text; + + return $this; + } + + public function getTextColor(): ?string + { + return $this->textColor; + } + + public function setTextColor(?string $textColor): static + { + $this->textColor = $textColor; + + return $this; + } + + public function getTextMarginTop(): ?string + { + return $this->textMarginTop; + } + + public function setTextMarginTop(?string $textMarginTop): static + { + $this->textMarginTop = $textMarginTop; + + return $this; + } + + public function getTextMarginBottom(): ?string + { + return $this->textMarginBottom; + } + + public function setTextMarginBottom(?string $textMarginBottom): static + { + $this->textMarginBottom = $textMarginBottom; + + return $this; + } + + public function getErrorCorrectionLevel(): ?string + { + return $this->errorCorrectionLevel; + } + + public function setErrorCorrectionLevel(?string $errorCorrectionLevel): static + { + $this->errorCorrectionLevel = $errorCorrectionLevel; + + return $this; + } +} diff --git a/src/Form/Type/ConfigType.php b/src/Form/Type/ConfigType.php index d92ddfb..fb30ab5 100644 --- a/src/Form/Type/ConfigType.php +++ b/src/Form/Type/ConfigType.php @@ -2,106 +2,52 @@ namespace App\Form\Type; -use App\QrConfig\Config; +use App\Entity\QrConfig; use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\DataMapperInterface; -use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\Form\FormInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Form\Extension\Core\Type\TextType; -final class ConfigType extends AbstractType implements DataMapperInterface +final class ConfigType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options): void { $builder ->add('size', TextType::class, [ 'required' => false, - 'empty_data' => '', ]) ->add('margin', TextType::class, [ 'required' => false, - 'empty_data' => '', ]) ->add('code_background', TextType::class, [ 'required' => false, - 'empty_data' => '', ]) ->add('code_color', TextType::class, [ 'required' => false, - 'empty_data' => '', ]) ->add('text', TextType::class, [ 'required' => false, - 'empty_data' => '', ]) ->add('text_color', TextType::class, [ 'required' => false, - 'empty_data' => '', ]) ->add('text_margin_top', TextType::class, [ 'required' => false, - 'empty_data' => '', ]) ->add('text_margin_bottom', TextType::class, [ 'required' => false, - 'empty_data' => '', ]) ->add('error_correction_level', TextType::class, [ 'required' => false, - 'empty_data' => '', ]) - ->setDataMapper($this) ; } public function configureOptions(OptionsResolver $resolver): void { - $resolver->setDefault('empty_data', null); - } - - public function mapDataToForms(mixed $viewData, \Traversable $forms): void { - // there is no data yet, so nothing to prepopulate - if (null === $viewData) { - return; - } - - // invalid data type - if (!$viewData instanceof Config) { - throw new UnexpectedTypeException($viewData, Config::class); - } - - /** @var FormInterface[] $forms */ - $forms = iterator_to_array($forms); - - // initialize form field values - $forms['size']->setData($viewData->getSize()); - $forms['margin']->setData($viewData->getMargin()); - $forms['code_background']->setData($viewData->getCodeBackground()); - $forms['code_color']->setData($viewData->getCodeColor()); - $forms['text']->setData($viewData->getText()); - $forms['text_color']->setData($viewData->getTextColor()); - $forms['text_margin_top']->setData($viewData->getTextMarginTop()); - $forms['text_margin_bottom']->setData($viewData->getTextMarginBottom()); - $forms['error_correction_level']->setData($viewData->getErrorCorrectionLevel()); - } - - public function mapFormsToData(\Traversable $forms, mixed &$viewData): void { - /** @var FormInterface[] $forms */ - $forms = iterator_to_array($forms); - - $viewData = new Config( - $forms['size']->getData(), - $forms['margin']->getData(), - $forms['code_background']->getData(), - $forms['code_color']->getData(), - $forms['text']->getData(), - $forms['text_color']->getData(), - $forms['text_margin_top']->getData(), - $forms['text_margin_bottom']->getData(), - $forms['error_correction_level']->getData(), - ); + $resolver->setDefaults([ + 'data_class' => QrConfig::class, + ]); } } diff --git a/src/Repository/QrConfigRepository.php b/src/Repository/QrConfigRepository.php new file mode 100644 index 0000000..c2163ee --- /dev/null +++ b/src/Repository/QrConfigRepository.php @@ -0,0 +1,43 @@ + + */ +class QrConfigRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, QrConfig::class); + } + + // /** + // * @return QrConfig[] Returns an array of QrConfig objects + // */ + // public function findByExampleField($value): array + // { + // return $this->createQueryBuilder('q') + // ->andWhere('q.exampleField = :val') + // ->setParameter('val', $value) + // ->orderBy('q.id', 'ASC') + // ->setMaxResults(10) + // ->getQuery() + // ->getResult() + // ; + // } + + // public function findOneBySomeField($value): ?QrConfig + // { + // return $this->createQueryBuilder('q') + // ->andWhere('q.exampleField = :val') + // ->setParameter('val', $value) + // ->getQuery() + // ->getOneOrNullResult() + // ; + // } +}