1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
12:
13: namespace DcGeneral\Contao\Dca\Builder\Legacy;
14:
15: use DcGeneral\Contao\Callback\ContainerGetBreadcrumbCallbackListener;
16: use DcGeneral\Contao\Callback\ContainerGlobalButtonCallbackListener;
17: use DcGeneral\Contao\Callback\ContainerHeaderCallbackListener;
18: use DcGeneral\Contao\Callback\ContainerOnCopyCallbackListener;
19: use DcGeneral\Contao\Callback\ContainerOnCutCallbackListener;
20: use DcGeneral\Contao\Callback\ContainerOnDeleteCallbackListener;
21: use DcGeneral\Contao\Callback\ContainerOnLoadCallbackListener;
22: use DcGeneral\Contao\Callback\ContainerOnSubmitCallbackListener;
23: use DcGeneral\Contao\Callback\ContainerPasteButtonCallbackListener;
24: use DcGeneral\Contao\Callback\ContainerPasteRootButtonCallbackListener;
25: use DcGeneral\Contao\Callback\ModelChildRecordCallbackListener;
26: use DcGeneral\Contao\Callback\ModelGroupCallbackListener;
27: use DcGeneral\Contao\Callback\ModelLabelCallbackListener;
28: use DcGeneral\Contao\Callback\ModelOperationButtonCallbackListener;
29: use DcGeneral\Contao\Callback\ModelOptionsCallbackListener;
30: use DcGeneral\Contao\Callback\PropertyInputFieldCallbackListener;
31: use DcGeneral\Contao\Callback\PropertyInputFieldGetWizardCallbackListener;
32: use DcGeneral\Contao\Callback\PropertyOnLoadCallbackListener;
33: use DcGeneral\Contao\Callback\PropertyOnSaveCallbackListener;
34: use DcGeneral\Contao\Dca\ContaoDataProviderInformation;
35: use DcGeneral\Contao\Dca\Palette\LegacyPalettesParser;
36: use DcGeneral\Contao\View\Contao2BackendView\Event\BuildWidgetEvent;
37: use DcGeneral\Contao\View\Contao2BackendView\Event\DecodePropertyValueForWidgetEvent;
38: use DcGeneral\Contao\View\Contao2BackendView\Event\EncodePropertyValueFromWidgetEvent;
39: use DcGeneral\Contao\View\Contao2BackendView\Event\GetBreadcrumbEvent;
40: use DcGeneral\Contao\View\Contao2BackendView\Event\GetGlobalButtonEvent;
41: use DcGeneral\Contao\View\Contao2BackendView\Event\GetGroupHeaderEvent;
42: use DcGeneral\Contao\View\Contao2BackendView\Event\GetOperationButtonEvent;
43: use DcGeneral\Contao\View\Contao2BackendView\Event\GetParentHeaderEvent;
44: use DcGeneral\Contao\View\Contao2BackendView\Event\GetPasteButtonEvent;
45: use DcGeneral\Contao\View\Contao2BackendView\Event\GetPasteRootButtonEvent;
46: use DcGeneral\Contao\View\Contao2BackendView\Event\GetPropertyOptionsEvent;
47: use DcGeneral\Contao\View\Contao2BackendView\Event\ManipulateWidgetEvent;
48: use DcGeneral\Contao\View\Contao2BackendView\Event\ModelToLabelEvent;
49: use DcGeneral\Contao\View\Contao2BackendView\Event\ParentViewChildRecordEvent;
50: use DcGeneral\DataDefinition\ContainerInterface;
51: use DcGeneral\Contao\DataDefinition\Definition\Contao2BackendViewDefinitionInterface;
52: use DcGeneral\DataDefinition\Definition\BasicDefinitionInterface;
53: use DcGeneral\Contao\DataDefinition\Definition\Contao2BackendViewDefinition;
54: use DcGeneral\DataDefinition\Definition\DefaultBasicDefinition;
55: use DcGeneral\DataDefinition\Definition\DefaultDataProviderDefinition;
56: use DcGeneral\DataDefinition\Definition\DefaultModelRelationshipDefinition;
57: use DcGeneral\DataDefinition\Definition\DefaultPalettesDefinition;
58: use DcGeneral\DataDefinition\Definition\ModelRelationshipDefinitionInterface;
59: use DcGeneral\DataDefinition\Definition\Properties\DefaultProperty;
60: use DcGeneral\DataDefinition\Definition\Properties\PropertyInterface;
61: use DcGeneral\DataDefinition\Definition\PalettesDefinitionInterface;
62: use DcGeneral\DataDefinition\Definition\DefaultPropertiesDefinition;
63: use DcGeneral\DataDefinition\Definition\View\Command;
64: use DcGeneral\DataDefinition\Definition\View\CommandInterface;
65: use DcGeneral\DataDefinition\Definition\View\CutCommand;
66: use DcGeneral\DataDefinition\Definition\View\DefaultModelFormatterConfig;
67: use DcGeneral\DataDefinition\Definition\View\ListingConfigInterface;
68: use DcGeneral\DataDefinition\Definition\View\Panel\DefaultFilterElementInformation;
69: use DcGeneral\DataDefinition\Definition\View\Panel\DefaultLimitElementInformation;
70: use DcGeneral\DataDefinition\Definition\View\Panel\DefaultSearchElementInformation;
71: use DcGeneral\DataDefinition\Definition\View\Panel\DefaultSortElementInformation;
72: use DcGeneral\DataDefinition\Definition\View\Panel\DefaultSubmitElementInformation;
73: use DcGeneral\DataDefinition\Definition\View\Panel\SubmitElementInformationInterface;
74: use DcGeneral\DataDefinition\Definition\View\PanelRowInterface;
75: use DcGeneral\DataDefinition\ModelRelationship\RootCondition;
76: use DcGeneral\Event\PostDeleteModelEvent;
77: use DcGeneral\Event\PostDuplicateModelEvent;
78: use DcGeneral\Event\PostPasteModelEvent;
79: use DcGeneral\Event\PostPersistModelEvent;
80: use DcGeneral\Exception\DcGeneralInvalidArgumentException;
81: use DcGeneral\Exception\DcGeneralRuntimeException;
82: use DcGeneral\Factory\DcGeneralFactory;
83: use DcGeneral\Factory\Event\BuildDataDefinitionEvent;
84: use DcGeneral\Factory\Event\CreateDcGeneralEvent;
85: use DcGeneral\Factory\Event\PopulateEnvironmentEvent;
86: use Symfony\Component\EventDispatcher\EventDispatcherInterface;
87:
88: 89: 90:
91: class LegacyDcaDataDefinitionBuilder extends DcaReadingDataDefinitionBuilder
92: {
93: const PRIORITY = 100;
94:
95: 96: 97:
98: public function build(ContainerInterface $container, BuildDataDefinitionEvent $event)
99: {
100: if (!$this->loadDca($container->getName(), $event->getDispatcher()))
101: {
102: return;
103: }
104:
105: $this->parseCallbacks($container, $event->getDispatcher());
106: $this->parseBasicDefinition($container);
107: $this->parseDataProvider($container);
108: $this->parseRootEntries($container);
109: $this->parseParentChildConditions($container);
110: $this->parseBackendView($container);
111: $this->parsePalettes($container);
112: $this->parseProperties($container);
113: $this->loadAdditionalDefinitions($container, $event);
114: }
115:
116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127:
128: protected function loadAdditionalDefinitions(ContainerInterface $container, BuildDataDefinitionEvent $event)
129: {
130: if ($this->getFromDca('config/ptable'))
131: {
132: $event->getDispatcher()->addListener(
133: sprintf('%s[%s]', PopulateEnvironmentEvent::NAME, $container->getName()),
134: function (PopulateEnvironmentEvent $event) {
135: $environment = $event->getEnvironment();
136: $definition = $environment->getDataDefinition();
137: $parentName = $definition->getBasicDefinition()->getParentDataProvider();
138: $factory = DcGeneralFactory::deriveEmptyFromEnvironment($environment)->setContainerName($parentName);
139: $parentDefinition = $factory->createContainer();
140:
141: $environment->setParentDataDefinition($parentDefinition);
142: }
143: );
144: }
145: }
146:
147: 148: 149: 150: 151: 152: 153: 154: 155:
156: protected function parseCallbacks(ContainerInterface $container, EventDispatcherInterface $dispatcher)
157: {
158: if (isset($GLOBALS['objDcGeneral']) && is_array($callbacks = $this->getFromDca('config/onload_callback')))
159: {
160: foreach ($callbacks as $callback)
161: {
162: $dispatcher->addListener(
163: sprintf('%s[%s]', CreateDcGeneralEvent::NAME, $container->getName()),
164: new ContainerOnLoadCallbackListener($callback, $GLOBALS['objDcGeneral'])
165: );
166: }
167: }
168:
169: if (isset($GLOBALS['objDcGeneral']) && is_array($callbacks = $this->getFromDca('config/onsubmit_callback')))
170: {
171: foreach ($callbacks as $callback)
172: {
173: $dispatcher->addListener(
174: sprintf('%s[%s]', PostPersistModelEvent::NAME, $container->getName()),
175: new ContainerOnSubmitCallbackListener($callback, $GLOBALS['objDcGeneral'])
176: );
177: }
178: }
179:
180: if (isset($GLOBALS['objDcGeneral']) && is_array($callbacks = $this->getFromDca('config/ondelete_callback')))
181: {
182: foreach ($callbacks as $callback)
183: {
184: $dispatcher->addListener(
185: sprintf('%s[%s]', PostDeleteModelEvent::NAME, $container->getName()),
186: new ContainerOnDeleteCallbackListener($callback, $GLOBALS['objDcGeneral'])
187: );
188: }
189: }
190:
191: if (isset($GLOBALS['objDcGeneral']) && is_array($callbacks = $this->getFromDca('config/oncut_callback')))
192: {
193: foreach ($callbacks as $callback)
194: {
195: $dispatcher->addListener(
196: sprintf('%s[%s]', PostPasteModelEvent::NAME, $container->getName()),
197: new ContainerOnCutCallbackListener($callback, $GLOBALS['objDcGeneral'])
198: );
199: }
200: }
201:
202: if (isset($GLOBALS['objDcGeneral']) && is_array($callbacks = $this->getFromDca('config/oncopy_callback')))
203: {
204: foreach ($callbacks as $callback)
205: {
206: $dispatcher->addListener(
207: sprintf('%s[%s]', PostDuplicateModelEvent::NAME, $container->getName()),
208: new ContainerOnCopyCallbackListener($callback, $GLOBALS['objDcGeneral'])
209: );
210: }
211: }
212:
213: if (isset($GLOBALS['objDcGeneral']) && $callback = $this->getFromDca('list/sorting/header_callback'))
214: {
215: $dispatcher->addListener(
216: sprintf('%s[%s]', GetParentHeaderEvent::NAME, $container->getName()),
217: new ContainerHeaderCallbackListener($callback, $GLOBALS['objDcGeneral'])
218: );
219: }
220:
221: if (isset($GLOBALS['objDcGeneral']) && $callback = $this->getFromDca('list/sorting/paste_button_callback'))
222: {
223: $dispatcher->addListener(
224: sprintf('%s[%s]', GetPasteRootButtonEvent::NAME, $container->getName()),
225: new ContainerPasteRootButtonCallbackListener($callback, $GLOBALS['objDcGeneral'])
226: );
227: $dispatcher->addListener(
228: sprintf('%s[%s]', GetPasteButtonEvent::NAME, $container->getName()),
229: new ContainerPasteButtonCallbackListener($callback, $GLOBALS['objDcGeneral'])
230: );
231: }
232:
233: if (isset($GLOBALS['objDcGeneral']) && $callback = $this->getFromDca('list/sorting/child_record_callback'))
234: {
235: $dispatcher->addListener(
236: sprintf('%s[%s]', ParentViewChildRecordEvent::NAME, $container->getName()),
237: new ModelChildRecordCallbackListener($callback)
238: );
239: }
240:
241: if (isset($GLOBALS['objDcGeneral']) && $callback = $this->getFromDca('list/label/group_callback'))
242: {
243: $dispatcher->addListener(
244: sprintf('%s[%s]', GetGroupHeaderEvent::NAME, $container->getName()),
245: new ModelGroupCallbackListener($callback)
246: );
247: }
248:
249: if (isset($GLOBALS['objDcGeneral']) && $callback = $this->getFromDca('list/label/label_callback'))
250: {
251: $dispatcher->addListener(
252: sprintf('%s[%s]', ModelToLabelEvent::NAME, $container->getName()),
253: new ModelLabelCallbackListener($callback, $GLOBALS['objDcGeneral'])
254: );
255: }
256:
257: if (isset($GLOBALS['objDcGeneral']))
258: {
259: if (is_array($operations = $this->getFromDca('global_operations')))
260: {
261: foreach ($operations as $operationName => $operationInfo)
262: {
263: if (isset($operationInfo['button_callback']))
264: {
265: $callback = $operationInfo['button_callback'];
266: $dispatcher->addListener(
267: sprintf('%s[%s][%s]', GetGlobalButtonEvent::NAME, $container->getName(), $operationName),
268: new ContainerGlobalButtonCallbackListener($callback)
269: );
270: }
271: }
272: }
273: }
274:
275: if (isset($GLOBALS['objDcGeneral']))
276: {
277: if (is_array($operations = $this->getFromDca('operations')))
278: {
279: foreach ($operations as $operationName => $operationInfo)
280: {
281: if (isset($operationInfo['button_callback']))
282: {
283: $callback = $operationInfo['button_callback'];
284: $dispatcher->addListener(
285: sprintf('%s[%s][%s]', GetOperationButtonEvent::NAME, $container->getName(), $operationName),
286: new ModelOperationButtonCallbackListener($callback)
287: );
288: }
289: }
290: }
291: }
292:
293: if (isset($GLOBALS['objDcGeneral']))
294: {
295: foreach ($this->getFromDca('fields') as $propName => $propInfo)
296: {
297: if (isset($propInfo['load_callback']))
298: {
299: foreach ($propInfo['load_callback'] as $callback)
300: {
301: $dispatcher->addListener(
302: DecodePropertyValueForWidgetEvent::NAME . sprintf('[%s][%s]', $container->getName(), $propName),
303: new PropertyOnLoadCallbackListener($callback, $GLOBALS['objDcGeneral'])
304: );
305: }
306: }
307:
308: if (isset($propInfo['save_callback']))
309: {
310: foreach ($propInfo['save_callback'] as $callback)
311: {
312: $dispatcher->addListener(
313: EncodePropertyValueFromWidgetEvent::NAME . sprintf('[%s][%s]', $container->getName(), $propName),
314: new PropertyOnSaveCallbackListener($callback, $GLOBALS['objDcGeneral'])
315: );
316: }
317: }
318:
319: if (isset($propInfo['options_callback']))
320: {
321: $callback = $propInfo['options_callback'];
322: $dispatcher->addListener(
323: GetPropertyOptionsEvent::NAME . sprintf('[%s][%s]', $container->getName(), $propName),
324: new ModelOptionsCallbackListener($callback, $GLOBALS['objDcGeneral'])
325: );
326: }
327:
328: if (isset($propInfo['input_field_callback']))
329: {
330: $callback = $propInfo['input_field_callback'];
331: $dispatcher->addListener(
332: BuildWidgetEvent::NAME . sprintf('[%s][%s]', $container->getName(), $propName),
333: new PropertyInputFieldCallbackListener($callback, $GLOBALS['objDcGeneral'])
334: );
335: }
336:
337: if (isset($propInfo['wizard']))
338: {
339: $callbacks = $propInfo['wizard'];
340: foreach ($callbacks as $callback) {
341: $dispatcher->addListener(
342: ManipulateWidgetEvent::NAME . sprintf('[%s][%s]', $container->getName(), $propName),
343: new PropertyInputFieldGetWizardCallbackListener($callback, $GLOBALS['objDcGeneral'])
344: );
345: }
346: }
347: }
348: }
349:
350: if (isset($GLOBALS['objDcGeneral']) && $callback = $this->getFromDca('list/presentation/breadcrumb_callback'))
351: {
352: $dispatcher->addListener(
353: sprintf('%s[%s]', GetBreadcrumbEvent::NAME, $container->getName()),
354: new ContainerGetBreadcrumbCallbackListener($callback, $GLOBALS['objDcGeneral'])
355: );
356: }
357: }
358:
359: 360: 361: 362: 363: 364: 365:
366: protected function parseBasicMode(BasicDefinitionInterface $config)
367: {
368: switch ($this->getFromDca('list/sorting/mode'))
369: {
370: case 0:
371:
372: case 1:
373:
374: case 2:
375:
376: case 3:
377:
378: $config->setMode(BasicDefinitionInterface::MODE_FLAT);
379: break;
380: case 4:
381:
382: $config->setMode(BasicDefinitionInterface::MODE_PARENTEDLIST);
383: break;
384: case 5:
385:
386: case 6:
387:
388: $config->setMode(BasicDefinitionInterface::MODE_HIERARCHICAL);
389: break;
390: default:
391: }
392: }
393:
394: 395: 396: 397: 398: 399: 400:
401: protected function parseBasicFlags(BasicDefinitionInterface $config)
402: {
403: if (($switchToEdit = $this->getFromDca('config/switchToEdit')) !== null)
404: {
405: $config->setSwitchToEditEnabled((bool)$switchToEdit);
406: }
407:
408: if (($value = $this->getFromDca('config/closed')) !== null)
409: {
410: $config->setClosed((bool)$value);
411: }
412:
413: if (($value = $this->getFromDca('config/notEditable')) !== null)
414: {
415: $config->setEditable(!$value);
416: }
417:
418: if (($value = $this->getFromDca('config/notDeletable')) !== null)
419: {
420: $config->setDeletable(!$value);
421: }
422:
423: if (($value = $this->getFromDca('config/notCreatable')) !== null)
424: {
425: $config->setCreatable(!(bool)$value);
426: }
427: }
428:
429: 430: 431: 432: 433: 434: 435:
436: protected function parseBasicDefinition(ContainerInterface $container)
437: {
438:
439: if ($container->hasBasicDefinition())
440: {
441: $config = $container->getBasicDefinition();
442: }
443: else
444: {
445: $config = new DefaultBasicDefinition();
446: $container->setBasicDefinition($config);
447: }
448:
449: $this->parseBasicMode($config);
450: $this->parseBasicFlags($config);
451:
452: if (($filters = $this->getFromDca('list/sorting/filter')) !== null)
453: {
454: if (is_array($filters) && !empty($filters))
455: {
456: $myFilters = array();
457: foreach ($filters as $filter)
458: {
459:
460: $myFilters = array('operation' => '=', 'property' => $filter[0], 'value' => $filter[1]);
461: }
462: if ($config->hasAdditionalFilter())
463: {
464: $currentFilter = $config->getAdditionalFilter();
465: $currentFilter = array_merge($currentFilter, $myFilters);
466: $filter = array(
467: 'operation' => 'AND',
468: 'children' => array($currentFilter)
469: );
470: }
471: else
472: {
473: $filter = $myFilters;
474: }
475:
476: $config->setAdditionalFilter($config->getDataProvider(), $filter);
477: }
478: }
479: }
480:
481: 482: 483: 484: 485: 486: 487:
488: protected function parseDataProvider(ContainerInterface $container)
489: {
490: if ($container->hasDataProviderDefinition())
491: {
492: $config = $container->getDataProviderDefinition();
493: }
494: else
495: {
496: $config = new DefaultDataProviderDefinition();
497: $container->setDataProviderDefinition($config);
498: }
499:
500: if (($parentTable = $this->getFromDca('config/ptable')) !== null)
501: {
502:
503: if (!$config->hasInformation($parentTable))
504: {
505: $providerInformation = new ContaoDataProviderInformation();
506: $providerInformation->setName($parentTable);
507: $config->addInformation($providerInformation);
508: }
509: else
510: {
511: $providerInformation = $config->getInformation($parentTable);
512: }
513:
514: if ($providerInformation instanceof ContaoDataProviderInformation)
515: {
516: $initializationData = (array)$providerInformation->getInitializationData();
517:
518: $providerInformation
519: ->setTableName($parentTable)
520: ->setInitializationData(array_merge(
521: array(
522: 'source' => $parentTable
523: ),
524: $initializationData
525: ));
526:
527: $container->getBasicDefinition()->setRootDataProvider($parentTable);
528: $container->getBasicDefinition()->setParentDataProvider($parentTable);
529: }
530: }
531:
532:
533: if (!$config->hasInformation($container->getName()))
534: {
535: $providerInformation = new ContaoDataProviderInformation();
536: $providerInformation->setName($container->getName());
537: $config->addInformation($providerInformation);
538: }
539: else
540: {
541: $providerInformation = $config->getInformation($container->getName());
542: }
543:
544: if ($providerInformation instanceof ContaoDataProviderInformation)
545: {
546: $initializationData = (array)$providerInformation->getInitializationData();
547:
548: $providerInformation
549: ->setTableName($container->getName())
550: ->setInitializationData(array_merge(
551: array(
552: 'source' => $container->getName()
553: ),
554: $initializationData
555: ))
556: ->isVersioningEnabled((bool)$this->getFromDca('config/enableVersioning'));
557:
558: $container->getBasicDefinition()->setDataProvider($container->getName());
559: }
560: }
561:
562: 563: 564: 565: 566: 567: 568:
569: protected function parseRootEntries(ContainerInterface $container)
570: {
571:
572: }
573:
574: 575: 576: 577: 578: 579: 580: 581: 582:
583: protected function getRootProviderName(ContainerInterface $container)
584: {
585: $rootProvider = $container->getBasicDefinition()->getRootDataProvider();
586:
587: if (!$rootProvider)
588: {
589: throw new DcGeneralRuntimeException(
590: 'Root data provider name not specified in DCA but rootEntries section specified.'
591: );
592: }
593:
594: if (!$container->getDataProviderDefinition()->hasInformation($rootProvider))
595: {
596: throw new DcGeneralRuntimeException('Unknown root data provider but rootEntries section specified.');
597: }
598:
599: return $rootProvider;
600: }
601:
602: 603: 604: 605: 606: 607: 608:
609: protected function parseParentChildConditions(ContainerInterface $container)
610: {
611: if ($container->hasDefinition(ModelRelationshipDefinitionInterface::NAME))
612: {
613: $definition = $container->getDefinition(ModelRelationshipDefinitionInterface::NAME);
614: }
615: else
616: {
617: $definition = new DefaultModelRelationshipDefinition();
618: }
619:
620:
621: if (($value = $this->getFromDca('config/ptable')) !== null)
622: {
623: $rootProvider = $this->getRootProviderName($container);
624:
625: if (($relationship = $definition->getRootCondition()) === null)
626: {
627: $relationship = new RootCondition();
628: $relationship
629: ->setSourceName($rootProvider);
630: $definition->setRootCondition($relationship);
631: }
632: if (!$relationship->getSetters())
633: {
634: $relationship
635: ->setSetters(array(array('property' => 'pid', 'value' => '0')));
636: }
637:
638: $container->setDefinition(ModelRelationshipDefinitionInterface::NAME, $definition);
639: }
640:
641:
642: if ($value = $this->getFromDca('list/sorting/root'))
643: {
644: $rootProvider = $this->getRootProviderName($container);
645:
646: $myFilter = array('operation' => 'IN', 'property' => 'id', 'value' => $value);
647:
648: if (($relationship = $definition->getRootCondition()) === null)
649: {
650: $relationship = new RootCondition();
651: $filter = $myFilter;
652: }
653: else
654: {
655: $filter = $relationship->getFilterArray();
656: if ($filter)
657: {
658: $filter = array(
659: 'operation' => 'AND',
660: 'children' => array($filter)
661: );
662:
663: $filter['children'][] = $myFilter;
664: }
665: else{
666: $filter = $myFilter;
667: }
668: }
669:
670: $relationship
671: ->setSourceName($rootProvider)
672: ->setFilterArray(array($filter));
673: $definition->setRootCondition($relationship);
674:
675: $container->setDefinition(ModelRelationshipDefinitionInterface::NAME, $definition);
676: }
677: }
678:
679: 680: 681: 682: 683: 684: 685: 686: 687: 688:
689: protected function parseBackendView(ContainerInterface $container)
690: {
691: if ($container->hasDefinition(Contao2BackendViewDefinitionInterface::NAME))
692: {
693: $view = $container->getDefinition(Contao2BackendViewDefinitionInterface::NAME);
694: }
695: else
696: {
697: $view = new Contao2BackendViewDefinition();
698: $container->setDefinition(Contao2BackendViewDefinitionInterface::NAME, $view);
699: }
700:
701: if (!$view instanceof Contao2BackendViewDefinitionInterface)
702: {
703: throw new DcGeneralInvalidArgumentException(
704: 'Configured BackendViewDefinition does not implement Contao2BackendViewDefinitionInterface.'
705: );
706: }
707:
708: $this->parseListing($container, $view);
709: $this->parsePanel($view);
710: $this->parseGlobalOperations($view);
711: $this->parseModelOperations($view);
712: }
713:
714: 715: 716: 717: 718: 719: 720: 721: 722:
723: protected function parseListing(ContainerInterface $container, Contao2BackendViewDefinitionInterface $view)
724: {
725: $listing = $view->getListingConfig();
726: $listDca = $this->getFromDca('list');
727:
728:
729: if (!$listDca)
730: {
731: return;
732: }
733:
734: $this->parseListSorting($listing, $listDca);
735: $this->parseListLabel($container, $listing, $listDca);
736: }
737:
738: 739: 740: 741: 742: 743: 744: 745: 746: 747: 748: 749: 750: 751:
752: protected function parseListSorting(ListingConfigInterface $listing, array $listDca)
753: {
754: $sortingDca = isset($listDca['sorting']) ? $listDca['sorting'] : array();
755:
756: if (isset($sortingDca['flag']))
757: {
758: $this->evalFlag($listing, $sortingDca['flag']);
759: }
760:
761: if (isset($sortingDca['fields']))
762: {
763: $fields = array();
764:
765: foreach ($sortingDca['fields'] as $field)
766: {
767: if (preg_match('~^(\w+)(?: (ASC|DESC))?$~', $field, $matches))
768: {
769: $fields[$matches[1]] = isset($matches[2]) ? $matches[2] : 'ASC';
770: }
771: else
772: {
773: throw new DcGeneralRuntimeException('Custom SQL in sorting fields are currently unsupported');
774: }
775: }
776:
777: $listing->setDefaultSortingFields($fields);
778: }
779:
780: if (isset($sortingDca['headerFields']))
781: {
782: $listing->setHeaderPropertyNames((array)$sortingDca['headerFields']);
783: }
784:
785: if (isset($sortingDca['icon']))
786: {
787: $listing->setRootIcon($sortingDca['icon']);
788: }
789:
790: if (isset($sortingDca['disableGrouping']) && $sortingDca['disableGrouping'])
791: {
792: $listing->setGroupingMode(ListingConfigInterface::GROUP_NONE);
793: }
794:
795: if (isset($sortingDca['child_record_class']))
796: {
797: $listing->setItemCssClass($sortingDca['child_record_class']);
798: }
799: }
800:
801: 802: 803: 804: 805: 806: 807: 808: 809: 810: 811:
812: protected function parseListLabel(ContainerInterface $container, ListingConfigInterface $listing, array $listDca)
813: {
814: $labelDca = isset($listDca['label']) ? $listDca['label'] : array();
815: $formatter = new DefaultModelFormatterConfig();
816: $configured = false;
817:
818: if (isset($labelDca['fields']))
819: {
820: $formatter->setPropertyNames($labelDca['fields']);
821: $configured = true;
822: }
823:
824: if (isset($labelDca['format']))
825: {
826: $formatter->setFormat($labelDca['format']);
827: $configured = true;
828: }
829:
830: if (isset($labelDca['maxCharacters']))
831: {
832: $formatter->setMaxLength($labelDca['maxCharacters']);
833: $configured = true;
834: }
835:
836: if ($configured)
837: {
838: $listing->setLabelFormatter($container->getBasicDefinition()->getDataProvider(), $formatter);
839: }
840:
841: if (isset($labelDca['showColumns']))
842: {
843: $listing->setShowColumns($labelDca['showColumns']);
844: }
845: }
846:
847: 848: 849: 850: 851: 852: 853:
854: protected function parsePanelFilter(PanelRowInterface $row)
855: {
856: foreach ($this->getFromDca('fields') as $property => $value)
857: {
858: if (isset($value['filter']))
859: {
860: $element = new DefaultFilterElementInformation();
861: $element->setPropertyName($property);
862: if (!$row->hasElement($element->getName()))
863: {
864: $row->addElement($element);
865: }
866: }
867: }
868: }
869:
870: 871: 872: 873: 874: 875: 876:
877: protected function parsePanelSort(PanelRowInterface $row)
878: {
879: if ($row->hasElement('sort'))
880: {
881: $element = $row->getElement('sort');
882: }
883: else
884: {
885: $element = new DefaultSortElementInformation();
886: $row->addElement($element);
887: }
888:
889: foreach ($this->getFromDca('fields') as $property => $value)
890: {
891: if (isset($value['sorting']))
892: {
893: $element->addProperty($property, (int)$value['flag']);
894: }
895: }
896: }
897:
898: 899: 900: 901: 902: 903: 904:
905: protected function parsePanelSearch(PanelRowInterface $row)
906: {
907: if ($row->hasElement('search'))
908: {
909: $element = $row->getElement('search');
910: }
911: else
912: {
913: $element = new DefaultSearchElementInformation();
914: }
915: foreach ($this->getFromDca('fields') as $property => $value)
916: {
917: if (isset($value['search']))
918: {
919: $element->addProperty($property);
920: }
921: }
922: if ($element->getPropertyNames() && !$row->hasElement('search'))
923: {
924: $row->addElement($element);
925: }
926: }
927:
928: 929: 930: 931: 932: 933: 934:
935: protected function parsePanelLimit(PanelRowInterface $row)
936: {
937: if (!$row->hasElement('limit'))
938: {
939: $row->addElement(new DefaultLimitElementInformation());
940: }
941: }
942:
943: 944: 945: 946: 947: 948: 949:
950: protected function parsePanelSubmit(PanelRowInterface $row)
951: {
952: if (!$row->hasElement('submit'))
953: {
954: $row->addElement(new DefaultSubmitElementInformation());
955: }
956: }
957:
958: 959: 960: 961: 962: 963: 964: 965: 966:
967: protected function parsePanelRow(PanelRowInterface $row, $elementList)
968: {
969: foreach (explode(',', $elementList) as $element)
970: {
971: switch ($element)
972: {
973: case 'filter':
974: $this->parsePanelFilter($row);
975: break;
976:
977: case 'sort':
978: $this->parsePanelSort($row);
979: break;
980:
981: case 'search':
982: $this->parsePanelSearch($row);
983: break;
984:
985: case 'limit':
986: $this->parsePanelLimit($row);
987: break;
988:
989: case 'submit':
990: $this->parsePanelSubmit($row);
991: break;
992:
993: default:
994: }
995: }
996: }
997:
998: 999: 1000: 1001: 1002: 1003: 1004:
1005: protected function parsePanel(Contao2BackendViewDefinitionInterface $view)
1006: {
1007: $layout = $view->getPanelLayout();
1008: $rows = $layout->getRows();
1009:
1010: foreach (explode(';', (string)$this->getFromDca('list/sorting/panelLayout')) as $rowNo => $elementRow)
1011: {
1012: if ($rows->getRowCount() < ($rowNo + 1))
1013: {
1014: $row = $rows->addRow();
1015: }
1016: else
1017: {
1018: $row = $rows->getRow($rowNo);
1019: }
1020:
1021: $this->parsePanelRow($row, $elementRow);
1022:
1023: if ($row->getCount() == 0)
1024: {
1025: $rows->deleteRow($rowNo);
1026: }
1027: }
1028:
1029: $hasSubmit = false;
1030: foreach ($rows as $row)
1031: {
1032: foreach ($row as $element)
1033: {
1034: if ($element instanceof SubmitElementInformationInterface)
1035: {
1036: $hasSubmit = true;
1037: break;
1038: }
1039:
1040: if ($hasSubmit)
1041: {
1042: break;
1043: }
1044: }
1045: }
1046:
1047: if (!$hasSubmit && $rows->getRowCount())
1048: {
1049: $row = $rows->getRow($rows->getRowCount() - 1);
1050: $row->addElement(new DefaultSubmitElementInformation(), 0);
1051: }
1052: }
1053:
1054: 1055: 1056: 1057: 1058: 1059: 1060:
1061: protected function parseGlobalOperations(Contao2BackendViewDefinitionInterface $view)
1062: {
1063: $operationsDca = $this->getFromDca('list/global_operations');
1064:
1065: if (!is_array($operationsDca))
1066: {
1067: return;
1068: }
1069:
1070: $collection = $view->getGlobalCommands();
1071:
1072: foreach ($operationsDca as $operationName => $operationDca)
1073: {
1074: $command = $this->createCommand($operationName, $operationsDca[$operationName]);
1075: $collection->addCommand($command);
1076: }
1077: }
1078:
1079: 1080: 1081: 1082: 1083: 1084: 1085:
1086: protected function parseModelOperations(Contao2BackendViewDefinitionInterface $view)
1087: {
1088: $operationsDca = $this->getFromDca('list/operations');
1089:
1090: if (!is_array($operationsDca))
1091: {
1092: return;
1093: }
1094:
1095: $collection = $view->getModelCommands();
1096:
1097: foreach ($operationsDca as $operationName => $operationDca)
1098: {
1099: $command = $this->createCommand($operationName, $operationsDca[$operationName]);
1100: $collection->addCommand($command);
1101: }
1102: }
1103:
1104: 1105: 1106: 1107: 1108: 1109: 1110:
1111: protected function parsePalettes(ContainerInterface $container)
1112: {
1113: $palettesDefinitionArray = $this->getFromDca('palettes');
1114: $subPalettesDefinitionArray = $this->getFromDca('subpalettes');
1115:
1116:
1117: if (!is_array($palettesDefinitionArray))
1118: {
1119: return;
1120: }
1121:
1122:
1123: if (!is_array($subPalettesDefinitionArray))
1124: {
1125: $subPalettesDefinitionArray = array();
1126: }
1127:
1128: if ($container->hasDefinition(PalettesDefinitionInterface::NAME))
1129: {
1130: $palettesDefinition = $container->getDefinition(PalettesDefinitionInterface::NAME);
1131: }
1132: else
1133: {
1134: $palettesDefinition = new DefaultPalettesDefinition();
1135: $container->setDefinition(PalettesDefinitionInterface::NAME, $palettesDefinition);
1136: }
1137:
1138: $palettesParser = new LegacyPalettesParser();
1139: $palettesParser->parse(
1140: $palettesDefinitionArray,
1141: $subPalettesDefinitionArray,
1142: $palettesDefinition
1143: );
1144: }
1145:
1146: 1147: 1148: 1149: 1150: 1151: 1152: 1153: 1154:
1155: protected function parseSinglePropertyLabel(PropertyInterface $property, $label)
1156: {
1157: if (!$property->getLabel())
1158: {
1159: if (is_array($label))
1160: {
1161: $lang = $label;
1162: $label = reset($lang);
1163: $description = next($lang);
1164:
1165: $property->setDescription($description);
1166: }
1167:
1168: $property->setLabel($label);
1169: }
1170: }
1171:
1172: 1173: 1174: 1175: 1176: 1177: 1178: 1179: 1180:
1181:
1182: protected function parseSingleProperty(PropertyInterface $property, array $propInfo)
1183:
1184: {
1185: foreach ($propInfo as $key => $value)
1186: {
1187: switch ($key)
1188: {
1189: case 'label':
1190: $this->parseSinglePropertyLabel($property, $value);
1191: break;
1192:
1193: case 'description':
1194: if (!$property->getDescription())
1195: {
1196: $property->setDescription($value);
1197: }
1198: break;
1199:
1200: case 'default':
1201: if (!$property->getDefaultValue())
1202: {
1203: $property->setDefaultValue($value);
1204: }
1205: break;
1206:
1207: case 'exclude':
1208: $property->setExcluded((bool)$value);
1209: break;
1210:
1211: case 'search':
1212: $property->setSearchable((bool)$value);
1213: break;
1214:
1215: case 'sorting':
1216: $property->setSortable((bool)$value);
1217: break;
1218:
1219: case 'filter':
1220: $property->setFilterable((bool)$value);
1221: break;
1222:
1223: case 'flag':
1224: $this->evalFlag($property, $value);
1225: break;
1226:
1227: case 'length':
1228: $property->setGroupingLength($value);
1229: break;
1230:
1231: case 'inputType':
1232: $property->setWidgetType($value);
1233: break;
1234:
1235: case 'options':
1236: $property->setOptions($value);
1237: break;
1238:
1239: case 'explanation':
1240: $property->setExplanation($value);
1241: break;
1242:
1243: case 'eval':
1244: $property->setExtra($value);
1245: break;
1246:
1247: default:
1248: }
1249: }
1250: }
1251:
1252: 1253: 1254: 1255: 1256: 1257: 1258:
1259: protected function parseProperties(ContainerInterface $container)
1260: {
1261: if ($container->hasPropertiesDefinition())
1262: {
1263: $definition = $container->getPropertiesDefinition();
1264: }
1265: else
1266: {
1267: $definition = new DefaultPropertiesDefinition();
1268: $container->setPropertiesDefinition($definition);
1269: }
1270:
1271: foreach ($this->getFromDca('fields') as $propName => $propInfo)
1272: {
1273: if ($definition->hasProperty($propName))
1274: {
1275: $property = $definition->getProperty($propName);
1276: }
1277: else
1278: {
1279: $property = new DefaultProperty($propName);
1280: $definition->addProperty($property);
1281: }
1282:
1283: $this->parseSingleProperty($property, $propInfo);
1284: }
1285: }
1286:
1287: 1288: 1289: 1290: 1291: 1292: 1293: 1294: 1295:
1296: protected function createCommandInstance($commandName, array $commandDca)
1297: {
1298: switch ($commandName)
1299: {
1300: case 'cut':
1301: return new CutCommand();
1302: default:
1303: return new Command();
1304: }
1305: }
1306:
1307: 1308: 1309: 1310: 1311: 1312: 1313: 1314: 1315:
1316: protected function createCommand($commandName, array $commandDca)
1317: {
1318:
1319: $command = $this->createCommandInstance($commandName, $commandDca);
1320: $command->setName($commandName);
1321:
1322: $parameters = $command->getParameters();
1323:
1324: if (isset($commandDca['href']))
1325: {
1326: parse_str($commandDca['href'], $queryParameters);
1327: foreach ($queryParameters as $name => $value)
1328: {
1329: $parameters[$name] = $value;
1330: }
1331: unset($commandDca['href']);
1332: }
1333:
1334: if (isset($commandDca['parameters']))
1335: {
1336: foreach ($commandDca['parameters'] as $name => $value)
1337: {
1338: $parameters[$name] = $value;
1339: }
1340: unset($commandDca['parameters']);
1341: }
1342:
1343: if (isset($commandDca['label']))
1344: {
1345: $lang = $commandDca['label'];
1346:
1347: if (is_array($lang))
1348: {
1349: $label = reset($lang);
1350: $description = next($lang);
1351:
1352: $command->setDescription($description);
1353: }
1354: else {
1355: $label = $lang;
1356: }
1357:
1358: $command->setLabel($label);
1359:
1360: unset($commandDca['label']);
1361: }
1362:
1363: if (isset($commandDca['description']))
1364: {
1365: $command->setDescription($commandDca['description']);
1366:
1367: unset($commandDca['description']);
1368: }
1369:
1370:
1371: if (isset($commandDca['button_callback']))
1372: {
1373: unset($commandDca['button_callback']);
1374: }
1375:
1376: if (count($commandDca))
1377: {
1378: $extra = $command->getExtra();
1379:
1380: foreach ($commandDca as $name => $value)
1381: {
1382: $extra[$name] = $value;
1383: }
1384: }
1385:
1386: return $command;
1387: }
1388:
1389: 1390: 1391: 1392: 1393: 1394: 1395: 1396: 1397:
1398: protected function evalFlagSorting($config, $flag)
1399: {
1400: if (($flag < 0) || ($flag > 12))
1401: {
1402: return;
1403: }
1404:
1405: if (($flag % 2) == 1)
1406: {
1407: $config->setSortingMode(ListingConfigInterface::SORT_ASC);
1408: }
1409: else
1410: {
1411: $config->setSortingMode(ListingConfigInterface::SORT_DESC);
1412: }
1413: }
1414:
1415: 1416: 1417: 1418: 1419: 1420: 1421: 1422: 1423:
1424: protected function evalFlagGrouping($config, $flag)
1425: {
1426: if (($flag < 0) || ($flag > 12))
1427: {
1428: return;
1429: }
1430:
1431: if ($flag <= 4)
1432: {
1433: $config->setGroupingMode(ListingConfigInterface::GROUP_CHAR);
1434: }
1435: elseif ($flag <= 6)
1436: {
1437: $config->setGroupingMode(ListingConfigInterface::GROUP_DAY);
1438: }
1439: elseif ($flag <= 8)
1440: {
1441: $config->setGroupingMode(ListingConfigInterface::GROUP_MONTH);
1442: }
1443: elseif ($flag <= 10)
1444: {
1445: $config->setGroupingMode(ListingConfigInterface::GROUP_YEAR);
1446: }
1447: else
1448: {
1449: $config->setGroupingMode(ListingConfigInterface::GROUP_NONE);
1450: }
1451: }
1452:
1453: 1454: 1455: 1456: 1457: 1458: 1459: 1460: 1461:
1462: protected function evalFlagGroupingLength($config, $flag)
1463: {
1464: if (($flag == 1) || ($flag == 2))
1465: {
1466: $config->setGroupingLength(1);
1467: }
1468: elseif(($flag == 3) || ($flag == 4))
1469: {
1470: $config->setGroupingLength(2);
1471: }
1472: }
1473:
1474: 1475: 1476: 1477: 1478: 1479: 1480: 1481: 1482:
1483: protected function evalFlag($config, $flag)
1484: {
1485: $this->evalFlagSorting($config, $flag);
1486: $this->evalFlagGrouping($config, $flag);
1487: $this->evalFlagGroupingLength($config, $flag);
1488: }
1489: }
1490: