Browse code

Attributes WIP

Benjamin Roth authored on06/08/2025 10:52:31
Showing10 changed files
... ...
@@ -92,15 +92,7 @@ $GLOBALS['TL_DCA']['tl_vr_wa_attribute'] = array
92 92
     // Palettes
93 93
     'palettes' => array
94 94
     (
95
-        '__selector__'                => array('type'),
96
-        'default'                     => '{title_legend},title,description;{type_legend},type'
97
-    ),
98
-
99
-    // Subpalettes
100
-    'subpalettes' => array
101
-    (
102
-        'type_text'                   => '',
103
-        'type_option'                 => ''
95
+        'default'                     => '{title_legend},title'
104 96
     ),
105 97
 
106 98
     // Fields
... ...
@@ -136,15 +128,5 @@ $GLOBALS['TL_DCA']['tl_vr_wa_attribute'] = array
136 128
             'eval'                    => array('tl_class'=>'clr'),
137 129
             'sql'                     => "text NULL"
138 130
         ),
139
-        'type' => array
140
-        (
141
-            'exclude'                 => true,
142
-            'filter'                  => true,
143
-            'inputType'               => 'select',
144
-            'options'                 => array('text', 'option'),
145
-            'reference'               => &$GLOBALS['TL_LANG']['tl_vr_wa_attribute']['type_options'],
146
-            'eval'                    => array('mandatory'=>true, 'submitOnChange'=>true, 'tl_class'=>'w50'),
147
-            'sql'                     => "varchar(32) NOT NULL default 'text'"
148
-        ),
149 131
     )
150 132
 );
... ...
@@ -89,7 +89,15 @@ $GLOBALS['TL_DCA']['tl_vr_wa_attribute_group'] = array
89 89
     // Palettes
90 90
     'palettes' => array
91 91
     (
92
-        'default'                     => '{title_legend},title,description;{config_legend},multiple,required'
92
+        '__selector__'                => array('type'),
93
+        'default'                     => '{title_legend},title,description;{type_legend},type'
94
+    ),
95
+
96
+    // Subpalettes
97
+    'subpalettes' => array
98
+    (
99
+        'type_text'                   => 'required',
100
+        'type_option'                 => 'multiple,required'
93 101
     ),
94 102
 
95 103
     // Fields
... ...
@@ -130,6 +138,16 @@ $GLOBALS['TL_DCA']['tl_vr_wa_attribute_group'] = array
130 138
             'inputType'               => 'checkbox',
131 139
             'eval'                    => array('tl_class'=>'w50 m12'),
132 140
             'sql'                     => "char(1) NOT NULL default ''"
141
+        ),
142
+        'type' => array
143
+        (
144
+            'exclude'                 => true,
145
+            'filter'                  => true,
146
+            'inputType'               => 'select',
147
+            'options'                 => array('text', 'option'),
148
+            'reference'               => &$GLOBALS['TL_LANG']['tl_vr_wa_attribute']['type_options'],
149
+            'eval'                    => array('mandatory'=>true, 'submitOnChange'=>true, 'tl_class'=>'w50'),
150
+            'sql'                     => "varchar(32) NOT NULL default 'text'"
133 151
         )
134 152
     )
135 153
 );
... ...
@@ -15,6 +15,8 @@ $GLOBALS['TL_LANG']['MOD']['weinanlieferung'][0] = 'Weinanlieferung';
15 15
 $GLOBALS['TL_LANG']['MOD']['weinanlieferung'][1] = 'Buchungstool zur Weinanlieferung';
16 16
 $GLOBALS['TL_LANG']['MOD']['wa_units'][0] = 'Botticheinheiten';
17 17
 $GLOBALS['TL_LANG']['MOD']['wa_units'][1] = 'Ermöglicht es auf Bottichmengen basierende Einheiten zu definieren.';
18
+$GLOBALS['TL_LANG']['MOD']['wa_attributes'][0] = 'Attribute';
19
+$GLOBALS['TL_LANG']['MOD']['wa_attributes'][1] = 'Verwalten von Attributen für Anlieferungs-Zeitslots.';
18 20
 $GLOBALS['TL_LANG']['MOD']['tl_vr_wa_rebsorte'] = 'Rebsorten';
19 21
 $GLOBALS['TL_LANG']['MOD']['tl_vr_wa_leseart'] = 'Leseart';
20 22
 $GLOBALS['TL_LANG']['MOD']['tl_vr_wa_slot'] = 'Zeitslots';
... ...
@@ -13,6 +13,7 @@ $GLOBALS['TL_LANG']['tl_vr_wa_attribute_group']['config_legend'] = 'Konfiguratio
13 13
 
14 14
 $GLOBALS['TL_LANG']['tl_vr_wa_attribute_group']['title'] = ['Titel', 'Bitte geben Sie den Titel der Attributgruppe ein.'];
15 15
 $GLOBALS['TL_LANG']['tl_vr_wa_attribute_group']['description'] = ['Beschreibung', 'Bitte geben Sie eine Beschreibung der Attributgruppe ein.'];
16
+$GLOBALS['TL_LANG']['tl_vr_wa_attribute_group']['type'] = ['Attributstyp', 'Legt den Typ der Attribute fest.'];
16 17
 $GLOBALS['TL_LANG']['tl_vr_wa_attribute_group']['multiple'] = ['Mehrfachauswahl', 'Erlaubt die Auswahl mehrerer Attribute aus dieser Gruppe.'];
17 18
 $GLOBALS['TL_LANG']['tl_vr_wa_attribute_group']['required'] = ['Pflichtfeld', 'Die Auswahl eines Attributs aus dieser Gruppe ist erforderlich.'];
18 19
 
... ...
@@ -87,13 +87,13 @@
87 87
 
88 88
                             {% for attribute in group.attributes %}
89 89
                                 <div class="attribute-item">
90
-                                    {% if attribute.type == 'text' %}
90
+                                    {% if group.type == 'text' %}
91 91
                                         <label for="attribute_{{ attribute.id }}">{{ attribute.title }}</label>
92 92
                                         <input type="text" id="attribute_{{ attribute.id }}" name="attribute_{{ attribute.id }}" class="form-control" value="{{ attribute.value }}">
93 93
                                         {% if attribute.description %}
94 94
                                             <div class="description">{{ attribute.description }}</div>
95 95
                                         {% endif %}
96
-                                    {% elseif attribute.type == 'option' %}
96
+                                    {% elseif group.type == 'option' %}
97 97
                                         <div class="checkbox">
98 98
                                             <label>
99 99
                                                 <input type="checkbox" id="attribute_{{ attribute.id }}" name="attribute_{{ attribute.id }}" value="1" {% if attribute.value %}checked{% endif %}>
... ...
@@ -114,28 +114,23 @@
114 114
                         {% if attribute_groups is defined and attribute_groups|length > 0 %}
115 115
                             {% for group in attribute_groups %}
116 116
                                 <fieldset>
117
-                                    <legend><strong>{{ group.title }}{% if group.required %}<sup class="text-danger">*</sup>{% endif %}</strong></legend>
117
+                                    <h5 class="legend">{{ group.title }}{% if group.required %}<sup class="text-danger">*</sup>{% endif %}</h5>
118 118
                                     {% if group.description %}
119
-                                        <div class="description">{{ group.description }}</div>
119
+                                        <div class="fieldset-description"><span class="info">{{ group.description }}</span></div>
120 120
                                     {% endif %}
121 121
 
122 122
                                     {% for attribute in group.attributes %}
123 123
                                         <div class="attribute-item">
124
-                                            {% if attribute.type == 'text' %}
125
-                                                <label for="attribute_{{ attribute.id }}">{{ attribute.title }}</label>
124
+                                            {% if group.type == 'text' %}
125
+                                                <label for="attribute_{{ attribute.id }}"><strong>{{ attribute.title }}</strong></label>
126 126
                                                 <input type="text" id="attribute_{{ attribute.id }}" name="attribute_{{ attribute.id }}" class="form-control">
127 127
                                                 {% if attribute.description %}
128
-                                                    <div class="description">{{ attribute.description }}</div>
128
+                                                    <div class="fieldset-description"><span class="info">{{ attribute.description }}</span></div>
129 129
                                                 {% endif %}
