diff --git a/src/Entity/ExportableItem.php b/src/Entity/ExportableItem.php index 6606a6c7..28b81161 100644 --- a/src/Entity/ExportableItem.php +++ b/src/Entity/ExportableItem.php @@ -12,8 +12,8 @@ namespace App\Entity; use Doctrine\Common\Collections\Collection; /** - * @method getTags() array - * @method getBreak() int + * @method array getTags() + * @method int getBreak() */ interface ExportableItem { diff --git a/src/Entity/MetaTableTypeInterface.php b/src/Entity/MetaTableTypeInterface.php index 03783a1d..856089af 100644 --- a/src/Entity/MetaTableTypeInterface.php +++ b/src/Entity/MetaTableTypeInterface.php @@ -11,6 +11,10 @@ namespace App\Entity; use Symfony\Component\Validator\Constraint; +/** + * @method null|string getSection() + * @method void setSection(?string $name) + */ interface MetaTableTypeInterface { /** @@ -43,6 +47,8 @@ interface MetaTableTypeInterface /** * This will merge the current object with the values from the given $meta instance. * It should NOT update the name or value, but only the form settings. + * + * Settings from the given $meta object will win over the current ones. */ public function merge(MetaTableTypeInterface $meta): MetaTableTypeInterface; @@ -132,6 +138,16 @@ interface MetaTableTypeInterface */ public function getOrder(): int; + /** + * FIXME activate with 3.0 + */ + //public function setSection(?string $section): void; + + /** + * FIXME activate with 3.0 + */ + //public function getSection(): ?string; + /** * Whether true if this field is defined by a plugin, or false if it is a value stored in the database. */ diff --git a/src/Entity/MetaTableTypeTrait.php b/src/Entity/MetaTableTypeTrait.php index 855e3a65..782463f7 100644 --- a/src/Entity/MetaTableTypeTrait.php +++ b/src/Entity/MetaTableTypeTrait.php @@ -67,6 +67,7 @@ trait MetaTableTypeTrait */ private mixed $data = null; private bool $updated = false; + private ?string $section = null; public function getName(): ?string { @@ -193,13 +194,11 @@ trait MetaTableTypeTrait public function merge(MetaTableTypeInterface $meta): MetaTableTypeInterface { - $this - ->setConstraints($meta->getConstraints()) - ->setIsRequired($meta->isRequired()) - ->setIsVisible($meta->isVisible()) - ->setOptions($meta->getOptions()) - ->setOrder($meta->getOrder()) - ; + $this->setConstraints($meta->getConstraints()); + $this->setIsRequired($meta->isRequired()); + $this->setIsVisible($meta->isVisible()); + $this->setOptions($meta->getOptions()); + $this->setOrder($meta->getOrder()); if ($meta->getLabel() !== null) { $this->setLabel($meta->getLabel()); @@ -209,6 +208,10 @@ trait MetaTableTypeTrait $this->setType($meta->getType()); } + if ($meta->getSection() !== null) { + $this->setSection($meta->getSection()); + } + return $this; } @@ -266,6 +269,16 @@ trait MetaTableTypeTrait } } + public function setSection(?string $section): void + { + $this->section = $section; + } + + public function getSection(): ?string + { + return $this->section; + } + /** * Whether this field is defined by a plugin or just a value stored in the database. */ diff --git a/src/Export/ExportRendererInterface.php b/src/Export/ExportRendererInterface.php index 72eb2417..535f94e0 100644 --- a/src/Export/ExportRendererInterface.php +++ b/src/Export/ExportRendererInterface.php @@ -14,9 +14,9 @@ use App\Repository\Query\TimesheetQuery; use Symfony\Component\HttpFoundation\Response; /** - * TODO change interface for 3.0 - * @method getType() string - * @method isInternal() bool + * FIXME change interface for 3.0 + * @method string getType() + * @method bool isInternal() */ interface ExportRendererInterface { diff --git a/templates/activity/edit.html.twig b/templates/activity/edit.html.twig index 4a415f54..f4de9867 100644 --- a/templates/activity/edit.html.twig +++ b/templates/activity/edit.html.twig @@ -8,6 +8,7 @@ 'back': path('admin_activity') } %} {% embed formEditTemplate with formOptions %} + {% import "macros/form_helper.html.twig" as form_helper %} {% block form_body %}
@@ -49,6 +50,18 @@
{% endif %} + {{ form_helper.metafields(form, null) }} + {% embed '@theme/embeds/collapsible.html.twig' with {id: 'activity_invoice_settings'} %} + {% import "macros/widgets.html.twig" as widgets %} + {% import "macros/form_helper.html.twig" as form_helper %} + {% block title %}{{ 'invoices'|trans }}{% endblock %} + {% block body %} + {% if form.invoiceText is defined %} + {{ form_row(form.invoiceText) }} + {% endif %} + {{ form_helper.metafields(form, 'invoice') }} + {% endblock %} + {% endembed %}
{{ form_row(form.visible) }} @@ -57,18 +70,6 @@ {{ form_row(form.billable) }}
- {% if form.metaFields is defined and form.metaFields is not empty %} - {{ form_row(form.metaFields) }} - {% endif %} - {% embed '@theme/embeds/collapsible.html.twig' with {id: 'activity_invoice_settings'} %} - {% import "macros/widgets.html.twig" as widgets %} - {% block title %}{{ 'invoices'|trans }}{% endblock %} - {% block body %} - {% if form.invoiceText is defined %} - {{ form_row(form.invoiceText) }} - {% endif %} - {% endblock %} - {% endembed %} {{ form_rest(form) }} {% endblock %} {% endembed %} diff --git a/templates/customer/edit.html.twig b/templates/customer/edit.html.twig index 30e3439d..fc6a17d7 100644 --- a/templates/customer/edit.html.twig +++ b/templates/customer/edit.html.twig @@ -8,6 +8,7 @@ 'back': path('admin_customer') } %} {% embed formEditTemplate with formOptions %} + {% import "macros/form_helper.html.twig" as form_helper %} {% block form_body %}
@@ -75,11 +76,10 @@
{% endif %} - {% if form.metaFields is defined and form.metaFields is not empty %} - {{ form_row(form.metaFields) }} - {% endif %} + {{ form_helper.metafields(form, null) }} {% embed '@theme/embeds/collapsible.html.twig' with {id: 'customer_address_settings'} %} {% import "macros/widgets.html.twig" as widgets %} + {% import "macros/form_helper.html.twig" as form_helper %} {% block title %}{{ 'address'|trans }}{% endblock %} {% block body %}
@@ -125,11 +125,12 @@ {{ form_row(form.timezone) }}
- + {{ form_helper.metafields(form, 'address') }} {% endblock %} {% endembed %} {% embed '@theme/embeds/collapsible.html.twig' with {id: 'customer_invoice_settings'} %} {% import "macros/widgets.html.twig" as widgets %} + {% import "macros/form_helper.html.twig" as form_helper %} {% block title %}{{ 'invoices'|trans }}{% endblock %} {% block body %} {% if form.buyerReference is defined %} @@ -141,6 +142,7 @@ {% if form.invoiceText is defined %} {{ form_row(form.invoiceText) }} {% endif %} + {{ form_helper.metafields(form, 'invoice') }} {% endblock %} {% endembed %}
diff --git a/templates/form/blocks.html.twig b/templates/form/blocks.html.twig index 4686c8b0..6d31f3dd 100644 --- a/templates/form/blocks.html.twig +++ b/templates/form/blocks.html.twig @@ -474,7 +474,9 @@ {%- block meta_fields_collection_widget -%} {% for meta in form|sort((a, b) => a.vars.data.order <=> b.vars.data.order) %} - {{ form_row(meta.value, {'row_attr': {'class': 'mb-3 ' ~ form.parent.vars.name ~ '_row_' ~ form.vars.name ~ '_' ~ meta.vars.name}}) }} + {% if not meta.rendered %} + {{ form_row(meta.value, {'row_attr': {'class': 'mb-3 ' ~ form.parent.vars.name ~ '_row_' ~ form.vars.name ~ '_' ~ meta.vars.name}}) }} + {% endif %} {% endfor %} {%- endblock meta_fields_collection_widget %} diff --git a/templates/macros/form_helper.html.twig b/templates/macros/form_helper.html.twig new file mode 100644 index 00000000..2b14b4e6 --- /dev/null +++ b/templates/macros/form_helper.html.twig @@ -0,0 +1,7 @@ +{% macro metafields(form, section) %} + {% for meta in form.metaFields|sort((a, b) => a.vars.data.order <=> b.vars.data.order) %} + {% if meta.vars.data.section is same as (section) %} + {{ form_row(meta.value, {'row_attr': {'class': 'mb-3 ' ~ form.vars.name ~ '_row_' ~ form.metaFields.vars.name ~ '_' ~ meta.vars.name}}) }} + {% endif %} + {% endfor %} +{% endmacro %} diff --git a/templates/project/edit.html.twig b/templates/project/edit.html.twig index aeede91a..304dca97 100644 --- a/templates/project/edit.html.twig +++ b/templates/project/edit.html.twig @@ -8,6 +8,7 @@ 'back': path('admin_project') } %} {% embed formEditTemplate with formOptions %} + {% import "macros/form_helper.html.twig" as form_helper %} {% block form_body %}
@@ -58,11 +59,10 @@
{% endif %} - {% if form.metaFields is defined and form.metaFields is not empty %} - {{ form_row(form.metaFields) }} - {% endif %} + {{ form_helper.metafields(form, null) }} {% embed '@theme/embeds/collapsible.html.twig' with {id: 'project_invoice_settings'} %} {% import "macros/widgets.html.twig" as widgets %} + {% import "macros/form_helper.html.twig" as form_helper %} {% block title %}{{ 'invoices'|trans }}{% endblock %} {% block body %}
@@ -76,6 +76,7 @@ {% if form.invoiceText is defined %} {{ form_row(form.invoiceText) }} {% endif %} + {{ form_helper.metafields(form, 'invoice') }} {% endblock %} {% endembed %}
diff --git a/tests/Entity/AbstractMetaEntityTestCase.php b/tests/Entity/AbstractMetaEntityTestCase.php index 75d0c502..42d2a6c2 100644 --- a/tests/Entity/AbstractMetaEntityTestCase.php +++ b/tests/Entity/AbstractMetaEntityTestCase.php @@ -38,6 +38,7 @@ abstract class AbstractMetaEntityTestCase extends TestCase self::assertFalse($sut->isVisible()); self::assertFalse($sut->isRequired()); self::assertEquals(0, $sut->getOrder()); + self::assertNull($sut->getSection()); } public function testSetterAndGetter(): void @@ -83,6 +84,11 @@ abstract class AbstractMetaEntityTestCase extends TestCase $entity = $this->getEntity(); self::assertInstanceOf(MetaTableTypeInterface::class, $sut->setEntity($entity)); self::assertSame($entity, $sut->getEntity()); + + $sut->setSection('foo'); + self::assertEquals('foo', $sut->getSection()); + $sut->setSection(null); + self::assertNull($sut->getSection()); } public function testMerge(): void @@ -90,18 +96,19 @@ abstract class AbstractMetaEntityTestCase extends TestCase $entity1 = $this->getEntity(); $entity2 = $this->getEntity(); $meta1 = $this->getMetaEntity(); - $meta1 - ->setName('foo') - ->setValue('bar') - ->setType('blub') - ->setEntity($entity1) - ->setConstraints([new NotNull()]) - ->setOptions(['foo' => 'bar', 'bar' => 'foo']) - ; + $meta1->setName('foo'); + $meta1->setValue('bar'); + $meta1->setType('blub'); + $meta1->setEntity($entity1); + $meta1->setConstraints([new NotNull()]); + $meta1->setOptions(['foo' => 'bar', 'bar' => 'foo']); + $meta1->setSection('hello'); + self::assertEquals('foo', $meta1->getName()); self::assertEquals('bar', $meta1->getValue()); self::assertEquals('blub', $meta1->getType()); self::assertEquals('foo', $meta1->getLabel()); + self::assertEquals('hello', $meta1->getSection()); self::assertFalse($meta1->isRequired()); self::assertFalse($meta1->isVisible()); self::assertSame($entity1, $meta1->getEntity()); @@ -109,18 +116,17 @@ abstract class AbstractMetaEntityTestCase extends TestCase self::assertCount(2, $meta1->getOptions()); $meta2 = $this->getMetaEntity(); - $meta2 - ->setName('foo2') - ->setLabel('TRALALA') - ->setValue('bar2') - ->setType('blub2') - ->setEntity($entity2) - ->setIsRequired(true) - ->setIsVisible(true) - ->setOrder(93) - ->setConstraints([new NotBlank(), new Length(['min' => 1])]) - ->setOptions(['foo1' => 'bar1']) - ; + $meta2->setName('foo2'); + $meta2->setLabel('TRALALA'); + $meta2->setValue('bar2'); + $meta2->setType('blub2'); + $meta2->setSection('world'); + $meta2->setEntity($entity2); + $meta2->setIsRequired(true); + $meta2->setIsVisible(true); + $meta2->setOrder(93); + $meta2->setConstraints([new NotBlank(), new Length(['min' => 1])]); + $meta2->setOptions(['foo1' => 'bar1']); self::assertInstanceOf(MetaTableTypeInterface::class, $meta1->merge($meta2)); @@ -128,6 +134,7 @@ abstract class AbstractMetaEntityTestCase extends TestCase self::assertEquals('bar', $meta1->getValue()); self::assertEquals('blub2', $meta1->getType()); self::assertEquals('TRALALA', $meta1->getLabel()); + self::assertEquals('world', $meta1->getSection()); self::assertEquals(93, $meta1->getOrder()); self::assertTrue($meta1->isRequired()); self::assertTrue($meta1->isVisible());