From 53d563c955de050eed55774fbd4b79d5d2bca53d Mon Sep 17 00:00:00 2001 From: Fanch Date: Tue, 18 Jul 2017 13:02:23 +0200 Subject: [PATCH] Lisem Fix & Features (#39) --- src/Admin/CoreAdmin.php | 70 ++++++++++++++++++- src/Admin/Traits/Mapper.php | 63 ++++++++++++++++- src/CodeGenerator/CodeGeneratorRegistry.php | 16 +++++ src/Resources/public/css/main.css | 3 +- .../public/js/deleteCheckboxCollection.js | 21 ++++++ src/Resources/public/js/tabNavigation.js | 44 ++++++++++++ src/Resources/translations/messages.fr.yml | 2 + src/Resources/views/CRUD/base_edit.html.twig | 6 +- src/Resources/views/standard_layout.html.twig | 1 + 9 files changed, 221 insertions(+), 5 deletions(-) create mode 100644 src/Resources/public/js/deleteCheckboxCollection.js diff --git a/src/Admin/CoreAdmin.php b/src/Admin/CoreAdmin.php index 79c0221..c6bf513 100644 --- a/src/Admin/CoreAdmin.php +++ b/src/Admin/CoreAdmin.php @@ -28,8 +28,10 @@ use Blast\CoreBundle\Admin\Traits\ManyToManyManager; use Blast\CoreBundle\Admin\Traits\Actions; use Blast\CoreBundle\Admin\Traits\ListActions; +use Blast\CoreBundle\CodeGenerator\CodeGeneratorRegistry; +use Symfony\Component\PropertyAccess\PropertyAccess; -abstract class CoreAdmin extends SonataAdmin +abstract class CoreAdmin extends SonataAdmin implements \JsonSerializable { use CollectionsManager, ManyToManyManager, @@ -457,4 +459,70 @@ public function removeAllFieldsFromFormGroup($groupName, $mapper) } } } + + public function jsonSerialize() + { + $propertiesToShow = [ + 'baseRouteName', + 'baseRoutePattern', + 'extraTemplates', + 'listFieldDescriptions', + 'showFieldDescriptions', + 'formFieldDescriptions', + 'filterFieldDescriptions', + 'maxPerPage', + 'maxPageLinks', + 'classnameLabel', + 'translationDomain', + 'formOptions', + 'datagridValues', + 'perPageOptions', + 'pagerType', + 'code', + 'label', + 'routes', + 'subject', + 'children', + 'parent', + 'baseCodeRoute', + 'uniqid', + 'extensions', + 'class', + 'subClasses', + 'list', + 'show', + 'form', + 'filter', + 'formGroups', + 'formTabs', + 'showGroups', + 'showTabs', + 'managedCollections', + 'helperLinks', + 'titles', + ]; + + $properties = []; + foreach ($this as $key => $value) { + if (in_array($key, $propertiesToShow)) { + $properties[$key] = $value; + } + } + + return $properties; + } + + /** + * {@inheritdoc} + */ + public function prePersist($object) + { + $hasCodeGenerator = CodeGeneratorRegistry::hasGeneratorForClass(get_class($object)); + if ($hasCodeGenerator) { + $accessor = PropertyAccess::createPropertyAccessor(); + foreach (CodeGeneratorRegistry::getCodeGenerators(get_class($object)) as $name => $generator) { + $accessor->setValue($object, $name, $generator->generate($object)); + } + } + } } diff --git a/src/Admin/Traits/Mapper.php b/src/Admin/Traits/Mapper.php index b34bccd..5691029 100644 --- a/src/Admin/Traits/Mapper.php +++ b/src/Admin/Traits/Mapper.php @@ -18,6 +18,8 @@ use Sonata\AdminBundle\Mapper\BaseMapper; use Sonata\AdminBundle\Show\ShowMapper; use Symfony\Component\Validator\Constraints\NotBlank; +use Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader; +use Doctrine\ORM\QueryBuilder; trait Mapper { @@ -290,8 +292,7 @@ protected function addContent(BaseMapper $mapper, $group) $endgroup = $endtab = false; // tab - if (!empty($tabcontent['_options']['hideTitle']) || - $mapper instanceof ShowMapper && !$this->forceTabs) { + if (!empty($tabcontent['_options']['hideTitle']) || $mapper instanceof ShowMapper && !$this->forceTabs) { // display tabs as groups $tabs = $this->{$fcts['tabs']['getter']}(); $groups = $this->{$fcts['groups']['getter']}(); @@ -311,6 +312,18 @@ protected function addContent(BaseMapper $mapper, $group) $mapper->tab($tab, isset($tabcontent['_options']) ? $tabcontent['_options'] : []); $endtab = true; } + + // adding count of collections items in tab + if (isset($tabcontent['_options']['countChildItems']) && is_array($tabcontent['_options']['countChildItems'])) { + $tabs = $this->{$fcts['tabs']['getter']}(); + $tabs[$tab]['class'] .= ' countable-tab'; + foreach ($tabcontent['_options']['countChildItems'] as $fieldToCount) { + $tabs[$tab]['class'] .= ' count-' . $fieldToCount; + } + $this->{$fcts['tabs']['setter']}($tabs); + } + + // clearing tabcontent options if (isset($tabcontent['_options'])) { unset($tabcontent['_options']); } @@ -466,6 +479,14 @@ protected function addField(BaseMapper $mapper, $name, $options = [], $fieldDesc $options['constraints'] = [new NotBlank()]; } + if (isset($options['query'])) { + $this->manageQueryCallback($mapper, $options); + } + + if (isset($options['choicesCallback'])) { + $this->manageChoicesCallback($mapper, $options); + } + // save-and-remove CoreBundle-specific options $extras = []; foreach ([ @@ -769,4 +790,42 @@ protected function getBaseRouteMapping() return $baseRoute; } + + protected function manageQueryCallback($mapper, &$options) + { + $query = $options['query']; + $entityClass = $options['class'] ? $options['class'] : $this->getClass(); + + if (!$query instanceof QueryBuilder) { + if (!is_array($query)) { + throw new Exception('« query » option must be an array : ["FQDN"=>"static method name"]'); + } + + list($className, $methodName) = $query; + + $queryFunction = call_user_func($className . '::' . $methodName, $this->getModelManager(), $entityClass); + + $options['query'] = $queryFunction; + } + } + + protected function manageChoicesCallback($mapper, &$options) + { + $callback = $options['choicesCallback']; + $entityClass = $options['class'] ? $options['class'] : $this->getClass(); + + if (!is_array($callback)) { + throw new Exception('« choicesCallback » option must be an array : ["FQDN"=>"static method name"]'); + } + + list($className, $methodName) = $callback; + + $choicesFunction = call_user_func($className . '::' . $methodName, $this->getModelManager(), $entityClass); + + $options['choices'] = $choicesFunction; + $options['choice_loader'] = new CallbackChoiceLoader(function () use ($options) { + return $options['choices']; + }); + unset($options['choicesCallback']); + } } diff --git a/src/CodeGenerator/CodeGeneratorRegistry.php b/src/CodeGenerator/CodeGeneratorRegistry.php index 2c94c10..f40a0f0 100644 --- a/src/CodeGenerator/CodeGeneratorRegistry.php +++ b/src/CodeGenerator/CodeGeneratorRegistry.php @@ -54,6 +54,22 @@ public static function getCodeGenerator($entityClass, $entityField = 'code') return self::$generators[$entityClass][$entityField]; } + /** + * Returns registred code generators for specifyed entity class. + * + * @param string $entityClass + * + * @return array + */ + public static function getCodeGenerators($entityClass) + { + if (!isset(self::$generators[$entityClass])) { + throw new \Exception("There is no registered entity code generator for class $entityClass"); + } + + return self::$generators[$entityClass]; + } + /** * @param string $entityClass * diff --git a/src/Resources/public/css/main.css b/src/Resources/public/css/main.css index e8fde95..f946a6e 100644 --- a/src/Resources/public/css/main.css +++ b/src/Resources/public/css/main.css @@ -1,4 +1,5 @@ .sidebar-form div{ margin: 0 0 3px 0; } .js-i18n, .js-data { display: none; } -.blast-table-label { margin: 6px 0 8px 0; } \ No newline at end of file +.blast-table-label { margin: 6px 0 8px 0; } +.countable-tab span.counter {position: absolute;top:0;right:0;} diff --git a/src/Resources/public/js/deleteCheckboxCollection.js b/src/Resources/public/js/deleteCheckboxCollection.js new file mode 100644 index 0000000..86fc712 --- /dev/null +++ b/src/Resources/public/js/deleteCheckboxCollection.js @@ -0,0 +1,21 @@ +$(document).on('ifChecked','.sonata-ba-field-inline-natural input[type="checkbox"], .sonata-ba-field-inline-table input[type="checkbox"]',function(e) { + var input = $(this); + var name = input.attr('name'); + + if(name.match(/\[[0-9]*\]\[_delete\]/)) { + + var formRow = input.closest('div.sonata-ba-tabs>div'); + + if(formRow.length == 0) { + formRow = input.closest('tr'); + } + + var r = confirm(Translator.trans('librinfo.confirm.delete_collection_item', {}, 'messages')); + if (r == true) { + formRow.remove(); + } else { + // throw exception to avoid checkbox checking + e.dummy(); + } + } +}); diff --git a/src/Resources/public/js/tabNavigation.js b/src/Resources/public/js/tabNavigation.js index 5455335..7bf4fc7 100644 --- a/src/Resources/public/js/tabNavigation.js +++ b/src/Resources/public/js/tabNavigation.js @@ -3,4 +3,48 @@ $(document).ready(function() { var tabName = $(this).attr('data-gototab'); $('li[data-tab-name="' + tabName + '"] a').trigger('click'); }); + + var countCollectionsInTabs = function() { + var countableTabs = $('.countable-tab'); + + countableTabs.each(function(index) { + var tab = $(this); + tab.data('currentCount', 0); + + var countableClasses = $.grep(tab.attr("class").split(' '), function(v) { + return v.match(/count-.*/); + }); + + $.each(countableClasses, function(i, cls) { + var fieldName = cls.replace('count-', ''); + var fieldId = 'field_widget_' + Admin.currentAdmin.uniqid + '_' + fieldName; + + var collectionAsForm = $('#' + fieldId + ' > div.sonata-ba-tabs > div'); + var collectionAsTable = $('#' + fieldId + ' > table > tbody > tr'); + + tab.data('currentCount', parseInt(tab.data('currentCount'), 10) + ( + parseInt(collectionAsForm.length, 10) + + parseInt(collectionAsTable.length, 10) + )); + }); + + var counterItem = tab.find('a > span.counter'); + + if (counterItem.length == 0) { + counterItem = tab.find('a').append( + $('').attr({ + 'class': 'counter' + }) + ).find('.counter'); + } + + counterItem.html(tab.data('currentCount')).attr('data-count',tab.data('currentCount')); + }); + }; + + countCollectionsInTabs(); + + $(document).on('sonata.add_element',function() { + countCollectionsInTabs(); + }); }); diff --git a/src/Resources/translations/messages.fr.yml b/src/Resources/translations/messages.fr.yml index de8fbe3..f4fbdd1 100644 --- a/src/Resources/translations/messages.fr.yml +++ b/src/Resources/translations/messages.fr.yml @@ -4,6 +4,8 @@ librinfo: _action: 'Action' _list_action: 'Action groupée' generate_code: 'Générer le code' + confirm: + delete_collection_item: 'Voulez-vous vraiment supprimer cet élément ?' main_tab.main_group: 'Général' main_tab: 'Général' 'main_group': 'Général' diff --git a/src/Resources/views/CRUD/base_edit.html.twig b/src/Resources/views/CRUD/base_edit.html.twig index 2b200da..6ea85f1 100644 --- a/src/Resources/views/CRUD/base_edit.html.twig +++ b/src/Resources/views/CRUD/base_edit.html.twig @@ -73,7 +73,7 @@