130
-                                            {% elseif attribute.type == 'option' %}
131
-                                                <div class="checkbox">
132
-                                                    <label>
133
-                                                        <input type="checkbox" id="attribute_{{ attribute.id }}" name="attribute_{{ attribute.id }}" value="1">
134
-                                                        {{ attribute.title }}
135
-                                                    </label>
136
-                                                    {% if attribute.description %}
137
-                                                        <div class="description">{{ attribute.description }}</div>
138
-                                                    {% endif %}
130
+                                            {% elseif group.type == 'option' %}
131
+                                                <div class="checkbox form-ext-control form-ext-{{ group.multiple ? 'checkbox' : 'radio' }}">
132
+                                                    <input class="form-ext-input" type="{{ group.multiple ? 'checkbox' : 'radio' }}" id="attribute_{{ attribute.id }}" name="{{ group.multiple ? 'attribute_'~attribute.id : 'group_'~group.id }}" value="1">
133
+                                                    <label class="form-ext-label" for="attribute_{{ attribute.id }}">{{ attribute.title }}</label>
139 134
                                                 </div>
140 135
                                             {% endif %}
141 136
                                         </div>
... ...
@@ -10,6 +10,10 @@ article, blockquote, p {
10 10
   line-height: 1.5;
11 11
 }
12 12
 
13
+h5.legend {
14
+  font-size: 1.3125rem;
15
+}
16
+
13 17
 .list {
14 18
   .slots > * ,
15 19
   .bookings > * {
... ...
@@ -211,3 +215,7 @@ ul {
211 215
 .ml-auto {
212 216
   margin-left: auto;
213 217
 }
218
+
219
+.fieldset-description {
220
+  margin-bottom: .5rem;
221
+}
... ...
@@ -157,7 +157,7 @@ class SlotAjaxController extends AbstractController
157 157
         // Get selected attributes
158 158
         $selectedAttributeIds = [];
159 159
         if ($Slot->attributes) {
160
-            $selectedAttributeIds = StringUtil::deserialize($Slot->attributes, true);
160
+            $selectedAttributeIds = array_map('trim', explode(',', $Slot->attributes));
161 161
         }
162 162
 
163 163
         // If no attributes are selected, don't show any
... ...
@@ -183,8 +183,7 @@ class SlotAjaxController extends AbstractController
183 183
                     $attributesByGroup[$groupId][] = [
184 184
                         'id' => $attribute->id,
185 185
                         'title' => $attribute->title,
186
-                        'description' => $attribute->description,
187
-                        'type' => $attribute->type
186
+                        'description' => $attribute->description
188 187
                     ];
189 188
                 }
190 189
 
... ...
@@ -203,6 +202,7 @@ class SlotAjaxController extends AbstractController
203 202
                                     'id' => $group->id,
204 203
                                     'title' => $group->title,
205 204
                                     'description' => $group->description,
205
+                                    'type' => $group->type,
206 206
                                     'multiple' => (bool)$group->multiple,
207 207
                                     'required' => (bool)$group->required,
208 208
                                     'attributes' => $attributesByGroup[$group->id]
... ...
@@ -408,7 +408,7 @@ class SlotAjaxController extends AbstractController
408 408
         // Get selected attributes
409 409
         $selectedAttributeIds = [];
410 410
         if ($Slot->attributes) {
411
-            $selectedAttributeIds = StringUtil::deserialize($Slot->attributes, true);
411
+            $selectedAttributeIds = array_map('trim', explode(',', $Slot->attributes));
412 412
         }
413 413
 
414 414
         // If no attributes are selected, don't show any
... ...
@@ -435,7 +435,6 @@ class SlotAjaxController extends AbstractController
435 435
                         'id' => $attribute->id,
436 436
                         'title' => $attribute->title,
437 437
                         'description' => $attribute->description,
438
-                        'type' => $attribute->type,
439 438
                         'value' => $attributeValues[$attribute->id] ?? null
440 439
                     ];
441 440
                 }
... ...
@@ -455,6 +454,7 @@ class SlotAjaxController extends AbstractController
455 454
                                     'id' => $group->id,
456 455
                                     'title' => $group->title,
457 456
                                     'description' => $group->description,
457
+                                    'type' => $group->type,
458 458
                                     'multiple' => (bool)$group->multiple,
459 459
                                     'required' => (bool)$group->required,
460 460
                                     'attributes' => $attributesByGroup[$group->id]
... ...
@@ -573,7 +573,7 @@ class SlotAjaxController extends AbstractController
573 573
         // Get selected attributes
574 574
         $selectedAttributeIds = [];
575 575
         if ($Slot->attributes) {
576
-            $selectedAttributeIds = StringUtil::deserialize($Slot->attributes, true);
576
+            $selectedAttributeIds = array_map('trim', explode(',', $Slot->attributes));
577 577
         }
578 578
 
579 579
         // If no attributes are selected, skip attribute processing
... ...
@@ -599,12 +599,14 @@ class SlotAjaxController extends AbstractController
599 599
                     $groups = WeinanlieferungAttributeGroupModel::findMultipleByIds($groupIds);
600 600
 
601 601
                     if ($groups !== null) {
602
-                        // Create maps for attribute-to-group and group-required status
602
+                        // Create maps for attribute-to-group, group-required status, and group-type
603 603
                         $attributeToGroupMap = [];
604 604
                         $groupRequiredMap = [];
605
+                        $groupTypeMap = [];
605 606
 
606 607
                         foreach ($groups as $group) {
607 608
                             $groupRequiredMap[$group->id] = (bool)$group->required;
609
+                            $groupTypeMap[$group->id] = $group->type;
608 610
                         }
609 611
 
610 612
                         foreach ($selectedAttributes as $attribute) {
... ...
@@ -618,14 +620,15 @@ class SlotAjaxController extends AbstractController
618 620
                         foreach ($selectedAttributes as $attribute) {
619 621
                             $attributeKey = 'attribute_' . $attribute->id;
620 622
                             $groupId = $attributeToGroupMap[$attribute->id];
623
+                            $groupType = $groupTypeMap[$groupId];
621 624
 
622
-                            if ($attribute->type === 'text') {
625
+                            if ($groupType === 'text') {
623 626
                                 // For text attributes, store the text value
624 627
                                 if (!empty(Input::post($attributeKey))) {
625 628
                                     $attributeValues[$attribute->id] = Input::post($attributeKey);
626 629
                                     $groupHasValue[$groupId] = true;
627 630
                                 }
628
-                            } else if ($attribute->type === 'option') {
631
+                            } else if ($groupType === 'option') {
629 632
                                 // For option attributes, store true if selected
630 633
                                 if (Input::post($attributeKey)) {
631 634
                                     $attributeValues[$attribute->id] = true;
... ...
@@ -752,7 +755,7 @@ class SlotAjaxController extends AbstractController
752 755
         // Get selected attributes
753 756
         $selectedAttributeIds = [];
754 757
         if ($Slot->attributes) {
755
-            $selectedAttributeIds = StringUtil::deserialize($Slot->attributes, true);
758
+            $selectedAttributeIds = array_map('trim', explode(',', $Slot->attributes));
756 759
         }
757 760
 
758 761
         // If no attributes are selected, skip attribute processing
... ...
@@ -778,12 +781,14 @@ class SlotAjaxController extends AbstractController
778 781
                     $groups = WeinanlieferungAttributeGroupModel::findMultipleByIds($groupIds);
779 782
 
780 783
                     if ($groups !== null) {
781
-                        // Create maps for attribute-to-group and group-required status
784
+                        // Create maps for attribute-to-group, group-required status, and group-type
782 785
                         $attributeToGroupMap = [];
783 786
                         $groupRequiredMap = [];
787
+                        $groupTypeMap = [];
784 788
 
785 789
                         foreach ($groups as $group) {
786 790
                             $groupRequiredMap[$group->id] = (bool)$group->required;
791
+                            $groupTypeMap[$group->id] = $group->type;
787 792
                         }
788 793
 
789 794
                         foreach ($selectedAttributes as $attribute) {
... ...
@@ -797,14 +802,15 @@ class SlotAjaxController extends AbstractController
797 802
                         foreach ($selectedAttributes as $attribute) {
798 803
                             $attributeKey = 'attribute_' . $attribute->id;
799 804
                             $groupId = $attributeToGroupMap[$attribute->id];
805
+                            $groupType = $groupTypeMap[$groupId];
800 806
 
801
-                            if ($attribute->type === 'text') {
807
+                            if ($groupType === 'text') {
802 808
                                 // For text attributes, store the text value
803 809
                                 if (!empty(Input::post($attributeKey))) {
804 810
                                     $attributeValues[$attribute->id] = Input::post($attributeKey);
805 811
                                     $groupHasValue[$groupId] = true;
806 812
                                 }
807
-                            } else if ($attribute->type === 'option') {
813
+                            } else if ($groupType === 'option') {
808 814
                                 // For option attributes, store true if selected
809 815
                                 if (Input::post($attributeKey)) {
810 816
                                     $attributeValues[$attribute->id] = true;
811 817
new file mode 100644
... ...
@@ -0,0 +1,64 @@
1
+<?php
2
+
3
+declare(strict_types=1);
4
+
5
+/*
6
+ * This file is part of contao-weinanlieferung-bundle.
7
+ *
8
+ * (c) vonRotenberg
9
+ *
10
+ * @license commercial
11
+ */
12
+
13
+namespace vonRotenberg\WeinanlieferungBundle\EventListener\DataContainer;
14
+
15
+use Contao\CoreBundle\DataContainer\PaletteManipulator;
16
+use Contao\CoreBundle\ServiceAnnotation\Callback;
17
+use Contao\DataContainer;
18
+use Doctrine\DBAL\Connection;
19
+use Symfony\Component\HttpFoundation\RequestStack;
20
+use Symfony\Contracts\Translation\TranslatorInterface;
21
+use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungAttributeGroupModel;
22
+use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungAttributeModel;
23
+
24
+class WeinanlieferungAttributeContainerListener
25
+{
26
+    /** @var Connection */
27
+    protected $db;
28
+
29
+    /** @var TranslatorInterface */
30
+    protected $translator;
31
+
32
+    /** @var RequestStack */
33
+    protected $requestStack;
34
+
35
+    public function __construct(Connection $db, TranslatorInterface $translator, RequestStack $requestStack)
36
+    {
37
+        $this->db = $db;
38
+        $this->translator = $translator;
39
+        $this->requestStack = $requestStack;
40
+    }
41
+
42
+
43
+    /**
44
+     * @Callback(table="tl_vr_wa_attribute", target="config.onload")
45
+     */
46
+    public function onLoadCallback(DataContainer $dc)
47
+    {
48
+        if (null === $dc || !$dc->id || 'edit' !== $this->requestStack->getCurrentRequest()->query->get('act')) {
49
+            return;
50
+        }
51
+
52
+        if (($attribute = WeinanlieferungAttributeModel::findByPk($dc->id)) === null || ($group = $attribute->getRelated('pid')) === null)
53
+        {
54
+            return;
55
+        }
56
+
57
+        if ($group->type == 'text')
58
+        {
59
+            PaletteManipulator::create()
60
+                ->addField('description','title')
61
+                ->applyToPalette('default', 'tl_vr_wa_attribute');
62
+        }
63
+    }
64
+}
... ...
@@ -189,12 +189,13 @@ class WeinanlieferungSlotContainerListener
189 189
             // Add attributes to the options array
190 190
             $groupAttributes = [];
191 191
             foreach ($attributes as $attribute) {
192
-                $groupAttributes[$attribute->id] = $attribute->title . ' <span style="color:#999;padding-left:3px">[' . $GLOBALS['TL_LANG']['tl_vr_wa_attribute']['type_options'][$attribute->type] . ']</span>';
192
+                $groupAttributes[$attribute->id] = $attribute->title;
193 193
             }
194 194
 
195 195
             // Add the group to the options array if it has attributes
196 196
             if (!empty($groupAttributes)) {
197
-                $options[$group->title] = $groupAttributes;
197
+                $groupTitle = $group->title . ' <span style="color:#999;padding-left:3px">[' . $GLOBALS['TL_LANG']['tl_vr_wa_attribute']['type_options'][$group->type] . ']</span>';
198
+                $options[$groupTitle] = $groupAttributes;
198 199
             }
199 200
         }
200 201