From fc1e5c954f9055e68dccb5476cbba4cb3ff4c331 Mon Sep 17 00:00:00 2001 From: Craig Heydenburg Date: Sat, 12 Dec 2015 20:54:21 -0500 Subject: [PATCH] Refactor BlocksModule and create BlockApi. | Q | A | ----------------- | --- | Bug fix? | yes | New feature? | yes | BC breaks? | no | Deprecations? | yes | Tests pass? | yes! | Fixed tickets | - | Refs tickets | - | License | MIT | Doc PR | included | Changelog updated | yes - Fix module stylesheet not being loaded automatically for Core-2.0 modules. - New advanced block filtering based on a combination of any query parameter or request attributes. - Implement new BlockApi and all corresponding methods. - Added AbstractExtensionInstaller for use by third-party developers. - Added ExtensionVariablesTrait for developers to insert into classes where Extension Variable management is needed. --- .travis.yml | 3 +- CHANGELOG-1.4.md | 12 +- src/docs/Core-2.0/Blocks.md | 43 + .../Traits/ExtensionVariablesTrait.md | 22 + src/docs/Core-2.0/Traits/TranslatorTrait.md | 21 + .../Bundle/CoreBundle/Bundle/Scanner.php | 2 +- .../Theme/ModuleStylesheetInsertListener.php | 59 ++ .../CoreBundle/Resources/config/theme.xml | 7 + .../Twig/Extension/CoreExtension.php | 28 +- .../Controller/AjaxInstallController.php | 25 +- .../Core/AbstractExtensionInstaller.php | 103 ++ src/lib/Zikula/Core/AbstractModule.php | 9 + src/lib/Zikula/Core/AbstractTheme.php | 37 +- .../Zikula/Core/BlockControllerInterface.php | 46 + .../Controller/AbstractBlockController.php | 72 +- .../Core/Controller/AbstractController.php | 64 +- src/lib/Zikula/Core/Theme/Engine.php | 88 +- src/lib/bootstrap.php | 4 +- .../Zikula/Controller/AbstractBlock.php | 6 + src/lib/legacy/Zikula/View/Theme.php | 4 - src/lib/{ => legacy}/util/BlockUtil.php | 72 +- src/lib/legacy/viewplugins/function.block.php | 2 +- src/lib/util/ModUtil.php | 6 +- src/system/BlocksModule/Api/AdminApi.php | 133 +-- src/system/BlocksModule/Api/BlockApi.php | 212 ++++ .../BlocksModule/Api/BlockFactoryApi.php | 100 ++ .../BlocksModule/Api/BlockFilterApi.php | 130 +++ src/system/BlocksModule/Api/UserApi.php | 3 +- .../BlocksModule/Block/ExtmenuBlock.php | 2 +- .../BlocksModule/Block/Form/Type/readme.md | 0 .../BlocksModule/BlocksModuleInstaller.php | 195 ++-- .../BlocksModule/BlocksModuleVersion.php | 75 -- .../BlocksModule/Collector/BlockCollector.php | 65 ++ .../BlocksModule/Container/LinkContainer.php | 118 +++ .../Controller/AdminController.php | 936 ++---------------- .../Controller/AjaxController.php | 125 --- .../Controller/BlockController.php | 286 ++++++ .../Controller/PlacementController.php | 116 +++ .../Controller/PositionController.php | 119 +++ .../Controller/UserController.php | 80 +- .../Compiler/BlockCollectorPass.php | 41 + .../ZikulaBlocksExtension.php | 24 + .../BlocksModule/Entity/BlockEntity.php | 251 +++-- .../Entity/BlockPlacementEntity.php | 106 +- .../Entity/BlockPositionEntity.php | 39 +- .../Repository/BlockPositionRepository.php | 44 + .../Entity/Repository/BlockRepository.php | 56 ++ .../BlockPositionRepositoryInterface.php | 21 + .../BlockRepositoryInterface.php | 20 + .../Form/Type/AdminViewFilterType.php | 84 ++ .../Form/Type/BlockFilterType.php | 66 ++ .../Form/Type/BlockPositionType.php | 47 + .../BlocksModule/Form/Type/BlockType.php | 100 ++ src/system/BlocksModule/Helper/HookHelper.php | 27 + .../BlocksModule/Helper/InstallerHelper.php | 92 ++ .../BlocksModule/Helper/ServiceNameHelper.php | 33 + .../Resources/config/services.xml | 74 ++ .../Resources/public/css/style.css | 9 +- .../public/js/Zikula.Blocks.Admin.Common.js | 19 +- .../public/js/Zikula.Blocks.Admin.Edit.js | 34 + .../js/Zikula.Blocks.Admin.Modifyposition.js | 14 +- .../public/js/Zikula.Blocks.Admin.New.js | 10 + .../public/js/Zikula.Blocks.Admin.View.js | 10 + .../Resources/views/Admin/blockview.html.twig | 1 + .../Resources/views/Admin/config.html.twig | 26 + .../Resources/views/Admin/delete.html.twig | 26 + .../Resources/views/Admin/delete.tpl | 25 - .../Resources/views/Admin/deleteposition.tpl | 25 - .../Resources/views/Admin/edit.html.twig | 68 ++ .../views/Admin/filter_form.html.twig | 16 + .../Resources/views/Admin/modify.tpl | 214 ---- .../Resources/views/Admin/modifyconfig.tpl | 28 - .../Resources/views/Admin/modifyposition.tpl | 113 --- .../Resources/views/Admin/new.html.twig | 30 + .../Resources/views/Admin/newblock.tpl | 90 -- .../Resources/views/Admin/newposition.tpl | 36 - .../Resources/views/Admin/view.html.twig | 122 +++ .../Resources/views/Admin/view.tpl | 143 --- .../Resources/views/Block/Extmenu/extmenu.tpl | 4 +- .../Resources/views/Block/Extmenu/modify.tpl | 1 + .../views/Block/Menutree/bootstrap.tpl | 4 +- .../views/Block/Menutree/bs_hamburger.tpl | 4 +- .../views/Block/Menutree/default.tpl | 4 +- .../views/Block/Menutree/horizontal.tpl | 4 +- .../Resources/views/Block/Menutree/tree.tpl | 4 +- .../views/Block/Menutree/vertical_left.tpl | 4 +- .../views/Block/Menutree/vertical_right.tpl | 4 +- .../views/Block/default_modify.html.twig | 4 + .../Resources/views/Placement/edit.html.twig | 98 ++ .../Resources/views/Position/delete.html.twig | 26 + .../Resources/views/Position/edit.html.twig | 37 + .../BlocksModule/Tests/Api/BlockApiTest.php | 129 +++ .../Tests/Api/BlockFilterApiTest.php | 218 ++++ .../Tests/Api/Fixture/FooBlock.php | 25 + .../Tests/Collector/BlockCollectorTest.php | 91 ++ .../Tests/Helper/Fixture/Block/TestBlock.php | 9 + .../Tests/Helper/InstallerHelperTest.php | 183 ++++ .../Tests/Helper/ServiceNameHelperTest.php | 54 + .../Twig/Extension/BlocksExtension.php | 135 +++ .../BlocksModule/ZikulaBlocksModule.php | 8 + src/system/BlocksModule/composer.json | 27 +- src/system/BlocksModule/phpunit.xml.dist | 2 +- .../Controller/AdminController.php | 2 +- src/system/ExtensionsModule/Api/AdminApi.php | 12 +- .../ExtensionsModule/Api/ExtensionApi.php | 91 ++ .../Entity/ExtensionDependencyEntity.php | 2 +- .../Entity/ExtensionEntity.php | 4 +- .../Entity/Repository/ExtensionRepository.php | 37 + .../ExtensionRepositoryInterface.php | 22 + .../ExtensionVariablesTrait.php | 92 ++ .../ExtensionsModuleInstaller.php | 8 +- .../Resources/config/services.xml | 12 + src/system/ExtensionsModule/Util.php | 5 + .../Entity/Repository/Route.generated.php | 25 - .../Entity/RouteEntity.generated.php | 148 --- src/system/SearchModule/Block/SearchBlock.php | 2 +- src/system/UsersModule/Block/OnlineBlock.php | 2 +- .../Resources/views/admin.html.twig | 2 +- .../views/Include/main_menu.html.twig | 2 +- .../views/Include/adminheader.html.twig | 2 +- 120 files changed, 4607 insertions(+), 2556 deletions(-) create mode 100644 src/docs/Core-2.0/Blocks.md create mode 100644 src/docs/Core-2.0/Traits/ExtensionVariablesTrait.md create mode 100644 src/docs/Core-2.0/Traits/TranslatorTrait.md create mode 100644 src/lib/Zikula/Bundle/CoreBundle/EventListener/Theme/ModuleStylesheetInsertListener.php create mode 100644 src/lib/Zikula/Core/AbstractExtensionInstaller.php create mode 100644 src/lib/Zikula/Core/BlockControllerInterface.php rename src/lib/{ => legacy}/util/BlockUtil.php (90%) create mode 100644 src/system/BlocksModule/Api/BlockApi.php create mode 100644 src/system/BlocksModule/Api/BlockFactoryApi.php create mode 100644 src/system/BlocksModule/Api/BlockFilterApi.php create mode 100644 src/system/BlocksModule/Block/Form/Type/readme.md delete mode 100644 src/system/BlocksModule/BlocksModuleVersion.php create mode 100644 src/system/BlocksModule/Collector/BlockCollector.php create mode 100644 src/system/BlocksModule/Container/LinkContainer.php delete mode 100644 src/system/BlocksModule/Controller/AjaxController.php create mode 100644 src/system/BlocksModule/Controller/BlockController.php create mode 100644 src/system/BlocksModule/Controller/PlacementController.php create mode 100644 src/system/BlocksModule/Controller/PositionController.php create mode 100644 src/system/BlocksModule/DependencyInjection/Compiler/BlockCollectorPass.php create mode 100644 src/system/BlocksModule/DependencyInjection/ZikulaBlocksExtension.php create mode 100644 src/system/BlocksModule/Entity/Repository/BlockPositionRepository.php create mode 100644 src/system/BlocksModule/Entity/Repository/BlockRepository.php create mode 100644 src/system/BlocksModule/Entity/RepositoryInterface/BlockPositionRepositoryInterface.php create mode 100644 src/system/BlocksModule/Entity/RepositoryInterface/BlockRepositoryInterface.php create mode 100644 src/system/BlocksModule/Form/Type/AdminViewFilterType.php create mode 100644 src/system/BlocksModule/Form/Type/BlockFilterType.php create mode 100644 src/system/BlocksModule/Form/Type/BlockPositionType.php create mode 100644 src/system/BlocksModule/Form/Type/BlockType.php create mode 100644 src/system/BlocksModule/Helper/HookHelper.php create mode 100644 src/system/BlocksModule/Helper/InstallerHelper.php create mode 100644 src/system/BlocksModule/Helper/ServiceNameHelper.php create mode 100644 src/system/BlocksModule/Resources/config/services.xml create mode 100644 src/system/BlocksModule/Resources/public/js/Zikula.Blocks.Admin.Edit.js create mode 100644 src/system/BlocksModule/Resources/public/js/Zikula.Blocks.Admin.New.js create mode 100644 src/system/BlocksModule/Resources/public/js/Zikula.Blocks.Admin.View.js create mode 100644 src/system/BlocksModule/Resources/views/Admin/blockview.html.twig create mode 100644 src/system/BlocksModule/Resources/views/Admin/config.html.twig create mode 100644 src/system/BlocksModule/Resources/views/Admin/delete.html.twig delete mode 100644 src/system/BlocksModule/Resources/views/Admin/delete.tpl delete mode 100644 src/system/BlocksModule/Resources/views/Admin/deleteposition.tpl create mode 100644 src/system/BlocksModule/Resources/views/Admin/edit.html.twig create mode 100644 src/system/BlocksModule/Resources/views/Admin/filter_form.html.twig delete mode 100644 src/system/BlocksModule/Resources/views/Admin/modify.tpl delete mode 100644 src/system/BlocksModule/Resources/views/Admin/modifyconfig.tpl delete mode 100644 src/system/BlocksModule/Resources/views/Admin/modifyposition.tpl create mode 100644 src/system/BlocksModule/Resources/views/Admin/new.html.twig delete mode 100644 src/system/BlocksModule/Resources/views/Admin/newblock.tpl delete mode 100644 src/system/BlocksModule/Resources/views/Admin/newposition.tpl create mode 100644 src/system/BlocksModule/Resources/views/Admin/view.html.twig delete mode 100644 src/system/BlocksModule/Resources/views/Admin/view.tpl create mode 100644 src/system/BlocksModule/Resources/views/Block/default_modify.html.twig create mode 100644 src/system/BlocksModule/Resources/views/Placement/edit.html.twig create mode 100644 src/system/BlocksModule/Resources/views/Position/delete.html.twig create mode 100644 src/system/BlocksModule/Resources/views/Position/edit.html.twig create mode 100644 src/system/BlocksModule/Tests/Api/BlockApiTest.php create mode 100644 src/system/BlocksModule/Tests/Api/BlockFilterApiTest.php create mode 100644 src/system/BlocksModule/Tests/Api/Fixture/FooBlock.php create mode 100644 src/system/BlocksModule/Tests/Collector/BlockCollectorTest.php create mode 100644 src/system/BlocksModule/Tests/Helper/Fixture/Block/TestBlock.php create mode 100644 src/system/BlocksModule/Tests/Helper/InstallerHelperTest.php create mode 100644 src/system/BlocksModule/Tests/Helper/ServiceNameHelperTest.php create mode 100644 src/system/BlocksModule/Twig/Extension/BlocksExtension.php create mode 100644 src/system/ExtensionsModule/Api/ExtensionApi.php rename src/{lib/Zikula/Core/Doctrine => system/ExtensionsModule}/Entity/ExtensionDependencyEntity.php (99%) rename src/{lib/Zikula/Core/Doctrine => system/ExtensionsModule}/Entity/ExtensionEntity.php (97%) create mode 100644 src/system/ExtensionsModule/Entity/Repository/ExtensionRepository.php create mode 100644 src/system/ExtensionsModule/Entity/RepositoryInterface/ExtensionRepositoryInterface.php create mode 100644 src/system/ExtensionsModule/ExtensionVariablesTrait.php delete mode 100755 src/system/RoutesModule/Entity/Repository/Route.generated.php delete mode 100755 src/system/RoutesModule/Entity/RouteEntity.generated.php diff --git a/.travis.yml b/.travis.yml index 51996727ff..e49ee6acc0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,5 +50,6 @@ install: # - sudo service apache2 restart # script: - - echo "Nothing to do.. yet!" + - phpunit +# - echo "Nothing to do.. yet!" # - wget -dO - localhost/src diff --git a/CHANGELOG-1.4.md b/CHANGELOG-1.4.md index 18f4ff4e55..ad3768feb5 100644 --- a/CHANGELOG-1.4.md +++ b/CHANGELOG-1.4.md @@ -8,11 +8,17 @@ CHANGELOG - ZIKULA 1.4.x - Deprecated: - n/a - Fixes: - - n/a + - Fix module stylesheet not being loaded automatically for Core-2.0 modules. - Features: - - n/a + - New advanced block filtering based on a combination of any query parameter or request attributes. - Core-2.0 Features: - - n/a + - Implement new BlockApi and all corresponding methods. + - BlockControllerInterface + - AbstractBlockController + - Updated BlocksModule Admin UI. + - BlocksModule updated to Core-2.0 Spec. + - Added AbstractExtensionInstaller for use by third-party developers. + - Added ExtensionVariablesTrait for developers to insert into classes where Extension Variable management is needed. - Vendor updates: - Symfony updated to 2.8.0 - Font-Awesome updated to 4.5.0 diff --git a/src/docs/Core-2.0/Blocks.md b/src/docs/Core-2.0/Blocks.md new file mode 100644 index 0000000000..619c3c340c --- /dev/null +++ b/src/docs/Core-2.0/Blocks.md @@ -0,0 +1,43 @@ +Blocks +====== + + - Block classnames should be suffixed by `Block` and located in the `ModuleRoot/Block/` directory. + - Block classes must implement Zikula\Core\BlockControllerInterface. + - Zikula\Core\Controller\AbstractBlockController is available if desired. + - Blocks must register their PermissionSchema as part of the owning module's array (in composer.json) + - The old "info" array of the block has been eliminated. + - `module` is inferred from providing module. + - `text_type` is replaced by `getType()`. + - `allow_multiple` is always `true`. + - `form_content` is no longer allowed (blocks MUST implement their own content control). + - The `init` method has been eliminated. + - `$content` parameter in both the `modify` and `display` method is un-serialized content property from BlockEntity. + - The `modify` method is expected to handle both the form and processing of the form (like a typical entity controller). + - The modify method _should_ implement a symfony form handling the data as an array. + - A simple Twig template is available as a default `ZikulaBlocksModule:Block:default_modify.html.twig`. + - if you implement your own modify template, **do not** render the `form_start(form)` or `form_end(form)` + tags within your template. + + +Block as a Service +------------------ + +Registering your block class as a service is optional, but can provide greater flexibility with dependencies. If a class +simply extends `AbstractBlockController`, it is not required to register the class as a service. Additionally, if a +class implements `BlockControllerInterface` and requires no construction arguments, registering as a service is +not required. + +If you choose to register your block as a service, you must tag your block service with the following tag: + + + +The 'CommonModuleName' is the 'camel-cased' bundle name. + + +Block Filters +------------- + +A powerful new filter mechanism has been implemented for blocks. For any block you can set up your own filters based on +nearly any request attribute or query parameter. These can also be used in any combination. As long as all +filter conditions evaluate to **true** the block will be displayed. Conditions can be compared using any available +comparator: not just `==`, but `!=`, `in_array()` and others. Array values must be a comma-delimited string. \ No newline at end of file diff --git a/src/docs/Core-2.0/Traits/ExtensionVariablesTrait.md b/src/docs/Core-2.0/Traits/ExtensionVariablesTrait.md new file mode 100644 index 0000000000..ea688da24e --- /dev/null +++ b/src/docs/Core-2.0/Traits/ExtensionVariablesTrait.md @@ -0,0 +1,22 @@ +ExtensionVariablesTrait +======================= + +name: \Zikula\ExtensionsModule\ExtensionVariablesTrait + +Adds the following methods to your class: + + - getVar($variableName, $default = false) + - getVars() + - setVar($variableName, $value = '') + - setVars(array $variables) + - delVar($variableName) + - delVars() + +In your constructor, you are required to set the following properties included in the trait: + + - $variableApi + - Must be set to the "zikula_extensions_module.api.variable" service + - $extensionName + - Must be set to the "common name" of the extension (e.g. "ZikulaBlocksModule") + +See \Zikula\Core\AbstractExtensionInstaller for usage example. \ No newline at end of file diff --git a/src/docs/Core-2.0/Traits/TranslatorTrait.md b/src/docs/Core-2.0/Traits/TranslatorTrait.md new file mode 100644 index 0000000000..5065b223aa --- /dev/null +++ b/src/docs/Core-2.0/Traits/TranslatorTrait.md @@ -0,0 +1,21 @@ +TranslatorTrait +=============== + +name: \Zikula\Common\Translator\TranslatorTrait + +Adds the following methods to your class: + + - \__($msg, $domain = null, $locale = null) + - _n($m1, $m2, $n, $domain = null, $locale = null) + - \__f($msg, $param, $domain = null, $locale = null) + - _fn($m1, $m2, $n, $param, $domain = null, $locale = null) + - getTranslator() + +_note: if you are reading this unrendered, the slash characters above are not part of the method name. they are escape +characters for the renderer._ + +You are required to implement a public method `setTranslator($translator)`. +In your constructor, you are required to call the `setTranslator()` method and set the `$translator` property. +Typically this will be set to the `'translator'` service. + +See \Zikula\Core\AbstractExtensionInstaller for usage example. \ No newline at end of file diff --git a/src/lib/Zikula/Bundle/CoreBundle/Bundle/Scanner.php b/src/lib/Zikula/Bundle/CoreBundle/Bundle/Scanner.php index 67452d307b..b8a0127475 100644 --- a/src/lib/Zikula/Bundle/CoreBundle/Bundle/Scanner.php +++ b/src/lib/Zikula/Bundle/CoreBundle/Bundle/Scanner.php @@ -74,7 +74,7 @@ public function decode($file) $json['autoload']['psr-4'][$ns] = $path; } $json['extra']['zikula']['short-name'] = substr($class, strrpos($class, '\\') + 1, strlen($class)); - $json['extensionType'] = strpos($base, 'system') ? \ModUtil::TYPE_SYSTEM : \ModUtil::TYPE_MODULE; + $json['extensionType'] = false !== strpos($base, 'system') ? \ModUtil::TYPE_SYSTEM : \ModUtil::TYPE_MODULE; return $json; } diff --git a/src/lib/Zikula/Bundle/CoreBundle/EventListener/Theme/ModuleStylesheetInsertListener.php b/src/lib/Zikula/Bundle/CoreBundle/EventListener/Theme/ModuleStylesheetInsertListener.php new file mode 100644 index 0000000000..c1fbb375dc --- /dev/null +++ b/src/lib/Zikula/Bundle/CoreBundle/EventListener/Theme/ModuleStylesheetInsertListener.php @@ -0,0 +1,59 @@ +kernel = $kernel; + } + + /** + * Add the module stylesheet to the page assets. + * @param FilterControllerEvent $event + * @throws \Twig_Error_Loader + */ + public function insertModuleStylesheet(FilterControllerEvent $event) + { + if (!$event->isMasterRequest()) { + return; + } + $controller = $event->getController()[0]; + if ($controller instanceof AbstractController) { + $module = $this->kernel->getModule($controller->getName()); + $module->addStylesheet(); + } + } + + public static function getSubscribedEvents() + { + return array( + KernelEvents::CONTROLLER => array( + array('insertModuleStylesheet'), + ), + ); + } +} diff --git a/src/lib/Zikula/Bundle/CoreBundle/Resources/config/theme.xml b/src/lib/Zikula/Bundle/CoreBundle/Resources/config/theme.xml index 77b47e71e9..e330e50529 100644 --- a/src/lib/Zikula/Bundle/CoreBundle/Resources/config/theme.xml +++ b/src/lib/Zikula/Bundle/CoreBundle/Resources/config/theme.xml @@ -12,6 +12,7 @@ Zikula\Bundle\CoreBundle\EventListener\Theme\DefaultPageVarSetterListener Zikula\Bundle\CoreBundle\EventListener\Theme\ControllerAnnotationReaderListener Zikula\Bundle\CoreBundle\EventListener\Theme\TemplatePathOverrideListener + Zikula\Bundle\CoreBundle\EventListener\Theme\ModuleStylesheetInsertListener Zikula\Core\Theme\AssetBag Zikula\Core\Theme\AssetBag Zikula\Core\Theme\AssetBag @@ -35,6 +36,7 @@ + @@ -74,6 +76,11 @@ + + + + + diff --git a/src/lib/Zikula/Bundle/CoreBundle/Twig/Extension/CoreExtension.php b/src/lib/Zikula/Bundle/CoreBundle/Twig/Extension/CoreExtension.php index 3c19e6d1fd..548f1b209b 100644 --- a/src/lib/Zikula/Bundle/CoreBundle/Twig/Extension/CoreExtension.php +++ b/src/lib/Zikula/Bundle/CoreBundle/Twig/Extension/CoreExtension.php @@ -17,6 +17,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; use Zikula\Bundle\CoreBundle\Twig; use Zikula\Bundle\CoreBundle\Twig\Extension\SimpleFunction\AdminMenuPanelSimpleFunction; +use Zikula\Core\AbstractModule; use Zikula\Core\Theme\AssetBag; class CoreExtension extends \Twig_Extension @@ -70,9 +71,6 @@ public function getFunctions() new \Twig_SimpleFunction('icon', [$this, 'icon']), new \Twig_SimpleFunction('lang', [$this, 'lang']), new \Twig_SimpleFunction('langdirection', [$this, 'langDirection']), - new \Twig_SimpleFunction('showblockposition', [$this, 'showBlockPosition'], array('is_safe' => array('html'))), - new \Twig_SimpleFunction('showblock', [$this, 'showBlock']), - new \Twig_SimpleFunction('blockinfo', [$this, 'getBlockInfo']), new \Twig_SimpleFunction('zasset', [$this, 'getAssetPath']), new \Twig_SimpleFunction('showflashes', [$this, 'showFlashes'], array('is_safe' => array('html'))), new \Twig_SimpleFunction('array_unset', [$this, 'arrayUnset']), @@ -100,30 +98,6 @@ public function getAssetPath($path) return $this->container->get('zikula_core.common.theme.asset_helper')->resolve($path); } - public function showBlockPosition($name, $implode = true) - { - return \BlockUtil::displayPosition($name, false, $implode); - } - - public function getBlockInfo($bid = 0, $name = null) - { - // get the block info array - $blockinfo = \BlockUtil::getBlockInfo($bid); - - if ($name) { - return $blockinfo[$name]; - } - } - - public function showBlock($block, $blockname, $module) - { - if (!is_array($block)) { - $block = \BlockUtil::getBlockInfo($block); - } - - return \BlockUtil::show($module, $blockname, $block); - } - /** * Function to get the site's language. * diff --git a/src/lib/Zikula/Bundle/CoreInstallerBundle/Controller/AjaxInstallController.php b/src/lib/Zikula/Bundle/CoreInstallerBundle/Controller/AjaxInstallController.php index 8d0f227851..6b7db7398a 100644 --- a/src/lib/Zikula/Bundle/CoreInstallerBundle/Controller/AjaxInstallController.php +++ b/src/lib/Zikula/Bundle/CoreInstallerBundle/Controller/AjaxInstallController.php @@ -14,6 +14,7 @@ namespace Zikula\Bundle\CoreInstallerBundle\Controller; +use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\JsonResponse; @@ -156,8 +157,23 @@ public function installModule($moduleName) if (file_exists($bootstrap)) { include_once $bootstrap; } - $instance = new $className($this->container, $module); - if ($instance->install()) { + + // support both Legacy and Core-2.0 Spec system modules until fully refactored. + // @todo remove legacy support when refactoring is complete. + $reflectionInstaller = new \ReflectionClass($className); + if ($reflectionInstaller->isSubclassOf('Zikula_AbstractInstaller')) { + $installer = $reflectionInstaller->newInstanceArgs(array($this->container, $module)); + } elseif ($reflectionInstaller->isSubclassOf('\Zikula\Core\ExtensionInstallerInterface')) { + $installer = $reflectionInstaller->newInstance(); + $installer->setBundle($module); + if ($installer instanceof ContainerAwareInterface) { + $installer->setContainer($this->container); + } + } else { + throw new \Exception('Installer class must be subclass of Zikula_AbstractInstaller or implement Zikula\Core\ExtensionInstallerInterface.'); + } + + if ($installer->install()) { return true; } @@ -218,9 +234,10 @@ private function categorizeModules() private function createBlocks() { + $installer = new \Zikula\BlocksModule\BlocksModuleInstaller(); + $installer->setBundle($this->container->get('kernel')->getModule('ZikulaBlocksModule')); // create the default blocks. - $blockInstance = new \Zikula\BlocksModule\BlocksModuleInstaller($this->container, $this->container->get('kernel')->getModule('ZikulaBlocksModule')); - $blockInstance->defaultdata(); + $installer->defaultdata(); return true; } diff --git a/src/lib/Zikula/Core/AbstractExtensionInstaller.php b/src/lib/Zikula/Core/AbstractExtensionInstaller.php new file mode 100644 index 0000000000..5baca46605 --- /dev/null +++ b/src/lib/Zikula/Core/AbstractExtensionInstaller.php @@ -0,0 +1,103 @@ +bundle = $bundle; + $this->name = $bundle->getName(); + $this->container = $bundle->getContainer(); + $this->container->get('translator')->setDomain($this->bundle->getTranslationDomain()); + $this->setTranslator($this->container->get('translator')); + $this->entityManager = $this->container->get('doctrine.entitymanager'); + $this->schemaTool = $this->container->get('zikula.doctrine.schema_tool'); + $this->extensionName = $this->name; // for ExtensionVariablesTrait + $this->variableApi = $bundle->getContainer()->get('zikula_extensions_module.api.variable'); // for ExtensionVariablesTrait + } + + public function setTranslator($translator) + { + $this->translator = $translator; + } + + /** + * Convenience shortcut to add a session flash message. + * @param $type + * @param $message + */ + public function addFlash($type, $message) + { + if (!$this->container->has('session')) { + throw new \LogicException('You can not use the addFlash method if sessions are disabled.'); + } + + $this->container->get('session')->getFlashBag()->add($type, $message); + } +} \ No newline at end of file diff --git a/src/lib/Zikula/Core/AbstractModule.php b/src/lib/Zikula/Core/AbstractModule.php index 30d9390412..a32f2ab94e 100644 --- a/src/lib/Zikula/Core/AbstractModule.php +++ b/src/lib/Zikula/Core/AbstractModule.php @@ -3,6 +3,7 @@ namespace Zikula\Core; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Zikula\Core\Theme\AssetBag; abstract class AbstractModule extends AbstractBundle { @@ -13,6 +14,14 @@ public function getNameType() return 'Module'; } + public function addStylesheet($name = 'style.css') + { + $moduleStylesheet = $this->getContainer()->get('zikula_core.common.theme.asset_helper')->resolve('@' . $this->getName() . ":css/$name"); + if (!empty($moduleStylesheet)) { + $this->container->get('zikula_core.common.theme.assets_css')->add([$moduleStylesheet => AssetBag::WEIGHT_DEFAULT]); + } + } + // /** // * @return ModuleInstallerInterface // */ diff --git a/src/lib/Zikula/Core/AbstractTheme.php b/src/lib/Zikula/Core/AbstractTheme.php index 8b5190a437..4e8bc46b95 100644 --- a/src/lib/Zikula/Core/AbstractTheme.php +++ b/src/lib/Zikula/Core/AbstractTheme.php @@ -51,37 +51,34 @@ public function generateThemedResponse($realm, Response $response) { $template = $this->config[$realm]['page']; - // @todo NOTE: 'pagetype' is temporary var in the template - return $this->getContainer()->get('templating')->renderResponse($this->name . ':' . $template, array('maincontent' => $response->getContent(), 'pagetype' => 'admin')); + return $this->getContainer()->get('templating')->renderResponse($this->name . ':' . $template, array('maincontent' => $response->getContent())); } /** * convert the block content to a theme-wrapped Response * @param string $realm - * @param array $block + * @param $positionName + * @param string $blockContent + * @param $blockTitle * @return string */ - public function generateThemedBlock($realm, array $block) + public function generateThemedBlockContent($realm, $positionName, $blockContent, $blockTitle) { - if (isset($this->config[$realm]['block']['positions'][$block['position']])) { - $template = $this->name . ':' . $this->config[$realm]['block']['positions'][$block['position']]; + if (isset($this->config[$realm]['block']['positions'][$positionName])) { + $template = $this->name . ':' . $this->config[$realm]['block']['positions'][$positionName]; } else { - // block position not defined. - // @todo return with no content, throw an exception or provide a default block? - // for now, provide a default + // block position not defined, provide a default template $template = 'CoreBundle:Default:block.html.twig'; } - $content = $this->getContainer()->get('templating')->render($template, $block); // @todo renderView? renderResponse? - // wrap block with unique div - $position = !empty($block['position']) ? $block['position'] : 'none'; - $content = '
' . "\n" - . $content - . "
\n"; - - return $content; + + $templateParameters = [ + 'title' => $blockTitle, + 'content' => $blockContent + ]; + // @todo add collapsable block code see \BlockUtil::themeBlock + // @todo including check for `isCollapsed` like \BlockUtil::checkUserBlock + + return $this->getContainer()->get('templating')->render($template, $templateParameters); } /** diff --git a/src/lib/Zikula/Core/BlockControllerInterface.php b/src/lib/Zikula/Core/BlockControllerInterface.php new file mode 100644 index 0000000000..72168d9138 --- /dev/null +++ b/src/lib/Zikula/Core/BlockControllerInterface.php @@ -0,0 +1,46 @@ +request->get('content', ''); + } /** - * Modify block interface. - * - * @param array $blockInfo Block info. - * - * @return string + * Display the block content. + * @param array|string $content + * @return array|string */ - public function modify($blockInfo) + public function display($content) { - return ''; + return $content; } /** - * Update block interface. - * - * @param array $blockInfo Block info. - * - * @return array blockInfo. + * Get the type of the block (e.g. the 'name'). + * @return string */ - public function update($blockInfo) + public function getType() { - return $blockInfo; - } + // default to the ClassName without the `Block` suffix + // note: This string is intentionally left untranslated. + $fqCn = get_class($this); + $pos = strrpos($fqCn, '\\'); + return substr($fqCn, $pos + 1, -5); + } } diff --git a/src/lib/Zikula/Core/Controller/AbstractController.php b/src/lib/Zikula/Core/Controller/AbstractController.php index 8558c48e21..a26f471194 100644 --- a/src/lib/Zikula/Core/Controller/AbstractController.php +++ b/src/lib/Zikula/Core/Controller/AbstractController.php @@ -19,10 +19,12 @@ use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Zikula\Common\Translator\TranslatorTrait; use Zikula\Core\AbstractBundle; +use Zikula\ExtensionsModule\ExtensionVariablesTrait; abstract class AbstractController extends Controller { use TranslatorTrait; + use ExtensionVariablesTrait; /** * @var string @@ -39,6 +41,8 @@ abstract class AbstractController extends Controller public function __construct(AbstractBundle $bundle) { $this->name = $bundle->getName(); + $this->extensionName = $this->name; // for ExtensionVariablesTrait + $this->variableApi = $bundle->getContainer()->get('zikula_extensions_module.api.variable'); // for ExtensionVariablesTrait $this->setTranslator($bundle->getContainer()->get('translator')); $this->translator->setDomain($bundle->getTranslationDomain()); $this->boot($bundle); @@ -172,66 +176,6 @@ public function setTranslator($translator) $this->translator = $translator; } - /** - * Convenience shortcut to get Extension Variable. - * @param string $variableName - * @param mixed $default - * @return mixed - */ - public function getVar($variableName, $default = false) - { - return $this->container->get('zikula_extensions_module.api.variable')->get($this->name, $variableName, $default); - } - - /** - * Convenience shortcut to get all Extension Variables. - * @return array - */ - public function getVars() - { - return $this->container->get('zikula_extensions_module.api.variable')->getAll($this->name); - } - - /** - * Convenience shortcut to set Extension Variable. - * @param string $variableName - * @param string $value - * @return bool - */ - public function setVar($variableName, $value = '') - { - return $this->container->get('zikula_extensions_module.api.variable')->set($this->name, $variableName, $value); - } - - /** - * Convenience shortcut to set many Extension Variables. - * @param array $variables - * @return bool - */ - public function setVars(array $variables) - { - return $this->container->get('zikula_extensions_module.api.variable')->setAll($this->name, $variables); - } - - /** - * Convenience shortcut to delete an Extension Variable. - * @param $variableName - * @return bool - */ - public function delVar($variableName) - { - return $this->container->get('zikula_extensions_module.api.variable')->del($this->name, $variableName); - } - - /** - * Convenience shortcut to delete all Extension Variables. - * @return bool - */ - public function delVars() - { - return $this->container->get('zikula_extensions_module.api.variable')->delAll($this->name); - } - /** * Convenience shortcut to check if user has requested permissions. * @param null $component diff --git a/src/lib/Zikula/Core/Theme/Engine.php b/src/lib/Zikula/Core/Theme/Engine.php index ecb8d598f6..7a0d32ec90 100644 --- a/src/lib/Zikula/Core/Theme/Engine.php +++ b/src/lib/Zikula/Core/Theme/Engine.php @@ -18,6 +18,7 @@ use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Doctrine\Common\Annotations\Reader; +use Zikula\BlocksModule\Api\BlockApi; use Zikula\Bundle\CoreBundle\HttpKernel\ZikulaKernel; /** @@ -79,14 +80,20 @@ class Engine */ private $filterService; + /** + * @var BlockApi + */ + private $blockApi; + /** * Engine constructor. * @param RequestStack $requestStack * @param Reader $annotationReader * @param ZikulaKernel $kernel - * @param \Zikula\Core\Theme\Filter $filter + * @param Filter $filter + * @param BlockApi $blockApi */ - public function __construct(RequestStack $requestStack, Reader $annotationReader, ZikulaKernel $kernel, $filter) + public function __construct(RequestStack $requestStack, Reader $annotationReader, ZikulaKernel $kernel, $filter, BlockApi $blockApi) { $this->annotationReader = $annotationReader; $this->kernel = $kernel; @@ -94,6 +101,7 @@ public function __construct(RequestStack $requestStack, Reader $annotationReader if (null !== $requestStack->getCurrentRequest()) { $this->setRequestAttributes($requestStack->getCurrentRequest()); } + $this->blockApi = $blockApi; } /** @@ -139,20 +147,62 @@ public function wrapResponseInTheme(Response $response) } /** - * Wrap a block in the theme's block template. - * @api Core-2.0 - * @todo consider changing block to a Response - * @param array $block - * @return bool|string (false if theme is not twigBased) + * BC method to wrap a block in the theme's block template if theme is twig-based. + * @deprecated + * @param array $blockInfo + * @return string */ - public function wrapBlockInTheme(array $block) + public function wrapBcBlockInTheme(array $blockInfo) { // @todo remove twigBased check in 2.0 if (!isset($this->activeThemeBundle) || !$this->activeThemeBundle->isTwigBased()) { return false; } + $position = !empty($blockInfo['position']) ? $blockInfo['position'] : 'none'; + $content = $this->activeThemeBundle->generateThemedBlockContent($this->getRealm(), $position, $blockInfo['content'], $blockInfo['title']); + + return $content; + } + + /** + * Wrap the block content in the theme block template and wrap that with a unique div. + * @api Core-2.0 + * @param string $content + * @param string $title + * @param string $blockType + * @param integer $bid + * @param string $positionName + * @param bool $legacy @deprecated param + * @return Response + */ + public function wrapBlockContentInTheme($content, $title, $blockType, $bid, $positionName, $legacy) + { + if (!$legacy) { + // legacy blocks are already themed at this point. @todo at Core-2.0 remove $legacy param and this check. + $content = $this->activeThemeBundle->generateThemedBlockContent($this->getRealm(), $positionName, $content, $title); + } + + // always wrap the block (in the previous versions this was configurable, but no longer) @todo remove comment + return $this->wrapBlockContentWithUniqueDiv($content, $positionName, $blockType, $bid); + } - return $this->activeThemeBundle->generateThemedBlock($this->getRealm(), $block); + /** + * Enclose themed block content in a unique div which is useful in applying styling. + * + * @param string $content + * @param string $positionName + * @param string $blockType + * @param integer $bid + * @return string + */ + private function wrapBlockContentWithUniqueDiv($content, $positionName, $blockType, $bid) + { + return '
' . "\n" + . $content + . "
\n"; } /** @@ -238,6 +288,26 @@ public function changeThemeByAnnotation($controllerClassName, $method) return false; } + /** + * @param $name + * @return bool + */ + public function positionIsAvailableInTheme($name) { + $config = $this->activeThemeBundle->getConfig(); + if (empty($config)) { + + return true; + } + foreach ($config as $realm => $definition) { + if (isset($definition['block']['positions'][$name])) { + + return true; + } + } + + return false; + } + /** * Find the realm in the theme.yml that matches the given path, route or module. * Three 'alias' realms may be defined and do not require a pattern: diff --git a/src/lib/bootstrap.php b/src/lib/bootstrap.php index 8870ea4d5f..ecf893eb5e 100644 --- a/src/lib/bootstrap.php +++ b/src/lib/bootstrap.php @@ -25,6 +25,8 @@ class_alias('\Zikula\CategoriesModule\Entity\CategoryEntity', '\Zikula\Module\CategoriesModule\Entity\CategoryEntity', true); class_alias('\Zikula\UsersModule\Entity\UserEntity', '\Zikula\Module\UsersModule\Entity\UserEntity', true); class_alias('\Zikula\ExtensionsModule\Entity\ExtensionVarEntity', '\Zikula\Core\Doctrine\Entity\ExtensionVarEntity', true); +class_alias('\Zikula\ExtensionsModule\Entity\ExtensionEntity', '\Zikula\Core\Doctrine\Entity\ExtensionEntity', true); +class_alias('\Zikula\ExtensionsModule\Entity\ExtensionDependencyEntity', '\Zikula\Core\Doctrine\Entity\ExtensionDependencyEntity', true); $kernelConfig = Yaml::parse(file_get_contents(__DIR__.'/../app/config/parameters.yml')); if (is_readable($file = __DIR__.'/../app/config/custom_parameters.yml')) { @@ -33,7 +35,7 @@ class_alias('\Zikula\ExtensionsModule\Entity\ExtensionVarEntity', '\Zikula\Core\ $kernelConfig = $kernelConfig['parameters']; if ($kernelConfig['env'] !== 'prod') { // hide deprecation errors - // TODO remove exclusions for 2.0 + // @todo remove exclusions for Core-2.0 Debug::enable(E_ALL & ~E_USER_DEPRECATED); } diff --git a/src/lib/legacy/Zikula/Controller/AbstractBlock.php b/src/lib/legacy/Zikula/Controller/AbstractBlock.php index a26b26b8df..7a789f7cce 100644 --- a/src/lib/legacy/Zikula/Controller/AbstractBlock.php +++ b/src/lib/legacy/Zikula/Controller/AbstractBlock.php @@ -15,6 +15,7 @@ /** * Abstract controller for blocks. + * @deprecated */ abstract class Zikula_Controller_AbstractBlock extends Zikula_AbstractController { @@ -85,4 +86,9 @@ public function __call($method, $args) throw new BadMethodCallException(__f('%1$s::%2$s() does not exist.', array(get_class($this), $method))); } + + public function getType() + { + return $this->info()['text_type']; + } } diff --git a/src/lib/legacy/Zikula/View/Theme.php b/src/lib/legacy/Zikula/View/Theme.php index d40a6a6718..d42d8a0eea 100644 --- a/src/lib/legacy/Zikula/View/Theme.php +++ b/src/lib/legacy/Zikula/View/Theme.php @@ -419,10 +419,6 @@ public function themesidebox($block) // HACK: Save/restore cache settings $this->caching = $caching; - if ((bool)$this->themeconfig['blockwrapper']) { - $return = '
' . "\n" . $return . "
\n"; - } - return $return; } diff --git a/src/lib/util/BlockUtil.php b/src/lib/legacy/util/BlockUtil.php similarity index 90% rename from src/lib/util/BlockUtil.php rename to src/lib/legacy/util/BlockUtil.php index 678a8f467e..551fe42f2b 100644 --- a/src/lib/util/BlockUtil.php +++ b/src/lib/legacy/util/BlockUtil.php @@ -12,10 +12,11 @@ * information regarding copyright and licensing. */ -use \Zikula\Core\Controller\AbstractBlockController; +use Zikula\Core\Controller\AbstractBlockController; /** * Block util. + * @deprecated remove at Core-2.0 */ class BlockUtil { @@ -141,12 +142,19 @@ public static function displayPosition($side, $echo = true, $implode = true) } } $blockinfo['position'] = $positions[$side]['name']; + $blockinfo['mid'] = $blockinfo['module']['id']; // get the module info and display the block $modinfo = ModUtil::getInfo($blockinfo['mid']); + $blockOutput = self::show($modinfo['name'], $blockinfo['bkey'], $blockinfo, $blockplacement->getBlock()); + // wrap block if theme requires it. + $blockWrapper = (bool) Zikula_View_Theme::getInstance()->themeconfig['blockwrapper']; + if ($blockWrapper) { + $blockOutput = '
' . "\n" . $blockOutput . "
\n"; + } if ($echo) { - echo self::show($modinfo['name'], $blockinfo['bkey'], $blockinfo); + echo $blockOutput; } else { - $blockoutput[$blockinfo['bid']] = self::show($modinfo['name'], $blockinfo['bkey'], $blockinfo); + $blockoutput[$blockinfo['bid']] = $blockOutput; } } if ($echo) { @@ -163,24 +171,31 @@ public static function displayPosition($side, $echo = true, $implode = true) /** * Show a block. * - * @param string $modname Module name. + * @param string $modname Module name. * @param string $blockname Name of the block. - * @param array $blockinfo Information parameters. - * + * @param array $blockinfo Information parameters. + * @param null $blockEntity * @return mixed Blockinfo array or null. */ - public static function show($modname, $blockname, $blockinfo = array()) + public static function show($modname, $blockname, $blockinfo = array(), $blockEntity = null) { global $blocks_modules; + $content = ''; $blockInstance = self::load($modname, $blockname); $displayfunc = array($blockInstance, 'display'); + $blockEntity = isset($blockEntity) ? $blockEntity : ServiceUtil::get('doctrine.entitymanager')->find('Zikula\BlocksModule\Entity\BlockEntity', $blockinfo['bid']); + $instanceArgs = ($blockInstance instanceof AbstractBlockController) ? $blockEntity->getContent() : $blockinfo; if (is_callable($displayfunc)) { - if (is_array($displayfunc)) { - return call_user_func($displayfunc, $blockinfo); - } else { - return $displayfunc($blockinfo); - } + $content = call_user_func($displayfunc, $instanceArgs); } + if ($blockInstance instanceof AbstractBlockController) + { + // FC blocks require wrapping the content in the theme + $blockinfo['content'] = $content; + $content = Zikula_View_Theme::getInstance()->themesidebox($blockinfo); + } + + return $content; } /** @@ -259,7 +274,7 @@ public static function themeBlock($blockinfo) // try twig theme first (note: theme is already set by this point) $container = ServiceUtil::getManager(); - $twigBasedThemeBlock = $container->get('zikula_core.common.theme_engine')->wrapBlockInTheme($blockinfo); + $twigBasedThemeBlock = $container->get('zikula_core.common.theme_engine')->wrapBcBlockInTheme($blockinfo); if ($twigBasedThemeBlock) { return $twigBasedThemeBlock; } @@ -396,30 +411,8 @@ public static function loadAll() */ public static function varsFromContent($content) { - // Try to unserialize first - if (DataUtil::is_serialized($content, false)) { - // Serialised content - $vars = unserialize($content); - - if ($vars !== false && is_array($vars)) { - return $vars; - } - } - - // Unserialised content - $links = explode("\n", $content); - $vars = array(); - foreach ($links as $link) { - $link = trim($link); - if ($link) { - $var = explode(':=', $link); - if (isset($var[1])) { - $vars[$var[0]] = $var[1]; - } - } - } - - return $vars; + // content is now automatically unserialized at the entity level + return $content; } /** @@ -431,7 +424,8 @@ public static function varsFromContent($content) */ public static function varsToContent($vars) { - return (serialize($vars)); + // content is now automatically serialized at the entity level + return $vars; } /** @@ -490,9 +484,11 @@ public static function getBlockInfo($value, $assocKey = 'bid') if (!isset($blockinfo[$assocKey]) || empty($blockinfo[$assocKey])) { $blockinfo[$assocKey] = array(); $blocks = self::getBlocksInfo(); + /** @var \Zikula\BlocksModule\Entity\BlockEntity $block */ foreach ($blocks as $block) { $key = $block[$assocKey]; $blockinfo[$assocKey][$key] = $block->toArray(); + $blockinfo[$assocKey][$key]['bkey'] = $block->getBlocktype(); } } if (isset($blockinfo[$assocKey][$value])) { diff --git a/src/lib/legacy/viewplugins/function.block.php b/src/lib/legacy/viewplugins/function.block.php index 4b67c40fbd..1a75e58c12 100644 --- a/src/lib/legacy/viewplugins/function.block.php +++ b/src/lib/legacy/viewplugins/function.block.php @@ -99,7 +99,7 @@ function smarty_function_block($params, Zikula_View $view) } // We need the module name. - $modinfo = ModUtil::getInfo($blockinfo['mid']); + $modinfo = ModUtil::getInfo($blockinfo['module']->getId()); if (!is_array($modinfo) || !isset($modinfo['name'])) { $modinfo = array('name' => 'core'); } diff --git a/src/lib/util/ModUtil.php b/src/lib/util/ModUtil.php index bf69f4fb4b..0d3abb73b6 100644 --- a/src/lib/util/ModUtil.php +++ b/src/lib/util/ModUtil.php @@ -1750,7 +1750,7 @@ public static function getModsTable() $entityManager = $sm->get('doctrine.entitymanager'); // get all modules - $modules = $entityManager->getRepository('Zikula\Core\Doctrine\Entity\ExtensionEntity')->findAll(); + $modules = $entityManager->getRepository('Zikula\ExtensionsModule\Entity\ExtensionEntity')->findAll(); foreach ($modules as $module) { $module = $module->toArray(); @@ -1792,7 +1792,7 @@ public static function getModules($where = array(), $sort = 'displayname') $entityManager = $sm->get('doctrine.entitymanager'); // get all modules - $modules = $entityManager->getRepository('Zikula\Core\Doctrine\Entity\ExtensionEntity')->findBy($where, array($sort => 'ASC')); + $modules = $entityManager->getRepository('Zikula\ExtensionsModule\Entity\ExtensionEntity')->findBy($where, array($sort => 'ASC')); return $modules; } @@ -1812,7 +1812,7 @@ public static function getModulesByState($state = self::STATE_ACTIVE, $sort = 'd { $sm = ServiceUtil::getManager(); $entityManager = $sm->get('doctrine.entitymanager'); - $modules = $entityManager->getRepository('Zikula\Core\Doctrine\Entity\ExtensionEntity')->findBy(array('state' => $state), array($sort => 'ASC')); + $modules = $entityManager->getRepository('Zikula\ExtensionsModule\Entity\ExtensionEntity')->findBy(array('state' => $state), array($sort => 'ASC')); return $modules; } diff --git a/src/system/BlocksModule/Api/AdminApi.php b/src/system/BlocksModule/Api/AdminApi.php index a206a3161d..2aa3b86659 100644 --- a/src/system/BlocksModule/Api/AdminApi.php +++ b/src/system/BlocksModule/Api/AdminApi.php @@ -23,6 +23,7 @@ /** * API functions used by administrative controllers + * @deprecated remove at Core-2.0 */ class AdminApi extends \Zikula_AbstractApi { @@ -64,46 +65,34 @@ public function update($args) throw new AccessDeniedException(); } - // remove old placements and insert the new ones - /** @var BlockPlacementEntity[] $items */ - $items = $this->entityManager->getRepository('ZikulaBlocksModule:BlockPlacementEntity') - ->findBy(array('bid'=>$args['bid'])); + $block = $this->entityManager->getRepository('ZikulaBlocksModule:BlockEntity')->findOneBy(['bid' => $args['bid']]); - // refactor position array (keys=values) - $positions = $args['positions']; - $args['positions'] = array(); - foreach ($positions as $value) { - $args['positions'][$value] = $value; - } - - foreach ($items as $item) { - $pid = $item->getPid(); - if (!in_array($pid,$args['positions'])) { - $this->entityManager->remove($item); + // remove old placements that are not wanted + foreach ($block->getPlacements() as $placement) { + $pid = $placement->getPosition()->getPid(); + if (!in_array($pid, $args['positions'])) { + $this->entityManager->remove($placement); + $block->removePlacement($placement); } else { - unset($args['positions'][$pid]); + $key = array_search($pid, $args['positions']); + unset($args['positions'][$key]); } } - if (isset($args['positions']) && is_array($args['positions'])) { - + // add new placements as requested + if (!empty($args['positions']) && is_array($args['positions'])) { foreach ($args['positions'] as $position) { $placement = new BlockPlacementEntity(); - $placement->setPid($position); - $placement->setBid($args['bid']); + $placement->setPosition($this->entityManager->getReference('ZikulaBlocksModule:BlockPositionEntity', $position)); + $placement->setBlock($block); $this->entityManager->persist($placement); + $block->addPlacement($placement); } } - - // unset positions - if (isset($args['positions'])) { - unset($args['positions']); - } + unset ($args['positions'], $args['placements']); // update item - $item = ModUtil::apiFunc('ZikulaBlocksModule', 'user', 'get', array('bid' => $args['bid'])); - $item->merge($args); - + $block->merge($args); $this->entityManager->flush(); return true; @@ -147,36 +136,33 @@ public function create($args) $args['content'] = ''; } - $block = array( + $blockData = array( 'title' => $args['title'], 'description' => $args['description'], 'language' => $args['language'], 'collapsable' => $args['collapsable'], - 'mid' => $args['mid'], + 'module' => $this->entityManager->getReference('Zikula\ExtensionsModule\Entity\ExtensionEntity', $args['mid']), 'defaultstate' => $args['defaultstate'], 'bkey' => $args['bkey'], 'content' => $args['content'] ); - $item = new BlockEntity(); - $item->merge($block); - $this->entityManager->persist($item); - $this->entityManager->flush(); + $block = new BlockEntity(); + $block->merge($blockData); + $this->entityManager->persist($block); // insert block positions for this block if (isset($args['positions']) && is_array($args['positions'])) { - foreach ($args['positions'] as $position) { $placement = new BlockPlacementEntity(); - $placement->setPid($position); - $placement->setBid($item['bid']); + $placement->setPosition($this->entityManager->getReference('ZikulaBlocksModule:BlockPositionEntity', $position)); + $placement->setBlock($block); $this->entityManager->persist($placement); } - - $this->entityManager->flush(); } + $this->entityManager->flush(); - return $item['bid']; + return $block->getBid(); } /** @@ -287,14 +273,14 @@ public function delete($args) } // delete block's placements - $query = $this->entityManager->createQueryBuilder() - ->delete() - ->from('ZikulaBlocksModule:BlockPlacementEntity', 'p') - ->where('p.bid = :bid') - ->setParameter('bid', $block['bid']) - ->getQuery(); - - $query->getResult(); +// $query = $this->entityManager->createQueryBuilder() +// ->delete() +// ->from('ZikulaBlocksModule:BlockPlacementEntity', 'p') +// ->where('p.bid = :bid') +// ->setParameter('bid', $block['bid']) +// ->getQuery(); +// +// $query->getResult(); // Now actually delete the block $this->entityManager->remove($block); @@ -444,55 +430,4 @@ public function deleteposition($args) // Let the calling process know that we have finished successfully return true; } - - /** - * Get available admin panel links. - * - * @return array array of admin links. - */ - public function getLinks() - { - $links = array(); - $submenulinks = array(); - - // get all possible block positions - $blockspositions = ModUtil::apiFunc('ZikulaBlocksModule', 'user', 'getallpositions'); - - // Create array for dropdown menu links - foreach ($blockspositions as $blocksposition) { - $filter['blockposition_id'] = $blocksposition['pid']; - $submenulinks[] = array( - 'url' => $this->get('router')->generate('zikulablocksmodule_admin_view', array('filter' => $filter)), - 'text' => $this->__f('Position "%s"', $blocksposition['name'])); - } - - if (SecurityUtil::checkPermission('ZikulaBlocksModule::', '::', ACCESS_EDIT)) { - $links[] = array( - 'url' => $this->get('router')->generate('zikulablocksmodule_admin_view'), - 'text' => $this->__('Blocks list'), - 'icon' => 'table', - 'links' => $submenulinks); - } - - if (SecurityUtil::checkPermission('ZikulaBlocksModule::', '::', ACCESS_ADD)) { - $links[] = array( - 'url' => $this->get('router')->generate('zikulablocksmodule_admin_newblock'), - 'text' => $this->__('Create new block'), - 'icon' => 'plus'); - } - if (SecurityUtil::checkPermission('ZikulaBlocksModule::', '::', ACCESS_ADD)) { - $links[] = array( - 'url' => $this->get('router')->generate('zikulablocksmodule_admin_newposition'), - 'text' => $this->__('Create new block position'), - 'icon' => 'plus'); - } - if (SecurityUtil::checkPermission('ZikulaBlocksModule::', '::', ACCESS_ADMIN)) { - $links[] = array( - 'url' => $this->get('router')->generate('zikulablocksmodule_admin_modifyconfig'), - 'text' => $this->__('Settings'), - 'icon' => 'wrench'); - } - - return $links; - } } \ No newline at end of file diff --git a/src/system/BlocksModule/Api/BlockApi.php b/src/system/BlocksModule/Api/BlockApi.php new file mode 100644 index 0000000000..e03f805c47 --- /dev/null +++ b/src/system/BlocksModule/Api/BlockApi.php @@ -0,0 +1,212 @@ +blockPositionRepository = $blockPositionRepository; + $this->blockFilter = $blockFilterApi; + $this->blockFactory = $blockFactoryApi; + $this->extensionApi = $extensionApi; + $this->blockCollector = $blockCollector; + $this->kernelRootDir = $kernelRootDir; // parameter is deprecated. remove at Core-2.0 + } + + /** + * Get a filtered array of block entities that have been assigned to a block position. + * @param $positionName + * @return array + */ + public function getBlocksByPosition($positionName) + { + if (empty($positionName)) { + throw new \InvalidArgumentException('Name must not be empty.'); + } + + /** @var \Zikula\BlocksModule\Entity\BlockPositionEntity $position */ + $position = $this->blockPositionRepository->findByName($positionName); + $blocks = []; + if (empty($position)) { + return $blocks; + } + foreach ($position->getPlacements() as $placement) { + if ($placement->getBlock()->getActive() && $this->blockFilter->isDisplayable($placement->getBlock())) { + $blocks[$placement->getBlock()->getBid()] = $placement->getBlock(); + } + } + + return $blocks; + } + + /** + * Create an instance of a the block Object given a 'bKey' string like AcmeFooModule:Acme\FooModule\Block\FooBlock + * which is the Common ModuleName and the FullyQualifiedClassName of the block. + * @param string $bKey + * @return \Zikula_Controller_AbstractBlock|BlockControllerInterface + */ + public function createInstanceFromBKey($bKey) + { + list($moduleName, $blockFqCn) = explode(':', $bKey); + $moduleInstance = $this->extensionApi->getModuleInstanceOrNull($moduleName); + + return $this->blockFactory->getInstance($blockFqCn, $moduleInstance); + } + + /** + * Get an array of Blocks that are available by scanning the filesystem. + * Optionally only retrieve the blocks of one module. + * + * @param ExtensionEntity|null $module + * @return array [[ModuleName:FqBlockClassName => ModuleDisplayName/BlockDisplayName]] + */ + public function getAvailableBlockTypes(ExtensionEntity $module = null) + { + $foundBlocks = []; + $modules = isset($module) ? [$module] : $this->extensionApi->getModulesBy(['state' => ExtensionApi::STATE_ACTIVE]); + /** @var \Zikula\ExtensionsModule\Entity\ExtensionEntity $module */ + foreach ($modules as $module) { + $moduleInstance = $this->extensionApi->getModuleInstanceOrNull($module->getName()); + list ($nameSpace, $path) = $this->getModuleBlockPath($moduleInstance, $module->getName()); + if (!isset($path)) { + continue; + } + $finder = new Finder(); + $foundFiles = $finder + ->files() + ->name('*.php') + ->in($path) + ->depth(0); + foreach ($foundFiles as $file) { + preg_match("/class (\\w+) (?:extends|implements) \\\\?(\\w+)/", $file->getContents(), $matches); + $blockInstance = $this->blockFactory->getInstance($nameSpace . $matches[1], $moduleInstance); + $foundBlocks[$module->getName() . ':' . $nameSpace . $matches[1]] = $module->getDisplayname() . '/' . $blockInstance->getType(); + } + } + // Add service defined blocks. + foreach ($this->blockCollector->getBlocks() as $id => $blockInstance) { + $className = get_class($blockInstance); + list ($moduleName, $serviceId) = explode(':', $id); + if (isset($foundBlocks["$moduleName:$className"])) { + // remove blocks found in file search with same class name + unset($foundBlocks["$moduleName:$className"]); + } + $moduleEntity = $this->extensionApi->getModule($moduleName); + $foundBlocks[$id] = $moduleEntity->getDisplayname() . '/' . $blockInstance->getType(); + } + + return $foundBlocks; + } + + /** + * Get an alphabetically sorted array of module names indexed by id that provide blocks. + * + * @return array + */ + public function getModulesContainingBlocks() + { + $modules = $this->extensionApi->getModulesBy(['state' => ExtensionApi::STATE_ACTIVE]); + $modulesContainingBlocks = []; + foreach ($modules as $module) { + $blocks = $this->getAvailableBlockTypes($module); + if (!empty($blocks)) { + $modulesContainingBlocks[$module->getId()] = $module->getName(); + } + } + asort($modulesContainingBlocks); + + return $modulesContainingBlocks; + } + + /** + * Get the block directory for a module given an instance of the module or (for BC purposes), the module name. + * The $moduleName parameter is deprecated and will be removed at Core-2.0 + * + * @param AbstractModule|null $moduleInstance + * @param null $moduleName (parameter is @deprecated) + * @return array + */ + public function getModuleBlockPath(AbstractModule $moduleInstance = null, $moduleName = null) + { + $path = null; + $nameSpace = null; + if (isset($moduleInstance)) { + if (is_dir($moduleInstance->getPath() . '/Block')) { + $path = $moduleInstance->getPath() . '/Block'; + $nameSpace = $moduleInstance->getNamespace() . '\Block\\'; + } + } elseif (isset($moduleName)) { // @todo remove at Core-2.0 + $testPath = realpath($this->kernelRootDir . '/../modules/' . $moduleName . '/lib/' . $moduleName . '/Block'); + if (is_dir($testPath)) { + $path = $testPath; + $nameSpace = '\\'; + } + } + + return [$nameSpace, $path]; + } +} \ No newline at end of file diff --git a/src/system/BlocksModule/Api/BlockFactoryApi.php b/src/system/BlocksModule/Api/BlockFactoryApi.php new file mode 100644 index 0000000000..6d38b4e6ed --- /dev/null +++ b/src/system/BlocksModule/Api/BlockFactoryApi.php @@ -0,0 +1,100 @@ +container = $container; + } + + /** + * Factory method to create an instance of a block given its name and the providing module instance. + * Supports either Zikula\Core\BlockControllerInterface or + * Zikula_Controller_AbstractBlock (to be removed). + * + * @todo at Core-2.0 remove BC support for Zikula_Controller_AbstractBlock + * @todo remove `null` default value for $moduleBundle at Core-2.0 and check for null below + * @param $blockClassName + * @param AbstractModule|null $moduleBundle + * @return \Zikula_Controller_AbstractBlock|BlockControllerInterface + */ + public function getInstance($blockClassName, AbstractModule $moduleBundle = null) + { + if (strpos($blockClassName, '.')) { + // probably a service name + if ($this->container->has($blockClassName)) { + $service = $this->container->get($blockClassName); + if ($service instanceof BlockControllerInterface) { + return $service; + } + } + } + + if (!class_exists($blockClassName)) { + throw new \RuntimeException(sprintf('Classname %s does not exist.', $blockClassName)); + } + if (!is_subclass_of($blockClassName, 'Zikula\Core\BlockControllerInterface') && !is_subclass_of($blockClassName, 'Zikula_Controller_AbstractBlock')) { + throw new \RuntimeException(sprintf('Block class %s must implement Zikula\Core\BlockControllerInterface or be a subclass of Zikula_Controller_AbstractBlock.', $blockClassName)); + } + + $serviceNameHelper = new ServiceNameHelper(); + if ($this->container->has($blockServiceName = $serviceNameHelper->generateServiceNameFromClassName($blockClassName))) { + return $this->container->get($blockServiceName); + } + + if (is_subclass_of($blockClassName, 'Zikula_Controller_AbstractBlock')) { + $blockInstance = new $blockClassName($this->container, $moduleBundle); + $blockInstance->init(); + } elseif (is_subclass_of($blockClassName, 'Zikula\Core\Controller\AbstractBlockController')) { + if ((null === $moduleBundle) || (!($moduleBundle instanceof AbstractModule))) { + throw new \LogicException('$moduleBundle must be instance of AbstractModule and not null.'); + } + $blockInstance = new $blockClassName($moduleBundle); + } else { + $blockInstance = new $blockClassName(); + } + + if ($blockInstance instanceof ContainerAwareInterface) { + $blockInstance->setContainer($this->container); + } + + $this->container->set($blockServiceName, $blockInstance); + + return $blockInstance; + } +} \ No newline at end of file diff --git a/src/system/BlocksModule/Api/BlockFilterApi.php b/src/system/BlocksModule/Api/BlockFilterApi.php new file mode 100644 index 0000000000..623da7f131 --- /dev/null +++ b/src/system/BlocksModule/Api/BlockFilterApi.php @@ -0,0 +1,130 @@ +requestStack = $requestStack; + } + + /** + * Determine if the block is displayable based on the filter criteria. + * + * @param BlockEntity $blockEntity + * @return boolean + */ + public function isDisplayable(BlockEntity $blockEntity) + { + $request = $this->requestStack->getCurrentRequest(); + if (null === $request) { + return true; + } + + $displayable = true; + $filters = $blockEntity->getFilters(); + foreach ($filters as $filter) { + switch ($filter['attribute']) { + case 'query param': + $name = $request->query->get($filter['queryParameter']); + break; + case '_route_params': + $params = $request->attributes->get('_route_params'); + $name = isset($params[$filter['queryParameter']]) ? $params[$filter['queryParameter']] : 'kjashdhk11111'; // random characters to prevent match + break; + default: + $name = $request->attributes->get($filter['attribute']); + } + $displayable = $displayable && $this->compare($name, $filter['comparator'], $filter['value']); + } + // filter for language/locale + $language = $blockEntity->getLanguage(); + if (!empty($language)) { + $displayable = $displayable && ($language == $request->getLocale()); + } + + return $displayable; + } + + /** + * Compare variables according to a dynamic comparator. + * + * @param $var1 + * @param $comparator + * @param $var2 + * @return bool + */ + private function compare($var1, $comparator, $var2) + { + switch ($comparator) { + case "==": + return $var1 == $var2; + case "!=": + return $var1 != $var2; + case ">=": + return $var1 >= $var2; + case "<=": + return $var1 <= $var2; + case ">": + return $var1 > $var2; + case "<": + return $var1 < $var2; + case "in_array": + $var2 = array_map('trim', explode(',',$var2)); + return in_array($var1, $var2); + case "!in_array": + $var2 = array_map('trim', explode(',',$var2)); + return !in_array($var1, $var2); + default: + return true; + } + } + + /** + * Get all the attributes of the request + 'query param'. + * + * @return array + */ + public function getFilterAttributeChoices() + { + $request = $this->requestStack->getCurrentRequest(); + if (null == $request) { + return []; + } + $attributes = []; + foreach ($request->attributes->keys() as $attribute) { + $attributes[$attribute] = $attribute; + } + $attributes['query param'] = 'query param'; + + return $attributes; + } +} \ No newline at end of file diff --git a/src/system/BlocksModule/Api/UserApi.php b/src/system/BlocksModule/Api/UserApi.php index 22aed156e3..68fec9de89 100644 --- a/src/system/BlocksModule/Api/UserApi.php +++ b/src/system/BlocksModule/Api/UserApi.php @@ -19,6 +19,7 @@ /** * API functions used by user controllers + * @deprecated remove at Core-2.0 */ class UserApi extends \Zikula_AbstractApi { @@ -82,7 +83,7 @@ public function getall($args) // add clause for filtering module if (isset($args['module_id']) && is_numeric($args['module_id']) && $args['module_id']) { - $qb->andWhere($qb->expr()->eq('b.mid', ':mid'))->setParameter('mid', $args['module_id']); + $qb->andWhere($qb->expr()->eq('b.module', ':mid'))->setParameter('mid', $args['module_id']); } // add clause for filtering language diff --git a/src/system/BlocksModule/Block/ExtmenuBlock.php b/src/system/BlocksModule/Block/ExtmenuBlock.php index f9720a2ad7..8e0e891ed7 100644 --- a/src/system/BlocksModule/Block/ExtmenuBlock.php +++ b/src/system/BlocksModule/Block/ExtmenuBlock.php @@ -175,7 +175,7 @@ public function display($blockinfo) if (SecurityUtil::checkPermission('ExtendedMenublock::', $blockinfo['bid'] . '::', ACCESS_ADMIN)) { $menuitems[] = array('name' => $this->__('--Installed modules--'), - 'url' => $this->get('router')->generate('zikulablocksmodule_admin_modify', array('bid' => $blockinfo['bid'])), + 'url' => $this->get('router')->generate('zikulablocksmodule_block_edit', array('blockEntity' => $blockinfo['bid'])), 'title' => '', 'level' => 0, 'parentid' => null, diff --git a/src/system/BlocksModule/Block/Form/Type/readme.md b/src/system/BlocksModule/Block/Form/Type/readme.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/system/BlocksModule/BlocksModuleInstaller.php b/src/system/BlocksModule/BlocksModuleInstaller.php index c95138a85b..689fa45b64 100644 --- a/src/system/BlocksModule/BlocksModuleInstaller.php +++ b/src/system/BlocksModule/BlocksModuleInstaller.php @@ -1,6 +1,6 @@ entityManager, $classes); + $this->schemaTool->create($this->entities); } catch (\Exception $e) { return false; } // Set a default value for a module variable - $this->setVar('collapseable', 0); + $this->setVar('collapseable', false); - HookUtil::registerSubscriberBundles($this->version->getHookSubscriberBundles()); + $hookHelper = new HookHelper($this->getTranslator()); + HookUtil::registerSubscriberBundles($hookHelper->getHookSubscriberBundles()); // Initialisation successful return true; @@ -66,7 +71,8 @@ public function upgrade($oldversion) // Upgrade dependent on old version number switch ($oldversion) { case '3.8.1': - HookUtil::registerSubscriberBundles($this->version->getHookSubscriberBundles()); + $hookHelper = new HookHelper($this->getTranslator()); + HookUtil::registerSubscriberBundles($hookHelper->getHookSubscriberBundles()); case '3.8.2': case '3.9.0': $blocks = $this->entityManager->getRepository('ZikulaBlocksModule:BlockEntity')->findAll(); @@ -93,12 +99,37 @@ public function upgrade($oldversion) // check if request is available (#2073) $templateWarning = $this->__('Warning: Block template locations modified, you may need to fix your template overrides if you have any.'); - if (is_object($this->request) && method_exists($this->request, 'getSession') && is_object($this->request->getSession())) { - $this->request->getSession()->getFlashBag()->add(\Zikula_Session::MESSAGE_WARNING, $templateWarning); + if (is_object($this->container->get('request')) && method_exists($this->container->get('request'), 'getSession') && is_object($this->container->get('request')->getSession())) { + $this->addFlash(\Zikula_Session::MESSAGE_WARNING, $templateWarning); } else { \LogUtil::registerWarning($templateWarning); } case '3.9.1': + // make all content fields of blocks serialized. + $sql = "SELECT * FROM blocks"; + $blocks = $this->entityManager->getConnection()->fetchAll($sql); + foreach ($blocks as $block) { + if (!\DataUtil::is_serialized($block['content'])) { + $serializedContent = addslashes(serialize($block['content'])); + $this->entityManager->getConnection()->executeQuery("UPDATE blocks SET content = '$serializedContent' WHERE bid = $block[bid]"); + } + } + $this->schemaTool->update($this->entities); + + $blocks = $this->entityManager->getRepository('ZikulaBlocksModule:BlockEntity')->findAll(); + $installerHelper = new InstallerHelper(); + /** @var \Zikula\BlocksModule\Entity\BlockEntity $block */ + foreach ($blocks as $block) { + $block->setFilter($installerHelper->upgradeFilterArray($block->getFilter())); + $block->setBlocktype(preg_match('/.*Block$/', $block->getBkey()) ? substr($block->getBkey(), 0, -5) : $block->getBkey()); + $block->setBkey($installerHelper->upgradeBkeyToFqClassname($this->container->get('kernel'), $block)); + } + $this->entityManager->flush(); + + $collapseable = $this->getVar('collapseable'); + $this->setVar('collapseable', (boolean) $collapseable); + + case '3.9.2': // future upgrade routines } @@ -126,28 +157,24 @@ public function uninstall() */ public function defaultdata() { - // load block api - ModUtil::loadApi('ZikulaBlocksModule', 'admin', true); - - // sanity check - truncate existing tables to ensure a clean blocks setup - $connection = $this->entityManager->getConnection(); - $platform = $connection->getDatabasePlatform(); - $connection->executeUpdate($platform->getTruncateTableSQL('blocks', true)); - $connection->executeUpdate($platform->getTruncateTableSQL('block_positions', true)); - $connection->executeUpdate($platform->getTruncateTableSQL('block_placements', true)); - // create the default block positions - left, right and center for the traditional 3 column layout - $left = ModUtil::apiFunc('ZikulaBlocksModule', 'admin', 'createposition', array('name' => 'left', 'description' => $this->__('Left blocks'))); - $right = ModUtil::apiFunc('ZikulaBlocksModule', 'admin', 'createposition', array('name' => 'right', 'description' => $this->__('Right blocks'))); - $center = ModUtil::apiFunc('ZikulaBlocksModule', 'admin', 'createposition', array('name' => 'center', 'description' => $this->__('Center blocks'))); - $search = ModUtil::apiFunc('ZikulaBlocksModule', 'admin', 'createposition', array('name' => 'search', 'description' => $this->__('Search block'))); - $header = ModUtil::apiFunc('ZikulaBlocksModule', 'admin', 'createposition', array('name' => 'header', 'description' => $this->__('Header block'))); - $footer = ModUtil::apiFunc('ZikulaBlocksModule', 'admin', 'createposition', array('name' => 'footer', 'description' => $this->__('Footer block'))); - $topnav = ModUtil::apiFunc('ZikulaBlocksModule', 'admin', 'createposition', array('name' => 'topnav', 'description' => $this->__('Top navigation block'))); - $bottomnav = ModUtil::apiFunc('ZikulaBlocksModule', 'admin', 'createposition', array('name' => 'bottomnav', 'description' => $this->__('Bottom navigation block'))); - - // define an array of the default blocks - $blocks = array(); + $positions = [ + 'left' => $this->__('Left blocks'), + 'right' => $this->__('Right blocks'), + 'center' => $this->__('Center blocks'), + 'search' => $this->__('Search block'), + 'header' => $this->__('Header block'), + 'footer' => $this->__('Footer block'), + 'topnav' => $this->__('Top navigation block'), + 'bottomnav' => $this->__('Bottom navigation block'), + ]; + foreach ($positions as $name => $description) { + $positions[$name] = new BlockPositionEntity(); + $positions[$name]->setName($name); + $positions[$name]->setDescription($description); + $this->entityManager->persist($positions[$name]); + } + $this->entityManager->flush(); // build the menu content $languages = ZLanguage::getInstalledLanguages(); @@ -183,26 +210,80 @@ public function defaultdata() ZLanguage::setLocale($saveLanguage); - $menucontent = serialize($menucontent); - $topnavcontent = serialize($topnavcontent); - $searchcontent = array('displaySearchBtn' => 1, - 'active' => array('ZikulaUsersModule' => 1)); - $searchcontent = serialize($searchcontent); + $searchcontent = [ + 'displaySearchBtn' => 1, + 'active' => array('ZikulaUsersModule' => 1) + ]; $hellomessage = $this->__('

Zikula is a content management system (CMS) and application framework. It is secure and stable, and is a good choice for sites with a large volume of traffic.

With Zikula:

  • you can customise all aspects of the site\'s appearance through themes, with support for CSS style sheets, JavaScript, Flash and all other modern web development technologies;
  • you can mark content as being suitable for either a single language or for all languages, and can control all aspects of localisation and internationalisation of your site;
  • you can be sure that your pages will display properly in all browsers, thanks to Zikula\'s full compliance with W3C HTML standards;
  • you get a standard application-programming interface (API) that lets you easily augment your site\'s functionality through modules, blocks and other extensions;
  • you can get help and support from the Zikula community of webmasters and developers at zikula.org.

Enjoy using Zikula!

The Zikula team

Note: Zikula is Free Open Source Software (FOSS) licensed under the GNU General Public License.

'); - $blocks[] = array('bkey' => 'Extmenu', 'collapsable' => 1, 'defaultstate' => 1, 'language' => '', 'mid' => ModUtil::getIdFromName('ZikulaBlocksModule'), 'title' => $this->__('Main menu'), 'description' => $this->__('Main menu'), 'content' => $menucontent, 'positions' => array($left)); - $blocks[] = array('bkey' => 'Search', 'collapsable' => 1, 'defaultstate' => 1, 'language' => '', 'mid' => ModUtil::getIdFromName('ZikulaSearchModule'), 'title' => $this->__('Search box'), 'description' => $this->__('Search block'), 'content' => $searchcontent, 'positions' => array($search)); - $blocks[] = array('bkey' => 'Html', 'collapsable' => 1, 'defaultstate' => 1, 'language' => '', 'mid' => ModUtil::getIdFromName('ZikulaBlocksModule'), 'title' => $this->__("This site is powered by Zikula!"), 'description' => $this->__('HTML block'), 'content' => $hellomessage, 'positions' => array($center)); - $blocks[] = array('bkey' => 'Login', 'collapsable' => 1, 'defaultstate' => 1, 'language' => '', 'mid' => ModUtil::getIdFromName('ZikulaUsersModule'), 'title' => $this->__('User log-in'), 'description' => $this->__('Login block'), 'positions' => array($right)); - //$blocks[] = array('bkey' => 'Online', 'collapsable' => 1, 'defaultstate' => 1, 'language' => '', 'mid' => ModUtil::getIdFromName('ZikulaUsersModule'), 'title' => $this->__('Who\'s on-line'), 'description' => $this->__('Online block'), 'positions' => array($right)); - $blocks[] = array('bkey' => 'Extmenu', 'collapsable' => 1, 'defaultstate' => 1, 'language' => '', 'mid' => ModUtil::getIdFromName('ZikulaBlocksModule'), 'title' => $this->__('Top navigation'), 'description' => $this->__('Theme navigation'), 'content' => $topnavcontent, 'positions' => array($topnav)); - - // create each block and then update the block - // the create creates the initial block record, the update sets the block placement - foreach ($blocks as $position => $block) { - ModUtil::apiFunc('ZikulaBlocksModule', 'admin', 'create', $block); + + $blocks = []; + $blocksModuleEntity = $this->entityManager->getRepository('\Zikula\ExtensionsModule\Entity\ExtensionEntity')->findOneBy(['name' => 'ZikulaBlocksModule']); + $searchModuleEntity = $this->entityManager->getRepository('\Zikula\ExtensionsModule\Entity\ExtensionEntity')->findOneBy(['name' => 'ZikulaSearchModule']); + $usersModuleEntity = $this->entityManager->getRepository('\Zikula\ExtensionsModule\Entity\ExtensionEntity')->findOneBy(['name' => 'ZikulaUsersModule']); + $blocks[] = [ + 'bkey' => 'ZikulaBlocksModule:\Zikula\BlocksModule\Block\ExtmenuBlock', + 'blocktype' => 'Extmenu', + 'language' => '', + 'module' => $blocksModuleEntity, + 'title' => $this->__('Main menu'), + 'description' => $this->__('Main menu'), + 'content' => $menucontent, + 'position' => $positions['left'] + ]; + $blocks[] = [ + 'bkey' => 'ZikulaSearchModule:\Zikula\SearchModule\Block\SearchBlock', + 'blocktype' => 'Search', + 'language' => '', + 'module' => $searchModuleEntity, + 'title' => $this->__('Search box'), + 'description' => $this->__('Search block'), + 'content' => $searchcontent, + 'position' => $positions['search'] + ]; + $blocks[] = [ + 'bkey' => 'ZikulaBlocksModule:\Zikula\BlocksModule\Block\HtmlBlock', + 'blocktype' => 'Html', + 'language' => '', + 'module' => $blocksModuleEntity, + 'title' => $this->__("This site is powered by Zikula!"), + 'description' => $this->__('HTML block'), + 'content' => $hellomessage, + 'position' => $positions['center'] + ]; + $blocks[] = [ + 'bkey' => 'ZikulaUsersModule:\Zikula\UsersModule\Block\LoginBlock', + 'blocktype' => 'Login', + 'language' => '', + 'module' => $usersModuleEntity, + 'title' => $this->__('User log-in'), + 'description' => $this->__('Login block'), + 'position' => $positions['right'] + ]; + $blocks[] = [ + 'bkey' => 'ZikulaBlocksModule:\Zikula\BlocksModule\Block\ExtmenuBlock', + 'blocktype' => 'Extmenu', + 'language' => '', + 'module' => $blocksModuleEntity, + 'title' => $this->__('Top navigation'), + 'description' => $this->__('Theme navigation'), + 'content' => $topnavcontent, + 'position' => $positions['topnav'] + ]; + + foreach ($blocks as $block) { + $blockEntity = new BlockEntity(); + $position = $block['position']; + unset($block['position']); + $blockEntity->merge($block); + $this->entityManager->persist($blockEntity); + $placement = new BlockPlacementEntity(); + $placement->setBlock($blockEntity); + $placement->setPosition($position); + $this->entityManager->persist($placement); } + $this->entityManager->flush(); return; } -} +} \ No newline at end of file diff --git a/src/system/BlocksModule/BlocksModuleVersion.php b/src/system/BlocksModule/BlocksModuleVersion.php deleted file mode 100644 index b5fc4d18ff..0000000000 --- a/src/system/BlocksModule/BlocksModuleVersion.php +++ /dev/null @@ -1,75 +0,0 @@ -__('Blocks'); - $meta['description'] = $this->__('Block administration module.'); - $meta['url'] = $this->__('blocks'); - $meta['version'] = '3.9.1'; - $meta['core_min'] = '1.4.0'; - $meta['capabilities'] = array(HookUtil::SUBSCRIBER_CAPABLE => array('enabled' => true)); - $meta['securityschema'] = array('ZikulaBlocksModule::' => 'Block key:Block title:Block ID', - 'ZikulaBlocksModule::position' => 'Position name::Position ID', - 'Menutree:menutreeblock:' => 'Block ID:Link Name:Link ID', - 'ExtendedMenublock::' => 'Block ID:Link ID:', - 'fincludeblock::' => 'Block title::', - 'HTMLblock::' => 'Block title::', - 'Languageblock::' => 'Block title::', - 'Menublock::' => 'Block title:Link name:', - 'PendingContent::' => 'Block title::', - 'Textblock::' => 'Block title::', - 'xsltblock::' => 'Block title::', - ); - - // Module depedencies - $meta['dependencies'] = array( - array('modname' => 'Scribite', - 'minversion' => '5.0.0', - 'maxversion' => '', - 'status' => ModUtil::DEPENDENCY_RECOMMENDED), - ); - return $meta; - } - - /** - * Set up hook subscriber bundle - * - * This area is only activated when editing an Html Block. - * There are no other hook functions currently implemented since linking - * back (via url) to a block is impossible. - */ - protected function setupHookBundles() - { - $bundle = new SubscriberBundle($this->name, 'subscriber.blocks.ui_hooks.htmlblock.content', 'ui_hooks', $this->__('HTML Block content hook')); - $bundle->addEvent('form_edit', 'blocks.ui_hooks.htmlblock.content.form_edit'); - $this->registerHookSubscriberBundle($bundle); - } -} diff --git a/src/system/BlocksModule/Collector/BlockCollector.php b/src/system/BlocksModule/Collector/BlockCollector.php new file mode 100644 index 0000000000..8f1806cd67 --- /dev/null +++ b/src/system/BlocksModule/Collector/BlockCollector.php @@ -0,0 +1,65 @@ + ServiceObject] + */ + private $blocks; + + public function __construct() + { + $this->blocks = []; + } + + /** + * Add a block to the collection. + * @param $id + * @param BlockControllerInterface $block + */ + public function add($id, BlockControllerInterface $block) + { + $this->blocks[$id] = $block; + } + + /** + * Get a block from the collection by service.id. + * @param $id + * @return null + */ + public function get($id) + { + return isset($this->blocks[$id]) ? $this->blocks[$id] : null; + } + + /** + * Get all the blocks in the collection. + * @return array + */ + public function getBlocks() + { + return $this->blocks; + } +} \ No newline at end of file diff --git a/src/system/BlocksModule/Container/LinkContainer.php b/src/system/BlocksModule/Container/LinkContainer.php new file mode 100644 index 0000000000..d4a173eb8a --- /dev/null +++ b/src/system/BlocksModule/Container/LinkContainer.php @@ -0,0 +1,118 @@ +translator = $translator; + $this->router = $router; + $this->permissionApi = $permissionApi; + } + + /** + * get Links of any type for this extension + * required by the interface + * + * @param string $type + * @return array + */ + public function getLinks($type = LinkContainerInterface::TYPE_ADMIN) + { + $method = 'get' . ucfirst(strtolower($type)); + if (method_exists($this, $method)) { + return $this->$method(); + } + + return []; + } + + /** + * get the Admin links for this extension + * + * @return array + */ + private function getAdmin() + { + $links = []; + + if ($this->permissionApi->hasPermission('ZikulaBlocksModule::', '::', ACCESS_EDIT)) { + $links[] = [ + 'url' => $this->router->generate('zikulablocksmodule_admin_view'), + 'text' => $this->translator->__('Blocks list'), + 'icon' => 'table' + ]; + } + + if ($this->permissionApi->hasPermission('ZikulaBlocksModule::', '::', ACCESS_ADD)) { + $links[] = [ + 'url' => $this->router->generate('zikulablocksmodule_block_new'), + 'text' => $this->translator->__('Create new block'), + 'icon' => 'plus' + ]; + } + if ($this->permissionApi->hasPermission('ZikulaBlocksModule::', '::', ACCESS_ADD)) { + $links[] = [ + 'url' => $this->router->generate('zikulablocksmodule_position_edit'), + 'text' => $this->translator->__('Create new block position'), + 'icon' => 'plus' + ]; + } + if ($this->permissionApi->hasPermission('ZikulaBlocksModule::', '::', ACCESS_ADMIN)) { + $links[] = [ + 'url' => $this->router->generate('zikulablocksmodule_admin_config'), + 'text' => $this->translator->__('Settings'), + 'icon' => 'wrench' + ]; + } + + return $links; + } + + /** + * set the BundleName as required buy the interface + * + * @return string + */ + public function getBundleName() + { + return 'ZikulaBlocksModule'; + } +} \ No newline at end of file diff --git a/src/system/BlocksModule/Controller/AdminController.php b/src/system/BlocksModule/Controller/AdminController.php index 18aa104f18..0799e3ca92 100644 --- a/src/system/BlocksModule/Controller/AdminController.php +++ b/src/system/BlocksModule/Controller/AdminController.php @@ -1,6 +1,6 @@ view->setCaching(Zikula_View::CACHE_DISABLED); - } - /** * @Route("") - * - * The main administration function. - * - * @return RedirectResponse + * @deprecated remove at Core-2.0 */ public function indexAction() { - // Security check will be done in view() - return new RedirectResponse($this->get('router')->generate('zikulablocksmodule_admin_view', array(), RouterInterface::ABSOLUTE_URL)); + @trigger_error('The zikulablocksmodule_admin_index route is deprecated. please use zikulablocksmodule_admin_view instead.', E_USER_DEPRECATED); + + return $this->redirect($this->generateUrl('zikulablocksmodule_admin_view')); } /** * @Route("/view") + * @Theme("admin") + * @Template * * View all blocks. * * @param Request $request * - * @return Response symfony response object + * @return \Symfony\Component\HttpFoundation\Response symfony response object * * @throws AccessDeniedException Thrown if the user doesn't have edit permissions to the module */ public function viewAction(Request $request) { - // Security check - if (!SecurityUtil::checkPermission('ZikulaBlocksModule::', '::', ACCESS_EDIT)) { + if (!$this->hasPermission('ZikulaBlocksModule::', '::', ACCESS_EDIT)) { throw new AccessDeniedException(); } - // get any filter form submissions - $sfilter = SessionUtil::getVar('filter', array(), '/Blocks'); - $filter = $request->request->get('filter', $sfilter); $clear = $request->request->get('clear', 0); if ($clear) { - $filter = array(); - SessionUtil::setVar('filter', $filter, '/Blocks'); - } - - // sort and sortdir GET parameters override filter values - $sort = (isset($filter['sort']) && !empty($filter['sort'])) ? strtolower($filter['sort']) : 'bid'; - $sortdir = (isset($filter['sortdir']) && !empty($filter['sortdir'])) ? strtoupper($filter['sortdir']) : 'ASC'; - - $filter['sort'] = $request->query->get('sort', $sort); - $filter['sortdir'] = $request->query->get('sortdir', $sortdir); - if ($filter['sortdir'] != 'ASC' && $filter['sortdir'] != 'DESC') { - $filter['sortdir'] = 'ASC'; - } - $filter['blockposition_id'] = isset($filter['blockposition_id']) ? $filter['blockposition_id'] : 0; - $filter['module_id'] = isset($filter['module_id']) ? $filter['module_id'] : 0; - $filter['language'] = isset($filter['language']) ? $filter['language'] : ''; - $filter['active_status'] = isset($filter['active_status']) ? $filter['active_status'] : 0; - - $this->view->assign('filter', $filter) - ->assign('sort', $filter['sort']) - ->assign('sortdir', $filter['sortdir']); - - // generate an authorisation key for the links - $csrftoken = SecurityUtil::generateCsrfToken($this->serviceManager, true); - $this->view->assign('csrftoken', $csrftoken); - - // Get all blocks - $blocks = ModUtil::apiFunc('ZikulaBlocksModule', 'user', 'getall', $filter); - - // get all possible block positions and build assoc array for easier usage later on - $blockspositions = ModUtil::apiFunc('ZikulaBlocksModule', 'user', 'getallpositions'); - foreach ($blockspositions as $blocksposition) { - $allbposarray[$blocksposition['pid']] = $blocksposition['name']; - } - - // loop round each item calculating the additional information - $blocksitems = array(); - foreach ($blocks as $key => $block) { - - $block = $block->toArray(); - - // set the module that holds the block - $modinfo = ModUtil::getInfo($block['mid']); - $block['modname'] = $modinfo['displayname']; - - // set the block's language - if (empty($block['language'])) { - $block['language'] = $this->__('All'); + $request->getSession()->set('zikulablocksmodule.filter', []); + } + $sessionFilterData = $request->getSession()->get('zikulablocksmodule.filter', []); + $sortField = $request->query->get('sort-field', isset($sessionFilterData['sort-field']) ? $sessionFilterData['sort-field'] : 'bid'); + $currentSortDirection = $request->query->get('sort-direction', isset($sessionFilterData['sort-direction']) ? $sessionFilterData['sort-direction'] : Column::DIRECTION_ASCENDING); + $filterForm = $this->createForm('Zikula\BlocksModule\Form\Type\AdminViewFilterType', $sessionFilterData, [ + 'action' => $this->generateUrl('zikulablocksmodule_admin_view'), + 'method' => 'POST', + 'translator' => $this->get('translator'), + 'moduleChoices' => $this->get('zikula_blocks_module.api.block')->getModulesContainingBlocks(), + 'positionChoices' => $this->getDoctrine()->getRepository('ZikulaBlocksModule:BlockPositionEntity')->getPositionChoiceArray() + ]); + $filterFormClone = clone $filterForm; + + $filterForm->handleRequest($request); + $filterData = $sessionFilterData; + if ($filterForm->isSubmitted()) { + if ($filterForm->get('filterButton')->isClicked()) { + $filterData = $filterForm->getData(); } else { - $block['language'] = ZLanguage::getLanguageName($block['language']); - } - - // set the block's position(s) - $bposarray = array(); - $thisblockspositions = ModUtil::apiFunc('ZikulaBlocksModule', 'user', 'getallblockspositions', array('bid' => $block['bid'])); - foreach ($thisblockspositions as $singleblockposition) { - $bposarray[] = $allbposarray[$singleblockposition['pid']]; - } - $block['positions'] = implode(', ', $bposarray); - unset($bposarray); - - // push block to array - $blocksitems[] = $block; - } - $this->view->assign('blocks', $blocksitems); - - // get the block positions and assign them to the template - $positions = ModUtil::apiFunc('ZikulaBlocksModule', 'user', 'getallpositions'); - $this->view->assign('positions', $positions); - - return new Response($this->view->fetch('Admin/view.tpl')); - } - - /** - * @Route("/deactivate/{bid}/{csrftoken}", requirements={"bid" = "^[1-9]\d*$"}) - * @Method("GET") - * - * Deactivate a block. - * - * @param Request $request - * @param integer $bid - * @param string $csrftoken - * - * int $bid block id - * - * @return RedirectResponse symfony response object - */ - public function deactivateAction(Request $request, $bid, $csrftoken) - { - $this->checkCsrfToken($csrftoken); - - // Pass to API - if (ModUtil::apiFunc('ZikulaBlocksModule', 'admin', 'deactivate', array('bid' => $bid))) { - // Success - $request->getSession()->getFlashBag()->add('status', $this->__('Done! Block now inactive.')); - } - - return new RedirectResponse($this->get('router')->generate('zikulablocksmodule_admin_view', array(), RouterInterface::ABSOLUTE_URL)); - } - - /** - * @Route("/activate/{bid}/{csrftoken}", requirements={"bid" = "^[1-9]\d*$"}) - * @Method("GET") - * - * Activate a block. - * - * @param Request $request - * @param integer $bid - * @param string $csrftoken - * - * int $bid block id - * - * @return RedirectResponse symfony response object - */ - public function activateAction(Request $request, $bid, $csrftoken) - { - $this->checkCsrfToken($csrftoken); - - // Pass to API - if (ModUtil::apiFunc('ZikulaBlocksModule', 'admin', 'activate', array('bid' => $bid))) { - // Success - $request->getSession()->getFlashBag()->add('status', $this->__('Done! Block now active.')); - } - - return new RedirectResponse($this->get('router')->generate('zikulablocksmodule_admin_view', array(), RouterInterface::ABSOLUTE_URL)); - } - - /** - * @Route("/modify/{bid}", requirements={"bid" = "^[1-9]\d*$"}) - * @Method("GET") - * - * Modify a block. - * - * @param integer $bid block id. - * - * @return Response symfony response object - * - * @throws AccessDeniedException Thrown if the user doesn't have edit permissions over the block - * @throws NotFoundHttpException Thrown if the requested block doesn't exist - */ - public function modifyAction($bid) - { - // Get details on current block - $blockinfo = BlockUtil::getBlockInfo($bid); - - // Security check - if (!SecurityUtil::checkPermission('ZikulaBlocksModule::', "$blockinfo[bkey]:$blockinfo[title]:$blockinfo[bid]", ACCESS_EDIT)) { - throw new AccessDeniedException(); - } - - // check the blockinfo array - if (empty($blockinfo)) { - throw new NotFoundHttpException($this->__('Sorry! No such block found.')); - } - - // get the block's placements - $placements = ModUtil::apiFunc('ZikulaBlocksModule', 'user', 'getallblockspositions', array('bid' => $bid)); - $placements_pids = array(); - foreach ($placements as $placement) { - $placements_pids[] = $placement['pid']; - } - $blockinfo['placements'] = $placements_pids; - - // Load block - $modinfo = ModUtil::getInfo($blockinfo['mid']); - $blockObj = BlockUtil::load($modinfo['name'], $blockinfo['bkey']); - if (!$blockObj) { - throw new NotFoundHttpException($this->__('Sorry! No such block found.')); - } - - // Title - putting a title ad the head of each page reminds the user what - // they are doing - if (!empty($modinfo['name'])) { - $this->view->assign('modtitle', "$modinfo[name]/$blockinfo[bkey]"); - } - - // Add hidden block id to form - $this->view->assign('bid', $bid); - - // assign the block values to the template - $this->view->assign($blockinfo); - - // build and assign the list of modules - $homepage = array('_homepage_' => $this->__('Homepage')); - $modules = ModUtil::getAllMods(); - unset($modules['zikula']); - foreach ($modules as $name => $module) { - $modules[$name] = $module['displayname']; - } - asort($modules); - - $this->view->assign('mods', array_merge($homepage, $modules)); - - // assign block positions - $positions = ModUtil::apiFunc('ZikulaBlocksModule', 'user', 'getallpositions'); - $block_positions = array(); - foreach ($positions as $position) { - $block_positions[$position['pid']] = $position['name']; - } - $this->view->assign('block_positions', $block_positions); - - // Block-specific - $blockoutput = ''; - if (($blockObj instanceof Zikula_Controller_AbstractBlock) || ($blockObj instanceof AbstractBlockController)) { - $blockoutput = call_user_func(array($blockObj, 'modify'), $blockinfo); - } else { - $usname = preg_replace('/ /', '_', $modinfo['name']); - $updatefunc = $usname . '_' . $blockinfo['bkey'] . 'block_modify'; - if (function_exists($updatefunc)) { - $blockoutput = $updatefunc($blockinfo); - } - } - - // Block output - $this->view->assign('blockoutput', $blockoutput); - - // Tableless for blockoutput - if (!isset($GLOBALS['blocks_modules'][$blockinfo['mid']][$blockinfo['bkey']]['admin_tableless'])) { - $GLOBALS['blocks_modules'][$blockinfo['mid']][$blockinfo['bkey']]['admin_tableless'] = false; - } - - // Requirement for the block - if (!isset($GLOBALS['blocks_modules'][$blockinfo['mid']][$blockinfo['bkey']]['requirement'])) { - $GLOBALS['blocks_modules'][$blockinfo['mid']][$blockinfo['bkey']]['requirement'] = ''; - } - - // Assign blockinfo to the template - $this->view->assign($GLOBALS['blocks_modules'][$blockinfo['mid']][$blockinfo['bkey']]); - - // Refresh - $refreshtimes = array( - 60 => $this->__('One minute'), - 120 => $this->__('Two minutes'), - 300 => $this->__('Five minutes'), - 600 => $this->__('Ten minutes'), - 900 => $this->__('Fifteen minutes'), - 1800 => $this->__('Half an hour'), - 3600 => $this->__('One hour'), - 7200 => $this->__('Two hours'), - 14400 => $this->__('Four hours'), - 43200 => $this->__('Twelve hours'), - 86400 => $this->__('One day'), - 172800 => $this->__('Two days'), - 259200 => $this->__('Three days'), - 345600 => $this->__('Four days'), - 432000 => $this->__('Five days'), - 518400 => $this->__('Six days'), - 604800 => $this->__('Seven days')); - $this->view->assign('blockrefreshtimes', $refreshtimes); - - return new Response($this->view->fetch('Admin/modify.tpl')); - } - - /** - * @Route("/modify") - * @Method("POST") - * - * Update a block. - * - * @param Request $request - * int $bid block id to update. - * string $title the new title of the block. - * string $description the new description of the block. - * array $positions the new position(s) of the block. - * array $modules the modules to display the block on. - * string $url the new URL of the block. - * string $language the new language of the block. - * string $content the new content of the block. - * - * @throws NotFoundHttpException Thrown if the block to be updated doesn't exist - * - * @return RedirectResponse - */ - public function updateAction(Request $request) - { - $this->checkCsrfToken(); - - // Get parameters - $bid = $request->request->get('bid'); - $title = $request->request->get('title'); - $description = $request->request->get('description'); - $language = $request->request->get('language'); - $collapsable = $request->request->get('collapsable', 0); - $defaultstate = $request->request->get('defaultstate', 1); - $content = $request->request->get('content', ''); - $refresh = $request->request->get('refresh'); - $positions = $request->request->get('positions'); - $filter = $request->request->get('filters', array()); - $returntoblock = $request->request->get('returntoblock'); - - // not stored in a block - $redirect = $request->request->get('redirect', null); - $cancel = $request->request->get('cancel', null); - - if (isset($cancel)) { - if (isset($redirect) && !empty($redirect)) { - - return new RedirectResponse(urldecode($redirect)); - } - - return new RedirectResponse($this->get('router')->generate('zikulablocksmodule_admin_view', array(), RouterInterface::ABSOLUTE_URL)); - } - - - // Fix for null language - if (!isset($language)) { - $language = ''; - } - - // Get and update block info - $blockinfo = BlockUtil::getBlockInfo($bid); - - - $blockinfo['title'] = $title; - $blockinfo['description'] = $description; - $blockinfo['bid'] = $bid; - $blockinfo['language'] = $language; - $blockinfo['collapsable'] = $collapsable; - $blockinfo['defaultstate'] = $defaultstate; - $blockinfo['content'] = $content; - $blockinfo['refresh'] = $refresh; - $blockinfo['positions'] = $positions; - $blockinfo['filter'] = $filter; - - // Load block - $modinfo = ModUtil::getInfo($blockinfo['mid']); - $blockObj = BlockUtil::load($modinfo['name'], $blockinfo['bkey']); - if (!$blockObj) { - throw new NotFoundHttpException($this->__('Sorry! No such block found.')); - } - - // Do block-specific update - if (($blockObj instanceof Zikula_Controller_AbstractBlock) || ($blockObj instanceof AbstractBlockController)) { - $blockinfo = call_user_func(array($blockObj, 'update'), $blockinfo); - } else { - $usname = preg_replace('/ /', '_', $modinfo['name']); - $updatefunc = $usname . '_' . $blockinfo['bkey'] . 'block_update'; - if (function_exists($updatefunc)) { - $blockinfo = $updatefunc($blockinfo); + $filterForm = $filterFormClone; // set to empty form on 'clear' submission. } } + $filterData['sort-field'] = $sortField; + $filterData['sort-direction'] = $currentSortDirection; + $request->getSession()->set('zikulablocksmodule.filter', $filterData); // remember - if (!$blockinfo) { - return new RedirectResponse($this->get('router')->generate('zikulablocksmodule_admin_modify', array('bid' => $bid), RouterInterface::ABSOLUTE_URL)); - } - - // Pass to API - if (ModUtil::apiFunc('ZikulaBlocksModule', 'admin', 'update', $blockinfo)) { - // Success - $request->getSession()->getFlashBag()->add('status', $this->__('Done! Block saved.')); - } - - if (isset($redirect) && !empty($redirect)) { - - return new RedirectResponse(urldecode($redirect)); - } - - if (!empty($returntoblock)) { - - // load the block config again - return new RedirectResponse($this->get('router')->generate('zikulablocksmodule_admin_modify', array('bid' => $returntoblock), RouterInterface::ABSOLUTE_URL)); - } - - return new RedirectResponse($this->get('router')->generate('zikulablocksmodule_admin_view', array(), RouterInterface::ABSOLUTE_URL)); - } - - /** - * @Route("/new") - * @Method("GET") - * - * Display form for a new block. - * - * @param string $block - * - * @return Response symfony response object - * - * @throws AccessDeniedException Throw if the user doesn't have permission to add a block - * @throws \RuntimeException Throw if the list of blocks cannot be loaded - */ - public function newblockAction(Request $request) - { - // Security check - if (!SecurityUtil::checkPermission('ZikulaBlocksModule::', '::', ACCESS_ADD)) { - throw new AccessDeniedException(); - } - - // Get parameters if exists - $default = array( - 'title' => '', - 'description' => '', - 'language' => ZLanguage::getLanguageCode(), - 'blockid' => null, - 'positions' => array(), - 'collapsable' => 0, - 'defaultstate' => 1 - ); - $inputblock = $request->query->get('block', $default); - - // Block - // Load all blocks - $blocks = BlockUtil::loadAll(); - if (!$blocks) { - throw new \RuntimeException($this->__('Error! Could not load blocks.')); - } - - $blockinfo = array(); - foreach ($blocks as $moduleblocks) { - foreach ($moduleblocks as $block) { - $modinfo = ModUtil::getInfoFromName($block['module']); - $blockinfo[$block['mid'] . ':' . $block['bkey']] = $modinfo['displayname'] . '/' . $block['text_type_long']; - } - } - $this->view->assign('blockids', $blockinfo); + $sortableColumns = new SortableColumns($this->get('router'), 'zikulablocksmodule_admin_view'); + $sortableColumns->addColumn(new Column('bid')); // first added is automatically the default + $sortableColumns->addColumn(new Column('title')); + $sortableColumns->addColumn(new Column('blocktype')); + $sortableColumns->addColumn(new Column('language')); + $sortableColumns->addColumn(new Column('state')); + $sortableColumns->setOrderBy($sortableColumns->getColumn($sortField), $currentSortDirection); + $sortableColumns->setAdditionalUrlParameters(array( + 'position' => isset($filterData['position']) ? $filterData['position'] : null, + 'module' => isset($filterData['module']) ? $filterData['module'] : null, + 'language' => isset($filterData['language']) ? $filterData['language'] : null, + 'status' => isset($filterData['status']) ? $filterData['status'] : null, + )); - // assign block positions - $positions = ModUtil::apiFunc('ZikulaBlocksModule', 'user', 'getallpositions'); - $block_positions = array(); - foreach ($positions as $position) { - $block_positions[$position['pid']] = $position['name']; - } - $this->view->assign('block_positions', $block_positions); + $templateParameters = []; + $templateParameters['blocks'] = $this->getDoctrine()->getManager()->getRepository('ZikulaBlocksModule:BlockEntity')->getFilteredBlocks($filterData); + $templateParameters['positions'] = $this->getDoctrine()->getManager()->getRepository('ZikulaBlocksModule:BlockPositionEntity')->findAll();; + $templateParameters['filter_active'] = !empty($filterData['position']) || !empty($filterData['module']) || !empty($filterData['language']) || (!empty($filterData['active']) && in_array($filterData['active'], [0, 1])); + $templateParameters['sort'] = $sortableColumns->generateSortableColumns(); + $templateParameters['filterForm'] = $filterForm->createView(); - return new Response($this->view->assign('block', $inputblock) - ->fetch('Admin/newblock.tpl')); + return $templateParameters; } /** - * @Route("/new") - * @Method("POST") - * - * Create a new block. - * - * @param Request $request - * - * string $title the new title of the block. - * string $description the new description of the block. - * int $blockid block id to create. - * string $language the language to assign to the block. - * string $position the position of the block. - * - * @return RedirectResponse - * - * @throws \InvalidArgumentException Thrown if no block id is supplied - */ - public function createAction(Request $request) - { - $this->checkCsrfToken(); - - // Get parameters - $block = $request->request->get('block'); - - if ($block['blockid'] == '') { - $block['blockid'] = 'error'; - $request->getSession()->getFlashBag()->add('error', $this->__('You must choose a block.')); - $response = new RedirectResponse($this->get('router')->generate('zikulablocksmodule_admin_newblock', array('block' => $block), RouterInterface::ABSOLUTE_URL)); - - return $response; - } - - list($mid, $bkey) = explode(':', $block['blockid']); - $block['mid'] = $mid; - $block['bkey'] = $bkey; - - // Fix for null language - if (!isset($block['language'])) { - $block['language'] = ''; - } - - // Default values - $block['collapsable'] = isset($block['collapsable']) ? $block['collapsable'] : 0; - $block['defaultstate'] = isset($block['defaultstate']) ? $block['defaultstate'] : 1; - - // Pass to API - $bid = ModUtil::apiFunc('ZikulaBlocksModule', 'admin', 'create', $block); - - if ($bid != false) { - $request->getSession()->getFlashBag()->add('status', $this->__('Done! Block created.')); - - return new RedirectResponse($this->get('router')->generate('zikulablocksmodule_admin_modify', array('bid' => $bid), RouterInterface::ABSOLUTE_URL)); - } - - return new RedirectResponse($this->get('router')->generate('zikulablocksmodule_admin_view', array(), RouterInterface::ABSOLUTE_URL)); - } - - /** - * @Route("/delete") - * - * Delete a block. + * @Route("/config") + * @Theme("admin") + * @Template * * @param Request $request - * - * int bid the block id. - * bool confirm to delete block. - * - * @return Response symfony response object - * - * @throws AccessDeniedException Thrown if the user doesn't have delete permissions over the block - * @throws NotFoundHttpException Thrown the requested block doesn't exist + * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response */ - public function deleteAction(Request $request) + public function configAction(Request $request) { - // Get parameters - $bid = (int)$request->get('bid', null); // retrieves from GET then POST - $confirmation = $request->request->get('confirmation'); - - // Get details on current block - $blockinfo = BlockUtil::getBlockInfo($bid); - - // Security check - if (!SecurityUtil::checkPermission('ZikulaBlocksModule::', "$blockinfo[bkey]:$blockinfo[title]:$blockinfo[bid]", ACCESS_DELETE)) { + if (!$this->hasPermission('ZikulaBlocksModule::', '::', ACCESS_ADMIN)) { throw new AccessDeniedException(); } - if ($blockinfo == false) { - throw new NotFoundHttpException($this->__('Sorry! No such block found.')); - } + $form = $this->createFormBuilder($this->getVars()) + ->add('collapseable', 'checkbox', ['label' => __('Enable menu collapse icons'), + 'required' => false + ]) + ->add('save', 'submit', ['label' => 'Save']) + ->add('cancel', 'submit', ['label' => 'Cancel']) + ->getForm(); - // Check for confirmation - if (empty($confirmation)) { - // No confirmation yet - get one - // get the module info - $modinfo = ModUtil::getInfo($blockinfo['mid']); + $form->handleRequest($request); - if (!empty($modinfo['name'])) { - $this->view->assign('blockname', "$modinfo[name]/$blockinfo[bkey]"); - } else { - $this->view->assign('blockname', "Core/$blockinfo[bkey]"); + if ($form->isValid()) { + if ($form->get('save')->isClicked()) { + $this->setVars($form->getData()); + $this->addFlash('status', __('Done! Module configuration updated.')); } - - // add the block id - $this->view->assign('block', $blockinfo); - - return new Response($this->view->fetch('Admin/delete.tpl')); - } - - $this->checkCsrfToken(); - - // Pass to API - if (ModUtil::apiFunc('ZikulaBlocksModule', 'admin', 'delete', array('bid' => $bid))) { - // Success - $request->getSession()->getFlashBag()->add('status', $this->__('Done! Block deleted.')); - } - - return new RedirectResponse($this->get('router')->generate('zikulablocksmodule_admin_view', array(), RouterInterface::ABSOLUTE_URL)); - } - - /** - * @Route("/newposition/{name}") - * @Method("GET") - * - * Display a form to create a new block position. - * - * @param string $name - * - * @return Response symfony response object - * - * @throws AccessDeniedException Thrown if the user doesn't have admin access to the module - */ - public function newpositionAction($name = '') - { - // Security check - if (!SecurityUtil::checkPermission('ZikulaBlocksModule::', '::', ACCESS_ADMIN)) { - throw new AccessDeniedException(); - } - - return new Response($this->view->assign('name', $name) - ->fetch('Admin/newposition.tpl')); - } - - /** - * @Route("/newposition") - * @Method("POST") - * - * Display a form to create a new block position. - * - * @param Request $request - * - * @return RedirectResponse symfony response object - * - * @throws AccessDeniedException Thrown if the user doesn't have admin access to the module - * @throws \InvalidArgumentException Thrown if the position name is empty or not valid or - * if the position description is empty - */ - public function createpositionAction(Request $request) - { - $this->checkCsrfToken(); - - // Security check - if (!SecurityUtil::checkPermission('ZikulaBlocksModule::position', '::', ACCESS_ADMIN)) { - throw new AccessDeniedException(); - } - - // Get parameters - $position = $request->request->get('position'); - - // check our vars - if (!isset($position['name']) || empty($position['name']) || !preg_match('/^[a-z0-9_-]*$/i', $position['name'])) { - $request->getSession()->getFlashBag()->add('error', __('Invalid value received for the "name" field')); - - return new RedirectResponse($this->get('router')->generate('zikulablocksmodule_admin_newposition', array(), RouterInterface::ABSOLUTE_URL)); - } - // check our vars - if (!isset($position['description'])) { - $request->getSession()->getFlashBag()->add('error', __('Invalid value received for the "description" field')); - - return new RedirectResponse($this->get('router')->generate('zikulablocksmodule_admin_newposition', array(), RouterInterface::ABSOLUTE_URL)); - } - - // add the new block position - $pid = ModUtil::apiFunc('ZikulaBlocksModule', 'admin', 'createposition', array('name' => $position['name'], 'description' => $position['description'])); - - if ($pid) { - $request->getSession()->getFlashBag()->add('status', $this->__('Done! Block position created.')); - - return new RedirectResponse($this->get('router')->generate('zikulablocksmodule_admin_modifyposition', array('pid' => $pid), RouterInterface::ABSOLUTE_URL) . "#blockpositionform"); - } - - return new RedirectResponse($this->get('router')->generate('zikulablocksmodule_admin_view', array(), RouterInterface::ABSOLUTE_URL)); - } - - /** - * @Route("/modifyposition/{pid}", requirements={"pid" = "^[1-9]\d*$"}) - * @Method("GET") - * - * Display a form to create a new block position. - * - * @param integer $pid - * - * @return Response symfony response object - * - * @throws AccessDeniedException Thrown if the user doesn't have admin access to the module - */ - public function modifypositionAction($pid) - { - // get the block position - $position = ModUtil::apiFunc('ZikulaBlocksModule', 'user', 'getposition', array('pid' => $pid)); - - // Security check - if (!SecurityUtil::checkPermission("ZikulaBlocksModule::$position[name]", '::', ACCESS_ADMIN)) { - throw new AccessDeniedException(); - } - - // assign the position item - $this->view->assign('pid', $position['pid']) - ->assign('name', $position['name']) - ->assign('description', $position['description']); - - // get all blocks in the position - $block_placements = ModUtil::apiFunc('ZikulaBlocksModule', 'user', 'getblocksinposition', array('pid' => $pid)); - - // get all defined blocks - $allblocks = ModUtil::apiFunc('ZikulaBlocksModule', 'user', 'getall', array('active_status' => 0)); - foreach ($allblocks as $key => $allblock) { - $allblock = $allblock->toArray(); - // set the module that holds the block - $modinfo = ModUtil::getInfo($allblock['mid']); - $allblock['modname'] = $modinfo['name']; - $allblocks[$key] = $allblock; - } - - // loop over arrays forming a list of blocks not in the block positon and obtaining - // full details on those that are - $blocks = array(); - foreach ($block_placements as $blockplacement) { - $block = BlockUtil::getBlockInfo($blockplacement['bid']); - foreach ($allblocks as $key => $allblock) { - if ($allblock['bid'] == $blockplacement['bid']) { - unset($allblocks[$key]); - $block['modname'] = $allblock['modname']; - } + if ($form->get('cancel')->isClicked()) { + $this->addFlash('status', __('Operation cancelled.')); } - $blocks[] = $block; - } - - $this->view->assign('assignedblocks', $blocks) - ->assign('unassignedblocks', $allblocks); - - return new Response($this->view->fetch('Admin/modifyposition.tpl')); - } - - /** - * @Route("/modifyposition") - * @Method("POST") - * - * Display a form to create a new block position. - * - * @param Request $request - * - * @return RedirectResponse symfony response object - * - * @throws \InvalidArgumentException Thrown if the position id, name or description is not supplied - */ - public function updatepositionAction(Request $request) - { - $this->checkCsrfToken(); - - // Get parameters - $position = $request->request->get('position'); - - // check our vars - if (!isset($position['pid']) || !isset($position['name']) || !isset($position['description'])) { - throw new \InvalidArgumentException(__('Invalid arguments received')); - } - - // update the position - if (ModUtil::apiFunc('ZikulaBlocksModule', 'admin', 'updateposition', - array('pid' => $position['pid'], 'name' => $position['name'], 'description' => $position['description']))) { - // all done - $request->getSession()->getFlashBag()->add('status', $this->__('Done! Block position saved.')); - return new RedirectResponse($this->get('router')->generate('zikulablocksmodule_admin_view', array(), RouterInterface::ABSOLUTE_URL)); - } - - return new RedirectResponse($this->get('router')->generate('zikulablocksmodule_admin_modifyposition', array('pid' => $position['pid']), RouterInterface::ABSOLUTE_URL)); - } - - /** - * @Route("/deleteposition") - * - * Delete a block position. - * - * @param Request $request - * - * int $pid the id of the position to be deleted - * int $objectid generic object id maps to pid if present - * bool $confirmation confirmation that this item can be deleted - * - * @return Response symfony response if confirmation is null, RedirectResponse otherwise. - * - * @throws NotFoundHttpException Thrown if the position doesn't exist - * @throws AccessDeniedException Thrown if the user doesn't have permission to delete the position - */ - public function deletepositionAction(Request $request) - { - // check where to get the parameters from for this dual purpose controller - if ($request->isMethod('GET')) { - $pid = (int)$request->query->get('pid', null); - } elseif ($request->isMethod('POST')) { - $pid = (int)$request->request->get('pid', null); - } - - // confirmation can only come from a form so use post only here - $confirmation = $request->request->get('confirmation', null); - - $item = ModUtil::apiFunc('ZikulaBlocksModule', 'user', 'getposition', array('pid' => $pid)); - - if ($item == false) { - throw new NotFoundHttpException($this->__('Error! No such block position found.')); - } - - if (!SecurityUtil::checkPermission('ZikulaBlocksModule::position', "$item[name]::$pid", ACCESS_DELETE)) { - throw new AccessDeniedException(); + return $this->redirect($this->generateUrl('zikulablocksmodule_admin_view')); } - // Check for confirmation. - if (empty($confirmation)) { - // No confirmation yet - $this->view->assign('position', $item); - - return new Response($this->view->fetch('Admin/deleteposition.tpl')); - } - - $this->checkCsrfToken(); - - if (ModUtil::apiFunc('ZikulaBlocksModule', 'admin', 'deleteposition', array('pid' => $pid))) { - // Success - $request->getSession()->getFlashBag()->add('status', $this->__('Done! Block position deleted.')); - } - - return new RedirectResponse($this->get('router')->generate('zikulablocksmodule_admin_view', array(), RouterInterface::ABSOLUTE_URL)); - } - - /** - * @Route("/config") - * @Method("GET") - * - * Any config options would likely go here in the future. - * - * @return Response symfony response object - * - * @throws AccessDeniedException Thrown if the user doesn't have admin access to the module - */ - public function modifyconfigAction() - { - // Security check - if (!SecurityUtil::checkPermission('ZikulaBlocksModule::', '::', ACCESS_ADMIN)) { - throw new AccessDeniedException(); - } - - // assign all the module vars - $this->view->assign($this->getVars()); - - return new Response($this->view->fetch('Admin/modifyconfig.tpl')); - } - - /** - * @Route("/config") - * @Method("/POST") - * - * Set config variable(s). - * - * @param Request $request - * - * @return RedirectResponse - * - * @throws AccessDeniedException Thrown if the user doesn't have admin access to the module - */ - public function updateconfigAction(Request $request) - { - $this->checkCsrfToken(); - - // Security check - if (!SecurityUtil::checkPermission('ZikulaBlocksModule::', '::', ACCESS_ADMIN)) { - throw new AccessDeniedException(); - } - - $collapseable = $request->request->get('collapseable'); - - if (!isset($collapseable) || !is_numeric($collapseable)) { - $collapseable = 0; - } - - $this->setVar('collapseable', $collapseable); - - // the module configuration has been updated successfuly - $request->getSession()->getFlashBag()->add('status', $this->__('Done! Saved module configuration.')); - - return new RedirectResponse($this->get('router')->generate('zikulablocksmodule_admin_view', array(), RouterInterface::ABSOLUTE_URL)); + return [ + 'form' => $form->createView(), + ]; } -} +} \ No newline at end of file diff --git a/src/system/BlocksModule/Controller/AjaxController.php b/src/system/BlocksModule/Controller/AjaxController.php deleted file mode 100644 index bb26dfe31c..0000000000 --- a/src/system/BlocksModule/Controller/AjaxController.php +++ /dev/null @@ -1,125 +0,0 @@ -checkAjaxToken(); - if (!SecurityUtil::checkPermission('ZikulaBlocksModule::', '::', ACCESS_ADMIN)) { - - return new ForbiddenResponse($this->__('No permission for this action.')); - } - - $blockorder = $request->request->get('blockorder', array()); - $position = $request->request->get('position'); - - // remove all blocks from this position - $query = $this->entityManager->createQueryBuilder() - ->delete() - ->from('ZikulaBlocksModule:BlockPlacementEntity', 'p') - ->where('p.pid = :pid') - ->setParameter('pid', $position) - ->getQuery(); - $query->getResult(); - - // add new block positions - foreach ((array)$blockorder as $order => $bid) { - $placement = new BlockPlacementEntity(); - $placement->setPid($position); - $placement->setBid($bid); - $placement->setSortorder($order); - $this->entityManager->persist($placement); - } - $this->entityManager->flush(); - - return new AjaxResponse(array('result' => true)); - } - - /** - * @Route("/toggle", options={"expose"=true}) - * @Method("POST") - * - * Toggleblock. - * - * This function toggles active/inactive. - * - * @param Request $request - * - * bid int id of block to toggle. - * - * @return AjaxResponse|FatalResponse|ForbiddenResponse true or Ajax error - */ - public function toggleblockAction(Request $request) - { - $this->checkAjaxToken(); - if (!SecurityUtil::checkPermission('ZikulaBlocksModule::', '::', ACCESS_ADMIN)) { - - return new ForbiddenResponse($this->__('No permission for this action.')); - } - - $bid = $request->request->get('bid', -1); - - if ($bid == -1) { - - return new FatalResponse($this->__('No block ID passed.')); - } - - // read the block information - $blockinfo = BlockUtil::getBlockInfo($bid); - if ($blockinfo == false) { - - return new FatalResponse($this->__f('Error! Could not retrieve block information for block ID %s.', DataUtil::formatForDisplay($bid))); - } - - if ($blockinfo['active'] == 1) { - ModUtil::apiFunc('ZikulaBlocksModule', 'admin', 'deactivate', array('bid' => $bid)); - } else { - ModUtil::apiFunc('ZikulaBlocksModule', 'admin', 'activate', array('bid' => $bid)); - } - - return new AjaxResponse(array('bid' => $bid)); - } -} \ No newline at end of file diff --git a/src/system/BlocksModule/Controller/BlockController.php b/src/system/BlocksModule/Controller/BlockController.php new file mode 100644 index 0000000000..425673cf12 --- /dev/null +++ b/src/system/BlocksModule/Controller/BlockController.php @@ -0,0 +1,286 @@ +createFormBuilder() + ->add('bkey', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', [ + 'placeholder' => 'Choose a block type', + 'choices' => $this->get('zikula_blocks_module.api.block')->getAvailableBlockTypes(), + 'label' => 'Block type', + ]) + ->add('choose', 'Symfony\Component\Form\Extension\Core\Type\SubmitType') + ->getForm(); + $form->handleRequest($request); + if ($form->isValid()) { + $bkey = json_encode($form->getData()['bkey']); + + return $this->redirect($this->generateUrl('zikulablocksmodule_block_edit', ['bkey' => $bkey])); + } + + return $this->render('ZikulaBlocksModule:Admin:new.html.twig', [ + 'form' => $form->createView(), + ]); + } + + /** + * Create a new block or edit an existing block. + * + * @Route("/edit/{blockEntity}", requirements={"blockEntity" = "^[1-9]\d*$"}) + * @Theme("admin") + * @param Request $request + * @param BlockEntity $blockEntity + * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response + */ + public function editAction(Request $request, BlockEntity $blockEntity = null) + { + $accessLevelRequired = ACCESS_EDIT; + if (null === $blockEntity) { + $bKey = json_decode($request->query->get('bkey')); + if (empty($bKey)) { + + return $this->redirect('zikulablocksmodule_block_new'); + } + $blockEntity = new BlockEntity(); // sets defaults in constructor + $blockEntity->setBkey($bKey); + $accessLevelRequired = ACCESS_ADD; + } + + if (!$this->hasPermission('ZikulaBlocksModule::', $blockEntity->getBlocktype() . ':' . $blockEntity->getTitle() . ':' . $blockEntity->getBid(), $accessLevelRequired)) { + throw new AccessDeniedException(); + } + + $blockInstance = $this->get('zikula_blocks_module.api.block')->createInstanceFromBKey($blockEntity->getBkey()); + $blockType = $blockEntity->getBlocktype(); + if (empty($blockType)) { + $blockEntity->setBlocktype($blockInstance->getType()); + } + + $form = $this->createForm('Zikula\BlocksModule\Form\Type\BlockType', $blockEntity); + $form->handleRequest($request); + + list($moduleName, $blockFqCn) = explode(':', $blockEntity->getBkey()); + $renderedOutput = $this->getBlockModifyOutput($blockInstance, $blockEntity, $request); + if (($blockInstance instanceof \Zikula_Controller_AbstractBlock) && $blockInstance->info()['form_content']) { // @todo @deprecated remove at Core-2.0 + $renderedOutput = $this->formContentModify($request, $blockEntity); + } + + if ($form->isSubmitted() and $form->get('save')->isClicked() and $form->isValid()) { + $content = []; + if ($blockInstance instanceof BlockControllerInterface) { + $content = $blockInstance->modify($request, $blockEntity->getContent()); + } elseif ($blockInstance instanceof \Zikula_Controller_AbstractBlock) { // @todo remove this BC at Core-2.0 + if ($blockInstance->info()['form_content']) { + $content = $this->formContentModify($request); + } else { + $blockInfo = call_user_func([$blockInstance, 'update'], ['content' => $blockEntity->getContent()]); + $content = $blockInfo['content']; + } + } + $blockEntity->setContent($content); + // sort Filter array so keys are always sequential. + $filters = $blockEntity->getFilters(); + sort($filters); + $blockEntity->setFilters($filters); + /** @var \Doctrine\ORM\EntityManager $em */ + $em = $this->getDoctrine()->getManager(); + $module = $em->getRepository('ZikulaExtensionsModule:ExtensionEntity')->findOneBy(['name' => $moduleName]); + $blockEntity->setModule($module); + $em->persist($blockEntity); + $em->flush(); + $this->addFlash('status', __('Block saved!')); + + return $this->redirect($this->generateUrl('zikulablocksmodule_admin_view')); + } + if ($form->isSubmitted() and $form->get('cancel')->isClicked()) { + $this->addFlash('status', __('Operation cancelled.')); + + return $this->redirect($this->generateUrl('zikulablocksmodule_admin_view')); + } + + return $this->render('ZikulaBlocksModule:Admin:edit.html.twig', [ + 'moduleName' => $moduleName, + 'renderedOutput' => $renderedOutput, + 'form' => $form->createView(), + ]); + } + + /** + * @Route("/delete/{bid}", requirements={"bid" = "^[1-9]\d*$"}) + * @Theme("admin") + * + * Delete a block. + * + * @param Request $request + * @param BlockEntity $blockEntity + * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response + */ + public function deleteAction(Request $request, BlockEntity $blockEntity) + { + if (!$this->hasPermission('ZikulaBlocksModule::', $blockEntity->getBkey() . ':' . $blockEntity->getTitle() . ':' . $blockEntity->getBid(), ACCESS_DELETE)) { + throw new AccessDeniedException(); + } + + $form = $this->createFormBuilder() + ->add('delete', 'Symfony\Component\Form\Extension\Core\Type\SubmitType', ['label' => 'Delete']) + ->add('cancel', 'Symfony\Component\Form\Extension\Core\Type\SubmitType', ['label' => 'Cancel']) + ->getForm(); + + $form->handleRequest($request); + + if ($form->isValid()) { + if ($form->get('delete')->isClicked()) { + $em = $this->getDoctrine()->getManager(); + $em->remove($blockEntity); + $em->flush(); + $this->addFlash('status', __('Done! Block deleted.')); + } + if ($form->get('cancel')->isClicked()) { + $this->addFlash('status', __('Operation cancelled.')); + } + + return $this->redirect($this->generateUrl('zikulablocksmodule_admin_view')); + } + + return $this->render('ZikulaBlocksModule:Admin:delete.html.twig', [ + 'form' => $form->createView(), + 'block' => $blockEntity + ]); + } + + /** + * Ajax method to toggle the active status of a block. + * + * bid int id of block to toggle. + * + * @Route("/toggle-active", options={"expose"=true}) + * @Method("POST") + * @param Request $request + * @return JsonResponse|FatalResponse|ForbiddenResponse bid or Ajax error + */ + public function toggleblockAction(Request $request) + { + if (!$this->hasPermission('ZikulaBlocksModule::', '::', ACCESS_ADMIN)) { + + return new ForbiddenResponse($this->__('No permission for this action.')); + } + $bid = $request->request->get('bid', -1); + if ($bid == -1) { + + return new FatalResponse($this->__('No block ID passed.')); + } + $em = $this->getDoctrine()->getManager(); + $block = $em->find('ZikulaBlocksModule:BlockEntity', $bid); + $block->setActive($block->getActive() == BlockApi::BLOCK_ACTIVE ? BlockApi::BLOCK_INACTIVE : BlockApi::BLOCK_ACTIVE); + $em->flush(); + + return new JsonResponse(['bid' => $bid]); + } + + /** + * Get the html output from the block's `modify` method. + * + * @deprecated This method is not required in Core-2.0. Simply use + * `$output = $blockClassInstance->modify($request, $blockEntity->getContent());` + * @param $blockClassInstance + * @param BlockEntity $blockEntity + * @param Request $request + * @return mixed|string + */ + private function getBlockModifyOutput($blockClassInstance, BlockEntity $blockEntity, Request $request) + { + $output = ''; + if ($blockClassInstance instanceof BlockControllerInterface) { + $output = $blockClassInstance->modify($request, $blockEntity->getContent()); + } elseif ($blockClassInstance instanceof \Zikula_Controller_AbstractBlock) { // @todo remove this BC at Core-2.0 + $blockInfo = \BlockUtil::getBlockInfo($blockEntity->getBid()); + $blockInfo = $blockInfo ? $blockInfo : ['content' => '']; + $output = call_user_func([$blockClassInstance, 'modify'], $blockInfo); + } + + return $output; + } + + /** + * Handle modification of blocks with form_content = true + * + * @deprecated This option is no longer allowed in Core-2.0. Blocks must provide their own content handling. + * @param Request $request + * @return mixed|string + */ + private function formContentModify(Request $request, $blockEntity = null) + { + if (isset($blockEntity)) { + $options = ['data' => $blockEntity->getContent() == [] ? '' : $blockEntity->getContent()]; + } else { + $options = []; + } + $form = $this->createFormBuilder()->add('content', 'Symfony\Component\Form\Extension\Core\Type\TextareaType', $options)->getForm(); + $form->handleRequest($request); + if ($form->isValid()) { + + return $form->getData()['content']; + } + + return $this->renderView('ZikulaBlocksModule:Block:default_modify.html.twig', [ + 'form' => $form->createView(), + ]); + } + + /** + * @Route("/view/{bid}", requirements={"bid" = "^[1-9]\d*$"}, options={"expose"=true}) + * @Method("GET") + * + * Display a block. + * + * @param BlockEntity $blockEntity + * @return Response symfony response object + */ + public function viewAction(BlockEntity $blockEntity = null) + { + return $this->render('ZikulaBlocksModule:Admin:blockview.html.twig', [ + 'block' => $blockEntity, + ]); + } + +} \ No newline at end of file diff --git a/src/system/BlocksModule/Controller/PlacementController.php b/src/system/BlocksModule/Controller/PlacementController.php new file mode 100644 index 0000000000..9ce23583f3 --- /dev/null +++ b/src/system/BlocksModule/Controller/PlacementController.php @@ -0,0 +1,116 @@ +hasPermission('ZikulaBlocksModule::', '::', ACCESS_ADMIN)) { + throw new AccessDeniedException(); + } + + $allBlocks = $this->getDoctrine()->getManager()->getRepository('ZikulaBlocksModule:BlockEntity')->findAll(); + $assignedBlocks = []; + foreach ($positionEntity->getPlacements() as $blockPlacement) { + $bid = $blockPlacement->getBlock()->getBid(); + foreach ($allBlocks as $key => $allblock) { + if ($allblock->getBid() == $bid) { + unset($allBlocks[$key]); + } + } + $assignedBlocks[] = $blockPlacement->getBlock(); + } + + return [ + 'position' => $positionEntity, + 'positionChoices' => $this->getDoctrine()->getRepository('ZikulaBlocksModule:BlockPositionEntity')->getPositionChoiceArray(), + 'assignedblocks' => $assignedBlocks, + 'unassignedblocks' => $allBlocks + ]; + } + + /** + * @Route("/ajax/changeorder", options={"expose"=true, "i18n"=false}) + * @Method("POST") + * + * Change the block order. + * + * @param Request $request + * + * blockorder array of sorted blocks (value = block id) + * position int zone id + * + * @return JsonResponse|ForbiddenResponse true or Ajax error + */ + public function changeBlockOrderAction(Request $request) + { + if (!$this->hasPermission('ZikulaBlocksModule::', '::', ACCESS_ADMIN)) { + + return new ForbiddenResponse($this->__('No permission for this action.')); + } + + $blockorder = $request->request->get('blockorder', []); // [7, 1] + $position = $request->request->get('position'); // 1 + $em = $this->getDoctrine()->getManager(); + + // remove all block placements from this position + $query = $em->createQueryBuilder() + ->delete() + ->from('ZikulaBlocksModule:BlockPlacementEntity', 'p') + ->where('p.position = :position') + ->setParameter('position', $position) + ->getQuery(); + $query->getResult(); + + // add new block positions + foreach ((array)$blockorder as $order => $bid) { + $placement = new BlockPlacementEntity(); + $placement->setPosition($em->getReference('ZikulaBlocksModule:BlockPositionEntity', $position)); + $placement->setBlock($em->getReference('ZikulaBlocksModule:BlockEntity', $bid)); + $placement->setSortorder($order); + $em->persist($placement); + } + $em->flush(); + + return new JsonResponse(['result' => true]); + } +} \ No newline at end of file diff --git a/src/system/BlocksModule/Controller/PositionController.php b/src/system/BlocksModule/Controller/PositionController.php new file mode 100644 index 0000000000..7db5b02997 --- /dev/null +++ b/src/system/BlocksModule/Controller/PositionController.php @@ -0,0 +1,119 @@ +getName() : 'position'; + if (!$this->hasPermission('ZikulaBlocksModule::' . $permParam, '::', ACCESS_ADMIN)) { + throw new AccessDeniedException(); + } + + if (null === $positionEntity) { + $positionEntity = new BlockPositionEntity(); // sets defaults in constructor + } + + $form = $this->createForm('Zikula\BlocksModule\Form\Type\BlockPositionType', $positionEntity); + $form->handleRequest($request); + + if ($form->isValid()) { + if ($form->get('save')->isClicked()) { + /** @var \Doctrine\ORM\EntityManager $em */ + $em = $this->getDoctrine()->getManager(); + $em->persist($positionEntity); + $em->flush(); + $this->addFlash('status', __('Position saved!')); + } + if ($form->get('cancel')->isClicked()) { + $this->addFlash('status', __('Operation cancelled.')); + } + + return $this->redirect($this->generateUrl('zikulablocksmodule_admin_view')); + } + + return [ + 'form' => $form->createView(), + ]; + } + + /** + * @Route("/delete/{pid}", requirements={"pid" = "^[1-9]\d*$"}) + * @Theme("admin") + * @Template + * + * Delete a position. + * + * @param Request $request + * @param BlockPositionEntity $positionEntity + * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response + */ + public function deleteAction(Request $request, BlockPositionEntity $positionEntity) + { + if (!$this->hasPermission('ZikulaBlocksModule::position', $positionEntity->getName() .'::'. $positionEntity->getPid(), ACCESS_DELETE)) { + throw new AccessDeniedException(); + } + + $form = $this->createFormBuilder() + ->add('delete', 'Symfony\Component\Form\Extension\Core\Type\SubmitType', ['label' => 'Delete']) + ->add('cancel', 'Symfony\Component\Form\Extension\Core\Type\SubmitType', ['label' => 'Cancel']) + ->getForm(); + + $form->handleRequest($request); + + if ($form->isValid()) { + if ($form->get('delete')->isClicked()) { + $em = $this->getDoctrine()->getManager(); + $em->remove($positionEntity); + $em->flush(); + $this->addFlash('status', __('Done! Position deleted.')); + } + if ($form->get('cancel')->isClicked()) { + $this->addFlash('status', __('Operation cancelled.')); + } + + return $this->redirect($this->generateUrl('zikulablocksmodule_admin_view')); + } + + return [ + 'form' => $form->createView(), + 'position' => $positionEntity + ]; + } +} \ No newline at end of file diff --git a/src/system/BlocksModule/Controller/UserController.php b/src/system/BlocksModule/Controller/UserController.php index acda20c22f..0db64786a5 100644 --- a/src/system/BlocksModule/Controller/UserController.php +++ b/src/system/BlocksModule/Controller/UserController.php @@ -14,84 +14,27 @@ namespace Zikula\BlocksModule\Controller; use UserUtil; -use BlockUtil; use SecurityUtil; -use System; -use Symfony\Component\Security\Core\Exception\AccessDeniedException; -use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\RedirectResponse; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; // used in annotations - do not remove -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; // used in annotations - do not remove +use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; +use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; +use Zikula\Core\Controller\AbstractController; /** * User controllers for the blocks module */ -class UserController extends \Zikula_AbstractController +class UserController extends AbstractController { - - /** - * @Route("") - * - * The main blocks user function. - * - * @throws NotFoundHttpException Thrown when accessed to indicate this function isn't valid - * @return void - */ - public function indexAction() - { - throw new NotFoundHttpException(__('Sorry! This module is not designed or is not currently configured to be accessed in the way you attempted.')); - } - - /** - * @Route("/display") - * - * Display a block if is active - * - * int $bid The id of the block - * bool $showinactive Override active status of block - * - * @return Response symfony response object - * - * @throws AccessDeniedException Throw if the user doesn't have edit permissions to the module - */ - public function displayAction() - { - // Block Id - if passed - display the block - // check GET then POST - $bid = (int)$this->request->get('bid', null); - $showinactive = (int)$this->request->get('showinactive', null); - - // Security check for $showinactive only - if ($showinactive && !SecurityUtil::checkPermission('ZikulaBlocksModule::', '::', ACCESS_EDIT)) { - throw new AccessDeniedException(); - } - - if ($bid > 0) { - // {block} function in template is not checking for active status, so let's check here - $blockinfo = BlockUtil::getBlockInfo($bid); - if ($blockinfo['active'] || $showinactive) { - $this->view->assign('bid', $bid); - - return new Response($this->view->fetch('User/display.tpl')); - } - } - - return new Response(); - } - /** * @Route("/changestatus/{bid}", requirements={"bid" = "^[1-9]\d*$"}) * @Method("GET") * - * Change the status of a block. + * Invert the status of a block. * * @param Request $request * @param integer $bid * - * Invert the status of a given block id (collapsed/uncollapsed). - * * @return RedirectResponse */ public function changestatusAction(Request $request, $bid) @@ -99,17 +42,10 @@ public function changestatusAction(Request $request, $bid) $uid = UserUtil::getVar('uid'); $entity = 'ZikulaBlocksModule:UserBlockEntity'; - $item = $this->entityManager->getRepository($entity)->findOneBy(array('uid' => $uid, 'bid' => $bid)); - - if ($item['active'] == 1) { - $item['active'] = 0; - } else { - $item['active'] = 1; - } - - $this->entityManager->flush(); + $item = $this->getDoctrine()->getManager()->getRepository($entity)->findOneBy(array('uid' => $uid, 'bid' => $bid)); + $item->setActive($item->getActive() == 1 ? 0 : 1); + $this->getDoctrine()->getManager()->flush(); - // now lets get back to where we came from return new RedirectResponse($request->server->get('HTTP_REFERER')); } } \ No newline at end of file diff --git a/src/system/BlocksModule/DependencyInjection/Compiler/BlockCollectorPass.php b/src/system/BlocksModule/DependencyInjection/Compiler/BlockCollectorPass.php new file mode 100644 index 0000000000..c959ddc232 --- /dev/null +++ b/src/system/BlocksModule/DependencyInjection/Compiler/BlockCollectorPass.php @@ -0,0 +1,41 @@ +hasDefinition('zikula_blocks_module.internal.block_collector')) { + return; + } + + $definition = $container->getDefinition('zikula_blocks_module.internal.block_collector'); + + foreach ($container->findTaggedServiceIds('zikula.block') as $id => $tagParameters) { + foreach ($tagParameters as $tagParameter) { + if (!isset($tagParameter['module'])) { + throw new \InvalidArgumentException(sprintf('Service "%s" must define the "module" attribute on "zikula.block" tags.', $id)); + } + $module = $tagParameter['module']; + } + + $definition->addMethodCall('add', [$module . ':' . $id, new Reference($id)]); + } + } +} diff --git a/src/system/BlocksModule/DependencyInjection/ZikulaBlocksExtension.php b/src/system/BlocksModule/DependencyInjection/ZikulaBlocksExtension.php new file mode 100644 index 0000000000..d791d6e01b --- /dev/null +++ b/src/system/BlocksModule/DependencyInjection/ZikulaBlocksExtension.php @@ -0,0 +1,24 @@ +load('services.xml'); + } +} diff --git a/src/system/BlocksModule/Entity/BlockEntity.php b/src/system/BlocksModule/Entity/BlockEntity.php index fa3f1ee7bc..3a2827d98d 100644 --- a/src/system/BlocksModule/Entity/BlockEntity.php +++ b/src/system/BlocksModule/Entity/BlockEntity.php @@ -13,15 +13,17 @@ namespace Zikula\BlocksModule\Entity; -use Zikula\Core\Doctrine\EntityAccess; +use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\Validator\Constraints as Assert; +use Zikula\BlocksModule\Entity\BlockPlacementEntity; +use Zikula\Core\Doctrine\EntityAccess; +use Zikula\ExtensionsModule\Entity\ExtensionEntity; /** * Block entity class. * - * We use annotations to define the entity mappings to database (see http://www.doctrine-project.org/docs/orm/2.1/en/reference/basic-mapping.html). - * - * @ORM\Entity + * @ORM\Entity(repositoryClass="Zikula\BlocksModule\Entity\Repository\BlockRepository") * @ORM\Table(name="blocks",indexes={@ORM\Index(name="active_idx",columns={"active"})}) */ class BlockEntity extends EntityAccess @@ -38,10 +40,17 @@ class BlockEntity extends EntityAccess /** * The block key * + * @Assert\NotBlank() * @ORM\Column(type="string", length=255) */ private $bkey; + /** + * @Assert\NotBlank() + * @ORM\Column(type="string", length=255) + */ + private $blocktype; + /** * The block title * @@ -61,30 +70,24 @@ class BlockEntity extends EntityAccess * * A seralized array of block content variables * - * @ORM\Column(type="text") + * @ORM\Column(type="array") */ private $content; - /** - * The block url - * - * @ORM\Column(type="text") - */ - private $url; - /** * The id of the module owning the block * - * @ORM\Column(type="integer") - */ - private $mid; + * @ORM\ManyToOne(targetEntity="Zikula\ExtensionsModule\Entity\ExtensionEntity") + * @ORM\JoinColumn(name="mid", referencedColumnName="id") + **/ + private $module; /** * The display filter to apply to the block * - * @ORM\Column(type="array") + * @ORM\Column(name="filter", type="array") */ - private $filter; + private $filters; /** * The active status of the block @@ -93,27 +96,6 @@ class BlockEntity extends EntityAccess */ private $active; - /** - * Is the block collapseable - * - * @ORM\Column(type="integer") - */ - private $collapsable; - - /** - * The default display state of the block (collapsed, uncollapsed) - * - * @ORM\Column(type="integer") - */ - private $defaultstate; - - /** - * The refresh time for the block content - * - * @ORM\Column(type="integer") - */ - private $refresh; - /** * The last updated timestamp of the block * @@ -128,6 +110,14 @@ class BlockEntity extends EntityAccess */ private $language; + /** + * @ORM\OneToMany( + * targetEntity="Zikula\BlocksModule\Entity\BlockPlacementEntity", + * mappedBy="block", + * cascade={"remove", "persist"}, + * orphanRemoval=true) + */ + private $placements; /** * constructor @@ -137,16 +127,14 @@ public function __construct() $this->bkey = ''; $this->title = ''; $this->description = ''; - $this->content = ''; - $this->url = ''; - $this->mid = 0; - $this->filter = array(); + $this->blocktype = ''; + $this->content = []; + $this->module = 0; + $this->filters = array(); $this->active = 1; - $this->collapsable = 1; - $this->defaultstate = 1; - $this->refresh = 3600; $this->last_update = new \DateTime("now"); $this->language = ''; + $this->placements = new ArrayCollection(); } /** @@ -189,6 +177,22 @@ public function setBkey($bkey) $this->bkey = $bkey; } + /** + * @return string + */ + public function getBlocktype() + { + return $this->blocktype; + } + + /** + * @param string $blocktype + */ + public function setBlocktype($blocktype) + { + $this->blocktype = $blocktype; + } + /** * get the title of the block * @@ -250,43 +254,23 @@ public function setContent($content) } /** - * get the url of the block - * - * @return string the block's url - */ - public function getUrl() - { - return $this->url; - } - - /** - * set the url for the block - * - * @param string $url the block's url - */ - public function setUrl($url) - { - $this->url = $url; - } - - /** - * get the id of the module that the block belongs to + * get the module that the block belongs to * - * @return integer the module's id + * @return ExtensionEntity */ - public function getMid() + public function getModule() { - return $this->mid; + return $this->module; } /** - * set the id of the module that the block belongs to + * set the module that the block belongs to * - * @param integer $mid the module's id + * @param \Zikula\ExtensionsModule\Entity\ExtensionEntity $module */ - public function setMid($mid) + public function setModule(ExtensionEntity $module) { - $this->mid = $mid; + $this->module = $module; } /** @@ -294,9 +278,9 @@ public function setMid($mid) * * @return array the block's filters */ - public function getFilter() + public function getFilters() { - return $this->filter; + return $this->filters; } /** @@ -304,9 +288,9 @@ public function getFilter() * * @param array $filter the blocks's filters */ - public function setFilter($filter) + public function setFilters($filters) { - $this->filter = $filter; + $this->filters = $filters; } /** @@ -330,102 +314,103 @@ public function setActive($active) } /** - * get the collapsable status of the block + * get last update time of the block * - * @return integer the collapsable status number (0=not collapsable, 1=collapsable) + * @return \DateTime the block's last updated time */ - public function getCollapsable() + public function getLast_Update() { - return $this->collapsable; + return $this->last_update; } /** - * set the collapsable status of the block + * set the last updated time of the block * - * @param integer $collapsable the collapsable status number (0=inactive, 1=active) + * @param none */ - public function setCollapsable($collapsable) + public function setLast_Update() { - $this->collapsable = $collapsable; + $this->last_update = new \DateTime("now"); } /** - * get the default activation state of the block + * get the language of the block * - * @return integer the state number (0=inactive, 1=active) + * @return string the block's language */ - public function getDefaultstate() + public function getLanguage() { - return $this->defaultstate; + return $this->language; } /** - * set the default activation state of the block + * set the language of the block * - * @param integer $defaultstate the default activation state (0=inactive, 1=active) + * @param string $language the block's language */ - public function setDefaultstate($defaultstate) + public function setLanguage($language) { - $this->defaultstate = $defaultstate; + $this->language = $language; } - /** - * get the refresh rate of the block - * - * @return integer the refresh rate number - */ - public function getRefresh() + public function getPlacements() { - return $this->refresh; + return $this->placements; } - /** - * set the refresh rate of the block - * - * @param integer $refresh the refresh rate in milliseconds (1sec=1000ms) - */ - public function setRefresh($refresh) + public function addPlacement(BlockPlacementEntity $placement) { - $this->refresh = $refresh; + if (!$this->placements->contains($placement)) { + $this->placements->add($placement); + } } - /** - * get last update time of the block - * - * @return datetime the block's last updated time - */ - public function getLast_Update() + public function removePlacement(BlockPlacementEntity $placement) { - return $this->last_update; + if ($this->placements->contains($placement)) { + $this->placements->removeElement($placement); + } } /** - * set the last updated time of the block - * - * @param none + * Get an ArrayCollection of BlockPositionEntity that are assigned to this Block + * @return ArrayCollection */ - public function setLast_Update() + public function getPositions() { - $this->last_update = new \DateTime("now"); - } + $positions = new ArrayCollection(); + foreach($this->getPlacements() as $placement) { + $positions->add($placement->getPosition()); + } - /** - * get the language of the block - * - * @return string the block's language - */ - public function getLanguage() - { - return $this->language; + return $positions; } /** - * set the language of the block - * - * @param string $language the block's language + * Set BlockPlacementsEntity from provided ArrayCollection of positionEntity + * requires + * cascade={"remove, "persist"} + * orphanRemoval=true + * on the association of $this->placements + * @param ArrayCollection $positions */ - public function setLanguage($language) + public function setPositions(ArrayCollection $positions) { - $this->language = $language; + // remove placements and skip existing placements. + foreach ($this->placements as $placement) { + if (!$positions->contains($placement->getPosition())) { + $this->placements->removeElement($placement); + } else { + $positions->removeElement($placement->getPosition()); // remove from positions to add. + } + } + + // add new placements + foreach ($positions as $position) { + $placement = new BlockPlacementEntity(); + $placement->setPosition($position); + // sortorder is irrelevant at this stage. + $placement->setBlock($this); // auto-adds placement + } } } diff --git a/src/system/BlocksModule/Entity/BlockPlacementEntity.php b/src/system/BlocksModule/Entity/BlockPlacementEntity.php index 04dbf5a124..502ca7c7d6 100644 --- a/src/system/BlocksModule/Entity/BlockPlacementEntity.php +++ b/src/system/BlocksModule/Entity/BlockPlacementEntity.php @@ -19,10 +19,10 @@ /** * BlockPlacement entity class. * - * We use annotations to define the entity mappings to database (see http://www.doctrine-project.org/docs/orm/2.1/en/reference/basic-mapping.html). - * * @ORM\Entity * @ORM\Table(name="block_placements",indexes={@ORM\Index(name="bid_pid_idx",columns={"bid","pid"})}) + * + * @ORM\HasLifecycleCallbacks */ class BlockPlacementEntity extends EntityAccess { @@ -30,17 +30,20 @@ class BlockPlacementEntity extends EntityAccess * The id of the block postion * * @ORM\Id - * @ORM\Column(type="integer") + * @ORM\ManyToOne(targetEntity="Zikula\BlocksModule\Entity\BlockPositionEntity", inversedBy="placements") + * @ORM\JoinColumn(name="pid", referencedColumnName="pid", nullable=false) */ - private $pid; + private $position; /** * The id of the block * + * @var \Zikula\BlocksModule\Entity\BlockEntity * @ORM\Id - * @ORM\Column(type="integer") + * @ORM\ManyToOne(targetEntity="Zikula\BlocksModule\Entity\BlockEntity", inversedBy="placements") + * @ORM\JoinColumn(name="bid", referencedColumnName="bid", nullable=false) */ - private $bid; + private $block; /** * The sort order of the block within the position @@ -55,55 +58,59 @@ class BlockPlacementEntity extends EntityAccess */ public function __construct() { - $this->pid = 0; - $this->bid = 0; $this->sortorder = 0; } /** - * get the id of the placement in the placement/block association - * - * @return integer the placement's id in the placement/block association + * @return BlockPositionEntity */ - public function getPid() + public function getPosition() { - return $this->pid; + return $this->position; } - /** - * set the id for the placement in the placement/block association - * - * @param integer $pid the placement's id in the placement/block association - */ - public function setPid($pid) + public function setPosition(BlockPositionEntity $position = null) { - $this->pid = $pid; + if ($this->position !== null) { + $this->position->removePlacement($this); + } + + if ($position !== null) { + $position->addPlacement($this); + } + + $this->position = $position; + + return $this; } /** - * get the id of the block in the placement/block association - * - * @return integer the block's id in the placement/block association + * @return BlockEntity */ - public function getBid() + public function getBlock() { - return $this->bid; + return $this->block; } - /** - * set the id for the block in the placement/block association - * - * @param integer $bid the block's id in the placement/block association - */ - public function setBid($bid) + public function setBlock(BlockEntity $block = null) { - $this->bid = $bid; + if ($this->block !== null) { + $this->block->removePlacement($this); + } + + if ($block !== null) { + $block->addPlacement($this); + } + + $this->block = $block; + + return $this; } /** - * get the sortorder of the placement/block association + * get the sortorder of the placement * - * @return integer the placement/block association sortorder + * @return integer the placement */ public function getSortorder() { @@ -111,12 +118,39 @@ public function getSortorder() } /** - * set the sortorder for the placement/block association + * set the sortorder for the placement * - * @param integer $sortorder the placement/block association sortorder + * @param integer $sortorder the placement */ public function setSortorder($sortorder) { $this->sortorder = $sortorder; } + + /** + * @ORM\PreRemove + */ + public function preRemoveCallback() + { + $this->setPosition(null); + $this->setBlock(null); + } + + /** + * @deprecated + * @return mixed + */ + public function getPid() + { + return $this->position->getPid(); + } + + /** + * @deprecated + * @return int + */ + public function getBid() + { + return $this->block->getBid(); + } } diff --git a/src/system/BlocksModule/Entity/BlockPositionEntity.php b/src/system/BlocksModule/Entity/BlockPositionEntity.php index 538cbdd530..1b7b417742 100644 --- a/src/system/BlocksModule/Entity/BlockPositionEntity.php +++ b/src/system/BlocksModule/Entity/BlockPositionEntity.php @@ -13,15 +13,15 @@ namespace Zikula\BlocksModule\Entity; -use Zikula\Core\Doctrine\EntityAccess; +use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\Validator\Constraints as Assert; +use Zikula\Core\Doctrine\EntityAccess; /** * BlockPosition entity class. * - * We use annotations to define the entity mappings to database (see http://www.doctrine-project.org/docs/orm/2.1/en/reference/basic-mapping.html). - * - * @ORM\Entity + * @ORM\Entity(repositoryClass="Zikula\BlocksModule\Entity\Repository\BlockPositionRepository") * @ORM\Table(name="block_positions",indexes={@ORM\Index(name="name_idx",columns={"name"})}) */ class BlockPositionEntity extends EntityAccess @@ -38,6 +38,8 @@ class BlockPositionEntity extends EntityAccess /** * The name of the block position * + * @Assert\Regex("/^[a-zA-Z0-9\-\_]+$/") + * @Assert\Length(max="255") * @ORM\Column(type="string", length=255) */ private $name; @@ -45,10 +47,19 @@ class BlockPositionEntity extends EntityAccess /** * The description of the block position * + * @Assert\Length(max="255") * @ORM\Column(type="string", length=255) */ private $description; + /** + * @ORM\OneToMany( + * targetEntity="Zikula\BlocksModule\Entity\BlockPlacementEntity", + * mappedBy="position", + * cascade={"remove"}) + * @ORM\OrderBy({"sortorder" = "ASC"}) + */ + private $placements; /** * constructor @@ -57,6 +68,7 @@ public function __construct() { $this->name = ''; $this->description = ''; + $this->placements = new ArrayCollection(); } /** @@ -118,4 +130,23 @@ public function setDescription($description) { $this->description = $description; } + + public function getPlacements() + { + return $this->placements; + } + + public function addPlacement(BlockPlacementEntity $placement) + { + if (!$this->placements->contains($placement)) { + $this->placements->add($placement); + } + } + + public function removePlacement(BlockPlacementEntity $placement) + { + if ($this->placements->contains($placement)) { + $this->placements->removeElement($placement); + } + } } diff --git a/src/system/BlocksModule/Entity/Repository/BlockPositionRepository.php b/src/system/BlocksModule/Entity/Repository/BlockPositionRepository.php new file mode 100644 index 0000000000..68de4a42fb --- /dev/null +++ b/src/system/BlocksModule/Entity/Repository/BlockPositionRepository.php @@ -0,0 +1,44 @@ + $name]); + } + + /** + * Get an array of position names indexed by the id + * @return array + */ + public function getPositionChoiceArray() + { + $positions = $this->getEntityManager()->createQueryBuilder() + ->select('p.pid, p.name') + ->from('ZikulaBlocksModule:BlockPositionEntity', 'p', 'p.pid') + ->getQuery() + ->getResult(); + foreach ($positions as $id => $row) { + $positions[$id] = $row['name']; + } + + return $positions; + } +} \ No newline at end of file diff --git a/src/system/BlocksModule/Entity/Repository/BlockRepository.php b/src/system/BlocksModule/Entity/Repository/BlockRepository.php new file mode 100644 index 0000000000..203ffcba96 --- /dev/null +++ b/src/system/BlocksModule/Entity/Repository/BlockRepository.php @@ -0,0 +1,56 @@ +_em->createQueryBuilder(); + $query = $qb->select('b') + ->from($this->_entityName, 'b'); + if (isset($filters['position'])) { + $subQb = $this->_em->createQueryBuilder(); + $query + ->join('b.placements', 'p') + ->where($qb->expr()->in('p.position', + $subQb->select('bp') + ->from('ZikulaBlocksModule:BlockPositionEntity', 'bp') + ->where('bp.pid = ?1') + ->getDQL() + )) + ->setParameter(1, $filters['position']); + unset($filters['position']); + } + $paramIndex = 2; + $sortField = isset($filters['sort-field']) ? $filters['sort-field'] : 'bid'; + $sortDirection = isset($filters['sort-direction']) ? $filters['sort-direction'] : 'ASC'; + unset($filters['sort-field'], $filters['sort-direction']); + foreach ($filters as $key => $value) { + if (!isset($value)) { + unset($filters[$key]); + } else { + $query->andWhere($qb->expr()->eq('b.' . $key, '?' . $paramIndex)) + ->setParameter($paramIndex, $value); + } + } + $query->orderBy('b.' . $sortField, $sortDirection); + + return $query->getQuery()->getResult(); + } +} \ No newline at end of file diff --git a/src/system/BlocksModule/Entity/RepositoryInterface/BlockPositionRepositoryInterface.php b/src/system/BlocksModule/Entity/RepositoryInterface/BlockPositionRepositoryInterface.php new file mode 100644 index 0000000000..b23bbe8038 --- /dev/null +++ b/src/system/BlocksModule/Entity/RepositoryInterface/BlockPositionRepositoryInterface.php @@ -0,0 +1,21 @@ +add('sort-field', 'hidden') + ->add('sort-direction', 'hidden') + ->add('position', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', [ + 'choices' => $options['positionChoices'], + 'required' => false, + 'placeholder' => $options['translator']->__('All'), + 'attr' => ['class' => 'input-sm'] + ]) + ->add('module', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', [ + 'choices' => $options['moduleChoices'], + 'required' => false, + 'placeholder' => $options['translator']->__('All'), + 'attr' => ['class' => 'input-sm'] + ]) + ->add('language', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', [ + 'choices' => \ZLanguage::getInstalledLanguageNames(), + 'required' => false, + 'placeholder' => $options['translator']->__('All'), + 'attr' => ['class' => 'input-sm'] + ]) + ->add('active', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', [ + 'choices' => [ + BlockApi::BLOCK_ACTIVE => $options['translator']->__('Active'), + BlockApi::BLOCK_INACTIVE => $options['translator']->__('Inactive'), + ], + 'required' => false, + 'placeholder' => $options['translator']->__('All'), + 'attr' => ['class' => 'input-sm'] + ]) + ->add('filterButton', 'submit', [ + 'icon' => 'fa-filter fa-lg', + 'label' => __('Filter'), + 'attr' => ['class' => "btn btn-default btn-sm"] + ]) + ; + } + + public function getBlockPrefix() + { + return 'zikulablocksmodule_adminviewfilter'; + } + + /** + * @param OptionsResolver $resolver + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'attr' => [ + 'class' => 'form form-inline', + ], + 'translator' => null, + 'moduleChoices' => [], + 'positionChoices' => [] + ]); + } +} \ No newline at end of file diff --git a/src/system/BlocksModule/Form/Type/BlockFilterType.php b/src/system/BlocksModule/Form/Type/BlockFilterType.php new file mode 100644 index 0000000000..c441830da2 --- /dev/null +++ b/src/system/BlocksModule/Form/Type/BlockFilterType.php @@ -0,0 +1,66 @@ +blockFilterApi = $blockFilterApi; + } + + + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder + ->add('attribute', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', [ + 'choices' => $this->blockFilterApi->getFilterAttributeChoices(), + 'choices_as_values' => true, + ]) + ->add('queryParameter', 'Symfony\Component\Form\Extension\Core\Type\TextType', ['required' => false]) + ->add('comparator', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', [ + 'choices' => [ + '==' => '==', + '!=' => '!=', + '>=' => '>=', + '<=' => '<=', + '>' => '>', + '<' => '<', + 'in_array' => 'in_array', + '!in_array' => '!in_array' + ], + 'choices_as_values' => true, + ]) + ->add('value', 'Symfony\Component\Form\Extension\Core\Type\TextType') + ; + } + + public function getBlockPrefix() + { + return 'zikulablocksmodule_blockfilter'; + } +} \ No newline at end of file diff --git a/src/system/BlocksModule/Form/Type/BlockPositionType.php b/src/system/BlocksModule/Form/Type/BlockPositionType.php new file mode 100644 index 0000000000..453d0ee10f --- /dev/null +++ b/src/system/BlocksModule/Form/Type/BlockPositionType.php @@ -0,0 +1,47 @@ +add('pid', 'Symfony\Component\Form\Extension\Core\Type\HiddenType') + ->add('name', 'Symfony\Component\Form\Extension\Core\Type\TextType') + ->add('description', 'Symfony\Component\Form\Extension\Core\Type\TextType') + ->add('save', 'Symfony\Component\Form\Extension\Core\Type\SubmitType') + ->add('cancel', 'Symfony\Component\Form\Extension\Core\Type\SubmitType') + ; + } + + public function getBlockPrefix() + { + return 'zikulablocksmodule_blockposition'; + } + + /** + * @param OptionsResolver $resolver + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'data_class' => 'Zikula\BlocksModule\Entity\BlockPositionEntity', + ]); + } +} \ No newline at end of file diff --git a/src/system/BlocksModule/Form/Type/BlockType.php b/src/system/BlocksModule/Form/Type/BlockType.php new file mode 100644 index 0000000000..8dffc71df7 --- /dev/null +++ b/src/system/BlocksModule/Form/Type/BlockType.php @@ -0,0 +1,100 @@ +blockApi = $blockApi; + $this->blockFilterApi = $blockFilterApi; + $this->translator = $translator; + } + + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder + ->add('bid', 'Symfony\Component\Form\Extension\Core\Type\HiddenType') + ->add('bkey', 'Symfony\Component\Form\Extension\Core\Type\HiddenType') + ->add('blocktype', 'Symfony\Component\Form\Extension\Core\Type\HiddenType') + ->add($builder->create('title', 'Symfony\Component\Form\Extension\Core\Type\TextType', [ + 'required' => false + ])->addModelTransformer(new NullToEmptyTransformer())) + ->add($builder->create('description', 'Symfony\Component\Form\Extension\Core\Type\TextType', [ + 'required' => false + ])->addModelTransformer(new NullToEmptyTransformer())) + ->add($builder->create('language', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', [ + 'choices' => \ZLanguage::getInstalledLanguageNames(), + 'required' => false, + 'placeholder' => $this->translator->__('All') + ])->addModelTransformer(new NullToEmptyTransformer())) + ->add('positions', 'Symfony\Bridge\Doctrine\Form\Type\EntityType', [ + 'class' => 'Zikula\BlocksModule\Entity\BlockPositionEntity', + 'choice_label' => 'name', + 'multiple' => true, + 'required' => false, + ]) + ->add('filters', 'Symfony\Component\Form\Extension\Core\Type\CollectionType', [ + 'entry_type' => 'Zikula\BlocksModule\Form\Type\BlockFilterType', + 'allow_add' => true, + 'allow_delete' => true, + 'label' => 'Custom filters', + 'required' => false + ]) + ->add('save', 'Symfony\Component\Form\Extension\Core\Type\SubmitType') + ->add('cancel', 'Symfony\Component\Form\Extension\Core\Type\SubmitType') + ; + } + + public function getBlockPrefix() + { + return 'zikulablocksmodule_block'; + } + + /** + * @param OptionsResolver $resolver + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'data_class' => 'Zikula\BlocksModule\Entity\BlockEntity', + ]); + } +} \ No newline at end of file diff --git a/src/system/BlocksModule/Helper/HookHelper.php b/src/system/BlocksModule/Helper/HookHelper.php new file mode 100644 index 0000000000..1f6ac478a8 --- /dev/null +++ b/src/system/BlocksModule/Helper/HookHelper.php @@ -0,0 +1,27 @@ +__('HTML Block content hook')); + $bundle->addEvent('form_edit', 'blocks.ui_hooks.htmlblock.content.form_edit'); + $this->registerHookSubscriberBundle($bundle); + } +} \ No newline at end of file diff --git a/src/system/BlocksModule/Helper/InstallerHelper.php b/src/system/BlocksModule/Helper/InstallerHelper.php new file mode 100644 index 0000000000..ed41869524 --- /dev/null +++ b/src/system/BlocksModule/Helper/InstallerHelper.php @@ -0,0 +1,92 @@ + '_zkModule', + 'ftype' => '_zkType', + 'fname' => '_zkFunc', + 'fargs' => 'fargs', + ]; + if (count($filters) <= 1) { + foreach ($filters as $filter) { + foreach ($filter as $parameter => $value) { + if ($parameter == 'fargs') { + parse_str($value, $queryVars); + foreach ($queryVars as $queryVarName => $queryVarValue) { + $newFilter[] = [$queryVarName, '==', $queryVarValue]; + } + } else { + $newFilter[] = [$legacyFieldMap[$parameter], '==', $value]; + } + } + } + } else { + $parameterValues = []; + foreach ($filters as $filter) { + foreach ($filter as $parameter => $value) { + // re-map values to array + $parameterValues[$legacyFieldMap[$parameter]][] = $value; + } + } + foreach ($parameterValues as $parameter => $valueArray) { + if ($parameter == 'fargs') { + $queryVarValues = []; + foreach ($valueArray as $value) { + parse_str($value, $queryVars); + foreach ($queryVars as $queryVarName => $queryVarValue) { + // re-map values to array + $queryVarValues[$queryVarName][] = $queryVarValue; + } + } + foreach ($queryVarValues as $varName => $varValue) { + $newFilter[] = [$varName, 'in_array', array_unique($varValue)]; + } + } else { + $newFilter[] = [$parameter, 'in_array', array_unique($valueArray)]; + } + } + } + + return $newFilter; + } + + public function upgradeBkeyToFqClassname(KernelInterface $kernel, BlockEntity $blockEntity) + { + $moduleName = $blockEntity->getModule()->getName(); + try { + $moduleBundle = $kernel->getModule($moduleName); + $blockClassName = $moduleBundle->getNamespace() . '\Block\\' . ucwords($blockEntity->getBkey()); + $blockClassName = preg_match('/.*Block$/', $blockClassName) ? $blockClassName : $blockClassName . 'Block'; + } catch (\Exception $e) { + $moduleBundle = null; + $blockClassName = '\\' . ucwords($moduleName).'\\'.'Block\\'.ucwords($blockEntity->getBkey()); + $blockClassName = preg_match('/.*Block$/', $blockClassName) ? $blockClassName : $blockClassName . 'Block'; + $blockClassNameOld = '\\' . ucwords($moduleName) . '_' . 'Block_' . ucwords($blockEntity->getBkey()); + $blockClassName = class_exists($blockClassName) ? $blockClassName : $blockClassNameOld; + } + + return "$moduleName:$blockClassName"; + } + +} \ No newline at end of file diff --git a/src/system/BlocksModule/Helper/ServiceNameHelper.php b/src/system/BlocksModule/Helper/ServiceNameHelper.php new file mode 100644 index 0000000000..224d90296c --- /dev/null +++ b/src/system/BlocksModule/Helper/ServiceNameHelper.php @@ -0,0 +1,33 @@ + 'acme.foo_bundle.bar.foo_bar' + * @param $classname + * @return string + */ + public function generateServiceNameFromClassName($classname) + { + $classname = str_replace(['\\', '_'], '.', $classname); // @todo in Core-2.0 the '_' can be removed. + $classname = Container::underscore($classname); + + return trim($classname, "\\_. \t\n\r\0\x0B"); + } +} \ No newline at end of file diff --git a/src/system/BlocksModule/Resources/config/services.xml b/src/system/BlocksModule/Resources/config/services.xml new file mode 100644 index 0000000000..5c09fd3164 --- /dev/null +++ b/src/system/BlocksModule/Resources/config/services.xml @@ -0,0 +1,74 @@ + + + + + + Zikula\BlocksModule\Container\LinkContainer + Zikula\BlocksModule\Entity\Repository\BlockPositionRepository + Zikula\BlocksModule\Api\BlockFactoryApi + Zikula\BlocksModule\Api\BlockApi + Zikula\BlocksModule\Api\BlockFilterApi + Zikula\BlocksModule\Collector\BlockCollector + Zikula\BlocksModule\Form\Type\BlockFilterType + Zikula\BlocksModule\Form\Type\BlockType + Zikula\BlocksModule\Twig\Extension\BlocksExtension + + + + + + + + + + + + + Zikula\BlocksModule\Entity\BlockPositionEntity + + + + + + + + + + + + + %kernel.root_dir% + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/system/BlocksModule/Resources/public/css/style.css b/src/system/BlocksModule/Resources/public/css/style.css index 80a539b1a1..5c38dbc399 100644 --- a/src/system/BlocksModule/Resources/public/css/style.css +++ b/src/system/BlocksModule/Resources/public/css/style.css @@ -38,15 +38,20 @@ button .deletebutton { display: none; } -ul.errorlist { +ul.errorlist, ul#filters { padding: 0; margin: 0; } +ul#filters li { + list-style-type: none; + margin: 0 0 4px; +} + ul.errorlist li { padding: 0; margin: 0; - list-style-image: url(../../../../../../../images/icons/extrasmall/error.png); + list-style-image: url(../../../../../images/icons/extrasmall/error.png); } .activationbutton { diff --git a/src/system/BlocksModule/Resources/public/js/Zikula.Blocks.Admin.Common.js b/src/system/BlocksModule/Resources/public/js/Zikula.Blocks.Admin.Common.js index 27ebeb7987..81ea838c77 100644 --- a/src/system/BlocksModule/Resources/public/js/Zikula.Blocks.Admin.Common.js +++ b/src/system/BlocksModule/Resources/public/js/Zikula.Blocks.Admin.Common.js @@ -13,16 +13,21 @@ a.after(''); $.ajax({ - url: Routing.generate('zikulablocksmodule_ajax_toggleblock'), + url: Routing.generate('zikulablocksmodule_block_toggleblock'), data: { bid: bid - }, - success: function(response) { - $('#spin' + bid).remove(); - // toggle label - a.parent().find('a').toggleClass('hide'); } - }); + }) + .done(function(response) { + // toggle label + a.parent().find('a').toggleClass('hide'); + }) + .fail(function(jqXHR, textStatus) { + alert( "error: " + textStatus ); + }) + .always(function() { + $('#spin' + bid).remove(); + }) }); }); })(jQuery); diff --git a/src/system/BlocksModule/Resources/public/js/Zikula.Blocks.Admin.Edit.js b/src/system/BlocksModule/Resources/public/js/Zikula.Blocks.Admin.Edit.js new file mode 100644 index 0000000000..33225a398c --- /dev/null +++ b/src/system/BlocksModule/Resources/public/js/Zikula.Blocks.Admin.Edit.js @@ -0,0 +1,34 @@ +// Copyright Zikula Foundation 2015 - license GNU/LGPLv3 (or at your option, any later version). + +( function($) { + $(document).ready(function() { + $('#add-filter').click(function(e) { + e.preventDefault(); + + var filterList = $('ul#filters'); + + // grab the prototype template + var newWidget = filterList.attr('data-prototype'); + // replace the "__name__" used in the id and name of the prototype with a unique number + newWidget = newWidget.replace(/__name__/g, filterCount); + filterCount++; + + // create a new list element and add it to the list + $(newWidget).appendTo(filterList); + }); + $('.delete-filter').click(function(e) { + e.preventDefault(); + var row = $(this).closest('li'); + row.remove(); + }); + $('#filters').on('change', '.attribute-selector', function() { + var value = $(this).val(); + var queryParamInput = $(this).parent('li').find(".queryParameter"); + if (value == 'query param' || value == '_route_params') { + queryParamInput.prop('disabled', false); + } else { + queryParamInput.prop('disabled', true); + } + }); + }) +})(jQuery); diff --git a/src/system/BlocksModule/Resources/public/js/Zikula.Blocks.Admin.Modifyposition.js b/src/system/BlocksModule/Resources/public/js/Zikula.Blocks.Admin.Modifyposition.js index 0b367a2ad9..565ba27fd8 100644 --- a/src/system/BlocksModule/Resources/public/js/Zikula.Blocks.Admin.Modifyposition.js +++ b/src/system/BlocksModule/Resources/public/js/Zikula.Blocks.Admin.Modifyposition.js @@ -35,12 +35,20 @@ }); $.ajax({ - url: Routing.generate('zikulablocksmodule_ajax_changeblockorder'), + url: Routing.generate('zikulablocksmodule_placement_changeblockorder'), data: { - position: $('#position').val(), + position: $('#position').data('position'), blockorder: blockorder } - }); + }) + .done(function(message) { + $('#feedback').fadeIn(200).fadeOut(3500); + //var descriptionDiv = $('#zikulablocksmodule_block_description').parents('.form-group'); + //descriptionDiv.after(message.result); + }) + .fail(function(jqXHR, textStatus) { + alert( "error: " + textStatus ); + }) } }).disableSelection(); diff --git a/src/system/BlocksModule/Resources/public/js/Zikula.Blocks.Admin.New.js b/src/system/BlocksModule/Resources/public/js/Zikula.Blocks.Admin.New.js new file mode 100644 index 0000000000..944e7f5347 --- /dev/null +++ b/src/system/BlocksModule/Resources/public/js/Zikula.Blocks.Admin.New.js @@ -0,0 +1,10 @@ +// Copyright Zikula Foundation 2015 - license GNU/LGPLv3 (or at your option, any later version). + +( function($) { + $(document).ready(function() { + $('#form_choose').hide(); + $('#form_bkey').change(function() { + this.form.submit(); + }); + }) +})(jQuery); diff --git a/src/system/BlocksModule/Resources/public/js/Zikula.Blocks.Admin.View.js b/src/system/BlocksModule/Resources/public/js/Zikula.Blocks.Admin.View.js new file mode 100644 index 0000000000..0aba93a6c1 --- /dev/null +++ b/src/system/BlocksModule/Resources/public/js/Zikula.Blocks.Admin.View.js @@ -0,0 +1,10 @@ +// Copyright Zikula Foundation 2015 - license GNU/LGPLv3 (or at your option, any later version). + +( function($) { + $(document).ready(function() { + $('#zikulablocksmodule-block-view-modal').on('show.bs.modal', function (e) { + var link = $(e.relatedTarget); + $(this).find(".modal-body").load(link.attr("href")); + }); + }) +})(jQuery); diff --git a/src/system/BlocksModule/Resources/views/Admin/blockview.html.twig b/src/system/BlocksModule/Resources/views/Admin/blockview.html.twig new file mode 100644 index 0000000000..45cfe7ed3b --- /dev/null +++ b/src/system/BlocksModule/Resources/views/Admin/blockview.html.twig @@ -0,0 +1 @@ +{{ showblock(block) }} \ No newline at end of file diff --git a/src/system/BlocksModule/Resources/views/Admin/config.html.twig b/src/system/BlocksModule/Resources/views/Admin/config.html.twig new file mode 100644 index 0000000000..8b52a85739 --- /dev/null +++ b/src/system/BlocksModule/Resources/views/Admin/config.html.twig @@ -0,0 +1,26 @@ +{% form_theme form with [ + 'ZikulaFormExtensionBundle:Form:bootstrap_3_zikula_admin_layout.html.twig', + 'ZikulaFormExtensionBundle:Form:form_div_layout.html.twig' +] %} +{{ render(controller('ZikulaAdminModule:Admin:adminheader')) }} +
+
+

+ + {{ __('Settings') }} +

+ + {{ form_start(form) }} + {{ form_errors(form) }} + {{ form_row(form.collapseable) }} +
+
+ {{ form_widget(form.save, {attr: {class: 'btn btn-success'}, icon:'fa-check'}) }} + {{ form_widget(form.cancel, {attr: {class: 'btn btn-default'}, icon:'fa-times'}) }} +
+
+ {{ form_end(form) }} +
+ +
+{{ render(controller('ZikulaAdminModule:Admin:adminfooter')) }} diff --git a/src/system/BlocksModule/Resources/views/Admin/delete.html.twig b/src/system/BlocksModule/Resources/views/Admin/delete.html.twig new file mode 100644 index 0000000000..d7cc697976 --- /dev/null +++ b/src/system/BlocksModule/Resources/views/Admin/delete.html.twig @@ -0,0 +1,26 @@ +{% form_theme form with [ + 'ZikulaFormExtensionBundle:Form:bootstrap_3_zikula_admin_layout.html.twig', + 'ZikulaFormExtensionBundle:Form:form_div_layout.html.twig' +] %} +{{ render(controller('ZikulaAdminModule:Admin:adminheader')) }} +
+
+

+ {{ __('Delete Block') }} '{{ block.title }}' +

+ +

{{ __f("Do you really want to delete block '%title%'?", {'%title%': block.title}) }}

+ + {{ form_start(form) }} + {{ form_errors(form) }} +
+
+ {{ form_widget(form.delete, {attr: {class: 'btn btn-success'}, icon:'fa-trash-o'}) }} + {{ form_widget(form.cancel, {attr: {class: 'btn btn-default'}, icon:'fa-times'}) }} +
+
+ {{ form_end(form) }} +
+ +
+{{ render(controller('ZikulaAdminModule:Admin:adminfooter')) }} diff --git a/src/system/BlocksModule/Resources/views/Admin/delete.tpl b/src/system/BlocksModule/Resources/views/Admin/delete.tpl deleted file mode 100644 index c8ce7fa9c1..0000000000 --- a/src/system/BlocksModule/Resources/views/Admin/delete.tpl +++ /dev/null @@ -1,25 +0,0 @@ -{adminheader} -

- - {$blockname|safetext} -

- -

{gt text="Do you really want to delete block '%s'?" tag1=$block.title|safetext}

- -
-
- {gt text='Confirmation prompt'} - - - - - -
-
- - {gt text='Cancel'} -
-
-
-
-{adminfooter} diff --git a/src/system/BlocksModule/Resources/views/Admin/deleteposition.tpl b/src/system/BlocksModule/Resources/views/Admin/deleteposition.tpl deleted file mode 100644 index 65340fa2b8..0000000000 --- a/src/system/BlocksModule/Resources/views/Admin/deleteposition.tpl +++ /dev/null @@ -1,25 +0,0 @@ -{adminheader} -

- - {gt text='Delete block position'} -

- -

{gt text="Do you really want to delete block position '%s'?" tag1=$position.name|safetext}

- -
-
- {gt text='Confirmation prompt'} - - - - - -
-
- {button class='btn btn-success' __alt='Delete' __title='Delete' __text='Delete'} - {gt text='Cancel'} -
-
-
-
-{adminfooter} diff --git a/src/system/BlocksModule/Resources/views/Admin/edit.html.twig b/src/system/BlocksModule/Resources/views/Admin/edit.html.twig new file mode 100644 index 0000000000..8b0120678c --- /dev/null +++ b/src/system/BlocksModule/Resources/views/Admin/edit.html.twig @@ -0,0 +1,68 @@ +{{ pageAddAsset('javascript', zasset('@ZikulaBlocksModule:js/Zikula.Blocks.Admin.Edit.js')) }} +{% form_theme form with [ +'ZikulaFormExtensionBundle:Form:bootstrap_3_zikula_admin_layout.html.twig', +'ZikulaFormExtensionBundle:Form:form_div_layout.html.twig' +] %} +{{ render(controller('ZikulaAdminModule:Admin:adminheader')) }} +
+
+

+ + {% if form.vars.value.bid %}{{ __('Modify') }}{% else %}{{ __('Create') }}{% endif %} {{ __('Block') }} +

+ {{ showflashes() }} + {{ form_start(form) }} + {{ form_errors(form) }} +
+ {{ __('Properties') }} +
+ +
+

{{ moduleName }}/{{ form.vars.value.blocktype }}

+
+
+ {{ form_row(form.bkey) }} + {{ form_row(form.title) }} + {{ form_row(form.description) }} +
+
+ {{ __('Content') }} + {{ renderedOutput|default('')|raw }} +
+
+ {{ __('Filters') }} + {{ form_row(form.positions) }} + {{ form_row(form.language) }} + +
+ {{ form_label(form.filters) }} +
+
    + {% for filter in form.filters %} + {% form_theme form _self %} + {% block _filters_entry_widget %} +
  • {{ form_widget(filter.attribute, { 'attr': {'class': 'attribute-selector'} }) }} {{ form_widget(filter.queryParameter, { 'attr': {'disabled': filter.vars.value.queryParameter is empty, 'class': 'queryParameter'} }) }} {{ form_widget(filter.comparator) }} {{ form_widget(filter.value) }}  
  • + {% endblock %} + {% endfor %} +
  • {{ form_row(form.filters) }}
  • +
+ Add Filter +
+
+
+ {# @TODO neither of the methods below will be needed when html block is refactored to supply its own template #} + {#{if $bkey eq 'HtmlBlock'}{* notify hooks here strictly for html block *}#} + {#{notifydisplayhooks eventname='blocks.ui_hooks.htmlblock.content.form_edit' id=$bid}#} + {#{/if}#} + {#{{ notifyDisplayHooks('pages.ui_hooks.pages.form_edit', form.vars.value.pageid|default(null)) }}#} +
+
+ {{ form_widget(form.save, {attr: {class: 'btn btn-success'}, icon:'fa-check'}) }} + {{ form_widget(form.cancel, {attr: {class: 'btn btn-default'}, icon:'fa-times'}) }} +
+
+ {{ form_end(form) }} +
+ +
+{{ render(controller('ZikulaAdminModule:Admin:adminfooter')) }} diff --git a/src/system/BlocksModule/Resources/views/Admin/filter_form.html.twig b/src/system/BlocksModule/Resources/views/Admin/filter_form.html.twig new file mode 100644 index 0000000000..cf8686f17f --- /dev/null +++ b/src/system/BlocksModule/Resources/views/Admin/filter_form.html.twig @@ -0,0 +1,16 @@ +{% form_theme filterForm with [ + 'ZikulaCategoriesModule:Form:filter_layout_customizations.html.twig', + 'ZikulaFormExtensionBundle:Form:form_div_layout.html.twig' +] %} +{{ form_start(filterForm) }} + + {% if filter_active %}{% set filteractive = __('active') %}{% else %}{% set filteractive = __('inactive') %}{% endif %} + {{ __f("Filter %active%", { '%active%': filteractive } ) }} + {{ __('Position') }} {{ form_widget(filterForm.position) }}   + {{ __('Module') }} {{ form_widget(filterForm.module) }}   + {{ __('Language') }} {{ form_widget(filterForm.language) }}   + {{ __('Active') }} {{ form_widget(filterForm.active) }}   + {{ form_widget(filterForm.filterButton) }} + + +{{ form_end(filterForm) }} \ No newline at end of file diff --git a/src/system/BlocksModule/Resources/views/Admin/modify.tpl b/src/system/BlocksModule/Resources/views/Admin/modify.tpl deleted file mode 100644 index 45fd51ce58..0000000000 --- a/src/system/BlocksModule/Resources/views/Admin/modify.tpl +++ /dev/null @@ -1,214 +0,0 @@ -{ajaxheader ui=true} -{pageaddvar name='javascript' value='javascript/helpers/Zikula.itemlist.js'} -{adminheader} -

- - {gt text='Edit block'} -

- -
-
- - - {if $requirement ne ''} -

- {$requirement} -

- {/if} -
- {$modtitle|safetext} -
- -
- -
-
-
- -
- -
-
-
- -
- {html_select_locales id='blocks_language' class='form-control' name='language' selected=$language installed=true all=true} -
-
-
-
- {gt text='Block placement filtering'} -
- -
- - {assign var='selectsize' value=$block_positions|@count}{if $selectsize gt 20}{assign var='selectsize' value=20}{/if}{if $selectsize lt 4}{assign var='selectsize' value=4}{/if} - - - {gt text='Show/hide advanced placement options'} -
- - -
-
- - {if $modvars.ZikulaBlocksModule.collapseable eq 1} -
- {gt text='Collapsibility'} -
- -
-
- - -
-
-
-
- -
-
- - -
-
-
-
- {/if} - - {if $blockoutput eq '' && $form_content eq true} -
- {gt text='Customisation'} -
- -
- -
-
-
- {if $bkey eq 'HtmlBlock'}{* notify hooks here strictly for html block *} - {notifydisplayhooks eventname='blocks.ui_hooks.htmlblock.content.form_edit' id=$bid} - {/if} - {/if} - - {if $blockoutput ne ''} -
- {gt text='Customisation'} - {if $admin_tableless} - {$blockoutput} - {else} - - {$blockoutput} -
- {/if} -
- {/if} - -
-
- -
- -
-
-
- - {if isset($redirect) && $redirect ne ''} - {assign var='cancelurl' value=$redirect|urldecode} - {else} - {route name='zikulablocksmodule_admin_view' assign='cancelurl'} - {/if} - -
-
- - {gt text='Cancel'} -
-
-
-
-{adminfooter} - -{pageaddvarblock} - -{/pageaddvarblock} diff --git a/src/system/BlocksModule/Resources/views/Admin/modifyconfig.tpl b/src/system/BlocksModule/Resources/views/Admin/modifyconfig.tpl deleted file mode 100644 index 5da3afb3db..0000000000 --- a/src/system/BlocksModule/Resources/views/Admin/modifyconfig.tpl +++ /dev/null @@ -1,28 +0,0 @@ -{adminheader} -

- - {gt text='Settings'} -

- -
-
- -
- {gt text='General settings'} -
- -
- -
-
-
- -
-
- - {gt text='Cancel'} -
-
-
-
-{adminfooter} diff --git a/src/system/BlocksModule/Resources/views/Admin/modifyposition.tpl b/src/system/BlocksModule/Resources/views/Admin/modifyposition.tpl deleted file mode 100644 index 4192376ccc..0000000000 --- a/src/system/BlocksModule/Resources/views/Admin/modifyposition.tpl +++ /dev/null @@ -1,113 +0,0 @@ -{pageaddvar name='javascript' value='system/BlocksModule/Resources/public/js/Zikula.Blocks.Admin.Common.js'} -{pageaddvar name='javascript' value='system/BlocksModule/Resources/public/js/Zikula.Blocks.Admin.Modifyposition.js'} -{pageaddvar name='javascript' value='jquery-ui'} -{adminheader} -

- - {gt text='Edit block position'} -

- -
-
- {gt text='Block position'} - - - - -
- -
- - {gt text='Characters allowed: a-z, A-Z, 0-9, dash (-) and underscore (_).'} -
-
-
- -
- -
-
-
-
- - {gt text='Cancel'} -
-
-
- -

{gt text='Block assignments'}

-

{gt text='Notice: Use drag and drop to arrange the blocks in this position into your desired order. The new block order will be saved automatically.'}

- -

{gt text='Blocks assigned to this position'}

- - - - - - - - - - - - - - - - {foreach item='block' from=$assignedblocks} - - - - - - - - - - {/foreach} - -
{gt text='Block ID'}{gt text='Title, Description'}{gt text='Module'}{gt text='Name'}{gt text='Language'}{gt text='State'}
{gt text='No blocks assigned yet.'}
{$block.bid|safetext} - {$block.title|safehtml|default:" "}{if $block.title && $block.description}, {/if}{$block.description|safehtml} - {$block.modname|safetext}{$block.bkey|safetext}{$block.language|safetext|default:" "} - {gt text='Active'} - {gt text='Inactive'} -
- -

{gt text='Blocks not assigned to this position'}

- - - - - - - - - - - - - - - - {foreach item='block' from=$unassignedblocks} - - - - - - - - - - {/foreach} - -
{gt text='Block ID'}{gt text='Title, Description'}{gt text='Module'}{gt text='Name'}{gt text='Language'}{gt text='State'}
{gt text='All blocks assigned.'}
{$block.bid|safetext} - {$block.title|safehtml|default:" "}{if $block.title && $block.description}, {/if}{$block.description|safehtml} - {$block.modname|safetext}{$block.bkey|safetext}{$block.language|safetext|default:" "} - {gt text='Active'} - {gt text='Inactive'} -
-
-{adminfooter} diff --git a/src/system/BlocksModule/Resources/views/Admin/new.html.twig b/src/system/BlocksModule/Resources/views/Admin/new.html.twig new file mode 100644 index 0000000000..7860b60398 --- /dev/null +++ b/src/system/BlocksModule/Resources/views/Admin/new.html.twig @@ -0,0 +1,30 @@ +{{ pageAddAsset('javascript', zasset('@ZikulaBlocksModule:js/Zikula.Blocks.Admin.New.js')) }} +{% form_theme form with [ +'ZikulaFormExtensionBundle:Form:bootstrap_3_zikula_admin_layout.html.twig', +'ZikulaFormExtensionBundle:Form:form_div_layout.html.twig' +] %} +{{ render(controller('ZikulaAdminModule:Admin:adminheader')) }} +
+
+

+ + {{ __('Create') }} {{ __('Block') }} +

+ {{ showflashes() }} + {{ form_start(form) }} + {{ form_errors(form) }} +
+ {{ __('Properties') }} +
{{ __('Select a block type.') }}
+ {{ form_row(form.bkey) }} +
+
+
+ {{ form_widget(form.choose, {attr: {class: 'btn btn-success'}, icon:'fa-check'}) }} +
+
+ {{ form_end(form) }} +
+ +
+{{ render(controller('ZikulaAdminModule:Admin:adminfooter')) }} diff --git a/src/system/BlocksModule/Resources/views/Admin/newblock.tpl b/src/system/BlocksModule/Resources/views/Admin/newblock.tpl deleted file mode 100644 index 2eed7d74d0..0000000000 --- a/src/system/BlocksModule/Resources/views/Admin/newblock.tpl +++ /dev/null @@ -1,90 +0,0 @@ -{adminheader} -

- - {gt text='Create new block'} -

- -
-
- -
- {gt text='New block'} -
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- {html_select_locales id='blocks_language' class='form-control' name='block[language]' installed=true all=true selected=$block.language|default:''} -
-
-
-
- {gt text='Block placement filtering'} -
- -
-
- {assign var='selectsize' value=$block_positions|@count}{if $selectsize gt 20}{assign var='selectsize' value=20}{/if}{if $selectsize lt 4}{assign var='selectsize' value=4}{/if} - -
-
-
-
- {if $modvars.ZikulaBlocksModule.collapseable eq 1} -
- {gt text='Collapsibility'} -
- -
-
- - - - -
-
-
-
- -
-
- - - - -
-
-
-
- {/if} - -
-
- - {gt text='Cancel'} -
-
-
-
-{adminfooter} diff --git a/src/system/BlocksModule/Resources/views/Admin/newposition.tpl b/src/system/BlocksModule/Resources/views/Admin/newposition.tpl deleted file mode 100644 index bea08cd136..0000000000 --- a/src/system/BlocksModule/Resources/views/Admin/newposition.tpl +++ /dev/null @@ -1,36 +0,0 @@ -{adminheader} -

- - {gt text='Create new block position'} -

- -

{gt text='After create this block position, you will be able to assign some blocks for it, and adjust the order you want them to be displayed.'}

- -
-
- -
- {gt text='New block position'} -
- -
- - {gt text='Characters allowed: a-z, A-Z, 0-9, dash (-) and underscore (_).'} -
-
-
- -
- -
-
-
-
-
- - {gt text='Cancel'} -
-
-
-
-{adminfooter} diff --git a/src/system/BlocksModule/Resources/views/Admin/view.html.twig b/src/system/BlocksModule/Resources/views/Admin/view.html.twig new file mode 100644 index 0000000000..75726ebf07 --- /dev/null +++ b/src/system/BlocksModule/Resources/views/Admin/view.html.twig @@ -0,0 +1,122 @@ +{{ pageAddAsset('javascript', zasset('@ZikulaBlocksModule:js/Zikula.Blocks.Admin.Common.js')) }} +{{ pageAddAsset('javascript', zasset('@ZikulaBlocksModule:js/Zikula.Blocks.Admin.View.js')) }} +{{ render(controller('ZikulaAdminModule:Admin:adminheader')) }} +

+ + {{ __('Blocks list') }} +

+ +

+ {{ __("This is the list of blocks present in your system, you can use the filter to display only certain blocks. + The order in which blocks are listed here is not necessarily the order in which they are displayed in site pages. + To manage the display order of the blocks click the position name in this table or on the 'edit block placements' + in the position list table below.") }} +

+ +{% include 'ZikulaBlocksModule:Admin:filter_form.html.twig' %} + + + + + + + + + + + + + + + + + {% for block in blocks %} + + + + + + + + + + + + {% else %} + + {% endfor %} + +
{{ __('ID') }}{{ __('Title') }}{{ __('Description') }}{{ __('Module') }}{{ __('Type') }}{{ __('Positions') }}{{ __('Language') }}{{ __('State') }}{{ __('Actions') }}
{{ block.bid }}{{ block.title|safeHtml }}{{ block.description|safeHtml }}{{ block.module.name }}{{ block.blocktype }} + {% for position in block.positions %} + {{ position.name }}{% if not loop.last %}, {% endif %} + {% endfor %} + {% if block.filters|length > 0 %} {% endif %} + {{ block.language|default( __('All') ) }} + {{ __('Active') }} + {{ __('Inactive') }} + + + + +
{{ __('No items found.') }}
+ +

{{ __('Block positions list') }}

+ +

{{ __("This is the list of block positions currently existing for your site's pages. +You can create a new block position by clicking 'Create block position' in the menu. To edit the settings for a block position, +click on the 'Edit' icon beside that particular position. To reorder the blocks within a block position, click on the +'Edit placements' (blocks) icon for that position or on the position name in the block list above. +To delete a block position, click on the 'Delete' icon and confirm the action in the confirmation prompt that will display.") }}

+ + + + + + + + + + + + + {% for position in positions %} + + + + + + + + {% else %} + + {% endfor %} + +
{{ __('Name') }}{{ __('Description') }}{{ __('Smarty tag') }}{{ __('Twig tag') }}{{ __('Actions') }}
+ {{ position.name }} + {% if not positionavailable(position.name) %} {% endif %} + {{ position.description|slice(0, 25)|safeHtml }}{blockposition name='{{ position.name }}'}{{ showblockposition('{{ position.name }}') }} + + + +
{{ __('No items found.') }}
+

{{ __('Marked positions are not available in the current default theme.') }}

+ +{{ render(controller('ZikulaAdminModule:Admin:adminfooter')) }} + +{# block preview modal #} + diff --git a/src/system/BlocksModule/Resources/views/Admin/view.tpl b/src/system/BlocksModule/Resources/views/Admin/view.tpl deleted file mode 100644 index f5e8699f76..0000000000 --- a/src/system/BlocksModule/Resources/views/Admin/view.tpl +++ /dev/null @@ -1,143 +0,0 @@ -{pageaddvar name='javascript' value='system/BlocksModule/Resources/public/js/Zikula.Blocks.Admin.Common.js'} - -{gt text='Click to activate this block' assign='activate'} -{gt text='Click to deactivate this block' assign='deactivate'} - -{adminheader} - -

- - {gt text='Blocks list'} -

- -

- {gt text="This is the list of blocks present in your system, you can use the filter to display only certain blocks. The order in which blocks are listed here is not necessarily the order in which they are displayed in site pages. To manage the display order within site pages, scroll down (or click here), then edit a block position. You will be able to arrange the order of display for blocks assigned to that block position."} -

- -
- {gt text='All' assign='lblAll'} - {gt text='Filter' assign='lblFilter'} -
- {$lblFilter} - - - - - - - {selector_module name='filter[module_id]' field='id' allText=$lblAll allValue=0 selectedValue=$filter.module_id|default:0} - - - - {html_select_languages id='filter_language' name='filter[language]' installed=1 all=1 selected=$filter.language|default:''} - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - {foreach item='block' from=$blocks} - {assign var='lbl_block' value=$block.title|strip_tags|safetext} - {gt text='Deactivate %s' tag1=$lbl_block assign='lbl_deactivate_block'} - {gt text='Activate %s' tag1=$lbl_block assign='lbl_activate_block'} - {gt text='Preview %s' tag1=$lbl_block assign='lbl_preview_block'} - {gt text='Edit %s' tag1=$lbl_block assign='lbl_edit_block'} - {gt text='Delete %s' tag1=$lbl_block assign='lbl_delete_block'} - {checkpermission component="`$module`::" instance="`$block.bkey`:`$block.title`:`$block.bid`" level='ACCESS_EDIT' assign='access_edit'} - {checkpermission component="`$module`::" instance="`$block.bkey`:`$block.title`:`$block.bid`" level='ACCESS_DELETE' assign='access_delete'} - - - - - - - - - - - - {foreachelse} - - {/foreach} - -
{sortlink __linktext='Block ID' sort='bid' currentsort=$sort sortdir=$sortdir route='zikulablocksmodule_admin_view' filter=$filter}{sortlink __linktext='Title' sort='title' currentsort=$sort sortdir=$sortdir route='zikulablocksmodule_admin_view' filter=$filter}{sortlink __linktext='Description' sort='description' currentsort=$sort sortdir=$sortdir route='zikulablocksmodule_admin_view' filter=$filter}{gt text='Module'}{sortlink __linktext='Name' sort='bkey' currentsort=$sort sortdir=$sortdir route='zikulablocksmodule_admin_view' filter=$filter}{gt text='Position(s)'}{sortlink __linktext='Language' sort='language' currentsort=$sort sortdir=$sortdir route='zikulablocksmodule_admin_view' filter=$filter}{sortlink __linktext='State' sort='active' currentsort=$sort sortdir=$sortdir route='zikulablocksmodule_admin_view' filter=$filter}{gt text='Actions'}
{$block.bid|safetext}{$block.title|safehtml}{$block.description|safehtml}{$block.modname|safetext}{$block.bkey|safetext}{$block.positions|safetext}{$block.language|safetext} - {gt text='Active'} - {gt text='Inactive'} - - - {if $access_edit} - - {/if} - {if $access_delete} - - {/if} -
{gt text='No items found.'}
- -

{gt text='Block positions list'}

- -

{gt text="This is the list of block positions currently existing for your site's pages. You can create a new block position by clicking 'Create block position' in the menu. To edit the settings for a block position, or to reorder the blocks within a block position, click on the 'Edit' icon beside that particular position. To delete a block position, click on the 'Delete' icon and confirm the action in the confirmation prompt that will display."}

- - - - - - - - - - - - {foreach item='position' from=$positions} - {gt text='Edit blockposition %s' tag1=$position.name|safetext assign='lbl_edit_blockposition'} - {gt text='Delete blockposition %s' tag1=$position.name|safetext assign='lbl_delete_blockposition'} - {checkpermission component="`$module`::position" instance="`$position.name`:`$position.pid`" level='ACCESS_EDIT' assign='access_edit'} - {checkpermission component="`$module`::position" instance="`$position.name`:`$position.pid`" level='ACCESS_DELETE' assign='access_delete'} - - - - - - - {foreachelse} - - {/foreach} - -
{gt text='Name'}{gt text='Description'}{gt text='Theme tag'}{gt text='Actions'}
{$position.name|safehtml}{$position.description|truncate:25|safehtml}{blockposition name='{$position.name|safehtml}'} - {if $access_edit} - - {/if} - {if $access_delete} - - {/if} -
{gt text='No items found.'}
-{adminfooter} diff --git a/src/system/BlocksModule/Resources/views/Block/Extmenu/extmenu.tpl b/src/system/BlocksModule/Resources/views/Block/Extmenu/extmenu.tpl index 7b87c0166a..a1ef8676ef 100644 --- a/src/system/BlocksModule/Resources/views/Block/Extmenu/extmenu.tpl +++ b/src/system/BlocksModule/Resources/views/Block/Extmenu/extmenu.tpl @@ -15,9 +15,9 @@ {/menu} {if $access_edit}

- {gt text='Add current URL' domain='zikula'} + {gt text='Add current URL' domain='zikula'}
- {gt text='Edit this block' domain='zikula'} + {gt text='Edit this block' domain='zikula'}

{/if} diff --git a/src/system/BlocksModule/Resources/views/Block/Extmenu/modify.tpl b/src/system/BlocksModule/Resources/views/Block/Extmenu/modify.tpl index 3a0d422c24..75601831ed 100644 --- a/src/system/BlocksModule/Resources/views/Block/Extmenu/modify.tpl +++ b/src/system/BlocksModule/Resources/views/Block/Extmenu/modify.tpl @@ -1,3 +1,4 @@ +{pageaddvar name='javascript' value='zikula.ui'} {pageaddvar name='javascript' value='javascript/helpers/Zikula.itemlist.js'} {pageaddvar name='stylesheet' value='system/BlocksModule/Resources/public/css/extmenu_modify.css'} {pageaddvarblock} diff --git a/src/system/BlocksModule/Resources/views/Block/Menutree/bootstrap.tpl b/src/system/BlocksModule/Resources/views/Block/Menutree/bootstrap.tpl index 63754a9f64..6e9b2a7695 100644 --- a/src/system/BlocksModule/Resources/views/Block/Menutree/bootstrap.tpl +++ b/src/system/BlocksModule/Resources/views/Block/Menutree/bootstrap.tpl @@ -4,8 +4,8 @@ {menutree data=$menutree_content id='menu'|cat:$blockinfo.bid class='nav navbar-nav' ext=true bootstrap=true extopt='first,last,single,dropdown,childless,dropdown-menu'} {if $menutree_editlinks} {/if} diff --git a/src/system/BlocksModule/Resources/views/Block/Menutree/bs_hamburger.tpl b/src/system/BlocksModule/Resources/views/Block/Menutree/bs_hamburger.tpl index c7fb6e1494..0528007297 100644 --- a/src/system/BlocksModule/Resources/views/Block/Menutree/bs_hamburger.tpl +++ b/src/system/BlocksModule/Resources/views/Block/Menutree/bs_hamburger.tpl @@ -13,8 +13,8 @@ {menutree data=$menutree_content id='menu'|cat:$blockinfo.bid class='nav navbar-nav' ext=true bootstrap=true extopt='first,last,single,dropdown,childless,dropdown-menu'} {if $menutree_editlinks} {/if} diff --git a/src/system/BlocksModule/Resources/views/Block/Menutree/default.tpl b/src/system/BlocksModule/Resources/views/Block/Menutree/default.tpl index 8dd37cf7f7..4e8a9300d0 100644 --- a/src/system/BlocksModule/Resources/views/Block/Menutree/default.tpl +++ b/src/system/BlocksModule/Resources/views/Block/Menutree/default.tpl @@ -2,8 +2,8 @@ {menutree data=$menutree_content id='menu'|cat:$blockinfo.bid class='menutree'} {if $menutree_editlinks} {/if} diff --git a/src/system/BlocksModule/Resources/views/Block/Menutree/horizontal.tpl b/src/system/BlocksModule/Resources/views/Block/Menutree/horizontal.tpl index 18f1dfeaa0..fe58af30d1 100644 --- a/src/system/BlocksModule/Resources/views/Block/Menutree/horizontal.tpl +++ b/src/system/BlocksModule/Resources/views/Block/Menutree/horizontal.tpl @@ -2,8 +2,8 @@ {menutree data=$menutree_content id='menu'|cat:$blockinfo.bid class='menutree_horizontal clearfix' ext=true} {if $menutree_editlinks} {/if} diff --git a/src/system/BlocksModule/Resources/views/Block/Menutree/tree.tpl b/src/system/BlocksModule/Resources/views/Block/Menutree/tree.tpl index f821362fd7..723cd19f98 100644 --- a/src/system/BlocksModule/Resources/views/Block/Menutree/tree.tpl +++ b/src/system/BlocksModule/Resources/views/Block/Menutree/tree.tpl @@ -2,8 +2,8 @@ {tree treearray=$menutree_content imagesDir='system/BlocksModule/Resources/public/images/menutree/' id='usermenutree'|cat:$blockinfo.bid} {if $menutree_editlinks} {/if} diff --git a/src/system/BlocksModule/Resources/views/Block/Menutree/vertical_left.tpl b/src/system/BlocksModule/Resources/views/Block/Menutree/vertical_left.tpl index 6491e4873d..279772cddf 100644 --- a/src/system/BlocksModule/Resources/views/Block/Menutree/vertical_left.tpl +++ b/src/system/BlocksModule/Resources/views/Block/Menutree/vertical_left.tpl @@ -2,8 +2,8 @@ {menutree data=$menutree_content id='menu'|cat:$blockinfo.bid class='menutree_vertical_left' ext=true} {if $menutree_editlinks} {/if} diff --git a/src/system/BlocksModule/Resources/views/Block/Menutree/vertical_right.tpl b/src/system/BlocksModule/Resources/views/Block/Menutree/vertical_right.tpl index 2d253c46ad..f966089e4d 100644 --- a/src/system/BlocksModule/Resources/views/Block/Menutree/vertical_right.tpl +++ b/src/system/BlocksModule/Resources/views/Block/Menutree/vertical_right.tpl @@ -2,8 +2,8 @@ {menutree data=$menutree_content id='menu'|cat:$blockinfo.bid class='menutree_vertical_right' ext=true} {if $menutree_editlinks} {/if} diff --git a/src/system/BlocksModule/Resources/views/Block/default_modify.html.twig b/src/system/BlocksModule/Resources/views/Block/default_modify.html.twig new file mode 100644 index 0000000000..1f7632c172 --- /dev/null +++ b/src/system/BlocksModule/Resources/views/Block/default_modify.html.twig @@ -0,0 +1,4 @@ +{% form_theme form 'ZikulaFormExtensionBundle:Form:bootstrap_3_zikula_admin_layout.html.twig' %} +{#{{ form_start(form) }}#}{# DO NOT 'start' the form! #} +{{ form_widget(form) }} +{#{{ form_end(form) }}#} \ No newline at end of file diff --git a/src/system/BlocksModule/Resources/views/Placement/edit.html.twig b/src/system/BlocksModule/Resources/views/Placement/edit.html.twig new file mode 100644 index 0000000000..f7ddbf9f2d --- /dev/null +++ b/src/system/BlocksModule/Resources/views/Placement/edit.html.twig @@ -0,0 +1,98 @@ +{{ pageAddAsset('javascript', zasset('@ZikulaBlocksModule:js/Zikula.Blocks.Admin.Common.js')) }} +{{ pageAddAsset('javascript', zasset('@ZikulaBlocksModule:js/Zikula.Blocks.Admin.Modifyposition.js')) }} + +{{ render(controller('ZikulaAdminModule:Admin:adminheader')) }} +

+ + {{ __('Block placements') }} +

+ + +
+ + +
+

+

{{ __('Notice: Use drag and drop to arrange the blocks in this position into your desired order. The new block order will be saved automatically.') }}

+ +

{{ __f("Blocks placed in the '%name%' position", {'%name%': position.name}) }}

+ +{% if not positionavailable(position.name) %}
{{ __f('WARNING: The "%name%" block position is not available in the current default theme.', {'%name%':position.name}) }}
{% endif %} + + + + + + + + + + + + + + + + {% for block in assignedblocks %} + + + + + + + + + + {% endfor %} + +
{{ __('Block ID') }}{{ __('Title, Description') }}{{ __('Module') }}{{ __('Type') }}{{ __('Language') }}{{ __('State') }}
{{ __('No blocks placed in this position yet.') }}
{{ block.bid }} + {{ block.title|safeHtml|default('') }}{% if block.title and block.description %}, {% endif %}{{ block.description|safeHtml }} + {{ block.module.name }}{{ block.blocktype }}{{ block.language|default('') }} + {{ __('Active') }} + {{ __('Inactive') }} +
+ +

{{ __f("Blocks not placed in '%name%' position", {'%name%': position.name}) }}

+ + + + + + + + + + + + + + + + {% for block in unassignedblocks %} + + + + + + + + + + {% endfor %} + +
{{ __('Block ID') }}{{ __('Title, Description') }}{{ __('Module') }}{{ __('Type') }}{{ __('Language') }}{{ __('State') }}
{{ __('All blocks placed.') }}
{{ block.bid }} + {{ block.title|safeHtml|default('') }}{% if block.title and block.description %}, {% endif %}{{ block.description|safeHtml }} + {{ block.module.name }}{{ block.blocktype }}{{ block.language|default('') }} + {{ __('Active') }} + {{ __('Inactive') }} +
+ +{{ render(controller('ZikulaAdminModule:Admin:adminfooter')) }} diff --git a/src/system/BlocksModule/Resources/views/Position/delete.html.twig b/src/system/BlocksModule/Resources/views/Position/delete.html.twig new file mode 100644 index 0000000000..1ebcbea0fb --- /dev/null +++ b/src/system/BlocksModule/Resources/views/Position/delete.html.twig @@ -0,0 +1,26 @@ +{% form_theme form with [ + 'ZikulaFormExtensionBundle:Form:bootstrap_3_zikula_admin_layout.html.twig', + 'ZikulaFormExtensionBundle:Form:form_div_layout.html.twig' +] %} +{{ render(controller('ZikulaAdminModule:Admin:adminheader')) }} +
+
+

+ {{ __('Delete Position') }} '{{ position.name }}' +

+ +

{{ __f("Do you really want to delete position '%name%'?", {'%name%': position.name}) }}

+ + {{ form_start(form) }} + {{ form_errors(form) }} +
+
+ {{ form_widget(form.delete, {attr: {class: 'btn btn-success'}, icon:'fa-trash-o'}) }} + {{ form_widget(form.cancel, {attr: {class: 'btn btn-default'}, icon:'fa-times'}) }} +
+
+ {{ form_end(form) }} +
+ +
+{{ render(controller('ZikulaAdminModule:Admin:adminfooter')) }} diff --git a/src/system/BlocksModule/Resources/views/Position/edit.html.twig b/src/system/BlocksModule/Resources/views/Position/edit.html.twig new file mode 100644 index 0000000000..0631ac7e07 --- /dev/null +++ b/src/system/BlocksModule/Resources/views/Position/edit.html.twig @@ -0,0 +1,37 @@ +{% form_theme form with [ +'ZikulaFormExtensionBundle:Form:bootstrap_3_zikula_admin_layout.html.twig', +'ZikulaFormExtensionBundle:Form:form_div_layout.html.twig' +] %} + +{{ render(controller('ZikulaAdminModule:Admin:adminheader')) }} + +

+ {% if form.vars.value.pid is empty %} + {{ __('After creating this block position, blocks can be assigned to it and the order they are to be displayed can be adjusted.') }}
+ {% endif %} + {{ __('The theme in use must implement the block position or the assigned blocks will never be displayed.') }} +

+ +
+
+

+ + {% if form.vars.value.pid %}{{ __('Modify') }}{% else %}{{ __('Create') }}{% endif %} {{ __('Position') }} +

+ {{ showflashes() }} + {{ form_start(form) }} + {{ form_errors(form) }} + {{ form_row(form.name) }} + {{ __('Characters allowed: a-z, A-Z, 0-9, dash (-) and underscore (_).') }} + {{ form_row(form.description) }} +
+
+ {{ form_widget(form.save, {attr: {class: 'btn btn-success'}, icon:'fa-check'}) }} + {{ form_widget(form.cancel, {attr: {class: 'btn btn-default'}, icon:'fa-times'}) }} +
+
+ {{ form_end(form) }} +
+ +
+{{ render(controller('ZikulaAdminModule:Admin:adminfooter')) }} diff --git a/src/system/BlocksModule/Tests/Api/BlockApiTest.php b/src/system/BlocksModule/Tests/Api/BlockApiTest.php new file mode 100644 index 0000000000..e2f588d4a6 --- /dev/null +++ b/src/system/BlocksModule/Tests/Api/BlockApiTest.php @@ -0,0 +1,129 @@ +setUpBlockPlacements(); + $this->fooBlock = new FooBlock(); + + $blockPosRepo = $this + ->getMockBuilder('Zikula\BlocksModule\Entity\RepositoryInterface\BlockPositionRepositoryInterface') + ->getMock(); + $position = $this + ->getMockBuilder('Zikula\BlocksModule\Entity\BlockPositionEntity') + ->getMock(); + $position + ->method('getPlacements') + ->willReturn($this->blockPlacements); + $blockPosRepo + ->method('findByName') + ->willReturn($position); + $blockFilterApi = $this + ->getMockBuilder('Zikula\BlocksModule\Api\BlockFilterApi') + ->disableOriginalConstructor() + ->getMock(); + $blockFilterApi + ->method('isDisplayable') + ->willReturnCallback(function($block) { + if ($block->getBid() == 2) { + return false; + } + return true; + }); + $blockFactory = $this + ->getMockBuilder('Zikula\BlocksModule\Api\BlockFactoryApi') + ->disableOriginalConstructor() + ->getMock(); + $blockFactory + ->method('getInstance') + ->willReturn($this->fooBlock); + $extensionApi = $this + ->getMockBuilder('Zikula\ExtensionsModule\Api\ExtensionApi') + ->disableOriginalConstructor() + ->getMock(); + $extensionApi + ->method('getModulesBy') + ->willReturn([]); + $blockCollector = new BlockCollector(); + + $this->api = new BlockApi($blockPosRepo, $blockFilterApi, $blockFactory, $extensionApi, $blockCollector, '/'); + } + + /** + * @covers BlockApi::getBlocksByPosition + */ + public function testGetBlocksByPosition() + { + $this->assertEquals([ + 1 => $this->blockPlacements->get(1)->getBlock(), + 5 => $this->blockPlacements->get(5)->getBlock() + ], $this->api->getBlocksByPosition('left')); + } + + /** + * @covers BlockApi::createInstanceFromBKey + */ + public function testCreateInstanceFromBKey() + { + $this->assertEquals($this->fooBlock, $this->api->createInstanceFromBKey('AcmeFooModule:Zikula\BlocksModule\Tests\Api\Fixture\FooBlock')); + } + + private function setUpBlockPlacements() + { + $this->blockPlacements = new ArrayCollection(); + $block = new BlockEntity(); + $block->setBid(1); + $placement = new BlockPlacementEntity(); + $placement->setBlock($block); + $this->blockPlacements->set(1, $placement); + $block = new BlockEntity(); + $block->setBid(2); + $placement = new BlockPlacementEntity(); + $placement->setBlock($block); + $this->blockPlacements->set(2, $placement); + $block = new BlockEntity(); + $block->setBid(5); + $placement = new BlockPlacementEntity(); + $placement->setBlock($block); + $this->blockPlacements->set(5, $placement); + } + +} diff --git a/src/system/BlocksModule/Tests/Api/BlockFilterApiTest.php b/src/system/BlocksModule/Tests/Api/BlockFilterApiTest.php new file mode 100644 index 0000000000..6886909207 --- /dev/null +++ b/src/system/BlocksModule/Tests/Api/BlockFilterApiTest.php @@ -0,0 +1,218 @@ + 1, + 'q-b' => 2 + ], [], [ + // attributes + 'foo' => 'bar', + 'fee' => 'bee', + 'fii' => 'bii', + 'int' => 9, + '_route_params' => [ + 'zee' => 'zar' + ] + ]); + $request->setLocale('en'); + $requestStack = $this->getMockBuilder('Symfony\Component\HttpFoundation\RequestStack') + ->disableOriginalConstructor() + ->getMock(); + $requestStack + ->method('getCurrentRequest') + ->willReturn($request); + $this->api = new BlockFilterApi($requestStack); + } + + /** + * @covers BlockFilterApi::getFilterAttributeChoices + */ + public function testGetFilterAttributeChoices() + { + $expected = [ + 'foo' => 'foo', + 'fee' => 'fee', + 'fii' => 'fii', + 'int' => 'int', + '_route_params' => '_route_params', + 'query param' => 'query param' + ]; + $this->assertEquals($expected, $this->api->getFilterAttributeChoices()); + } + + /** + * @covers BlockFilterApi::isDisplayable + * @dataProvider filterProvider + * @param array $filter + * @param bool $expected + */ + public function testIsDisplayable($filter, $expected) + { + $blockEntity = $this->getMockBuilder('Zikula\BlocksModule\Entity\BlockEntity') + ->getMock(); + $blockEntity + ->method('getLanguage') + ->willReturn('en'); + $blockEntity + ->method('getFilters') + ->willReturn($filter); + $this->assertEquals($expected, $this->api->isDisplayable($blockEntity)); + } + + public function filterProvider() + { + return [ + [[], true], + [[[ + 'attribute' => 'foo', + 'comparator' => '==', + 'value' => 'bar' + ]], true], + [[[ + 'attribute' => 'foo', + 'comparator' => '==', + 'value' => 'bee' + ]], false], + [[[ + 'attribute' => 'foo', + 'comparator' => '!=', + 'value' => 'bee' + ]], true], + [[[ + 'attribute' => 'int', + 'comparator' => '==', + 'value' => 9 + ]], true], + [[[ + 'attribute' => 'int', + 'comparator' => '>=', + 'value' => 9 + ]], true], + [[[ + 'attribute' => 'int', + 'comparator' => '<=', + 'value' => 9 + ]], true], + [[[ + 'attribute' => 'int', + 'comparator' => '>', + 'value' => 8 + ]], true], + [[[ + 'attribute' => 'int', + 'comparator' => '<', + 'value' => 10 + ]], true], + [[[ + 'attribute' => 'int', + 'comparator' => 'in_array', + 'value' => "8,9,10" + ]], true], + [[[ + 'attribute' => 'int', + 'comparator' => '!in_array', + 'value' => "10,11,12" + ]], true], + [[[ + 'attribute' => 'int', + 'comparator' => 'in_array', + 'value' => " 8,9 , 10 " + ]], true], + [[ + [ + 'attribute' => 'foo', + 'comparator' => '==', + 'value' => 'bar' + ], + [ + 'attribute' => 'fee', + 'comparator' => '==', + 'value' => 'bee' + ], + ], true], + [[ + [ + 'attribute' => 'foo', + 'comparator' => '==', + 'value' => 'bar' + ], + [ + 'attribute' => 'fee', + 'comparator' => 'in_array', + 'value' => ',baz,bee,bum' + ], + [ + 'attribute' => 'int', + 'comparator' => '>=', + 'value' => '3' + ], + ], true], + [[ + [ + 'attribute' => 'query param', + 'queryParameter' => 'q-a', + 'comparator' => '==', + 'value' => '1' + ] + ], true], + [[ + [ + 'attribute' => 'query param', + 'queryParameter' => 'q-b', + 'comparator' => '==', + 'value' => '2' + ] + ], true], + [[ + [ + 'attribute' => 'q-b', + 'comparator' => '==', + 'value' => '2' + ] + ], false], + [[ + [ + 'attribute' => '_route_params', + 'queryParameter' => 'zee', + 'comparator' => '==', + 'value' => 'zar' + ] + ], true], + [[ + [ + 'attribute' => '_route_params', + 'queryParameter' => 'foo', + 'comparator' => '==', + 'value' => 'zar' + ] + ], false], + ]; + } +} diff --git a/src/system/BlocksModule/Tests/Api/Fixture/FooBlock.php b/src/system/BlocksModule/Tests/Api/Fixture/FooBlock.php new file mode 100644 index 0000000000..150c4fc5de --- /dev/null +++ b/src/system/BlocksModule/Tests/Api/Fixture/FooBlock.php @@ -0,0 +1,25 @@ +collector = new BlockCollector(); + } + + /** + * @covers BlockCollector::add + */ + public function testAdd() + { + $this->assertEquals(0, count($this->collector->getBlocks())); + $block = $this->getMockBuilder('Zikula\Core\BlockControllerInterface') + ->getMock(); + $block + ->method('getType') + ->willReturn('A'); + $this->collector->add('a', $block); + $this->assertEquals(1, count($this->collector->getBlocks())); + $block = $this->getMockBuilder('Zikula\Core\BlockControllerInterface') + ->getMock(); + $block + ->method('getType') + ->willReturn('B'); + $this->collector->add('b', $block); + $this->assertEquals(2, count($this->collector->getBlocks())); + } + + /** + * @covers BlockCollector::add + */ + public function testGet() + { + $block = $this->getMockBuilder('Zikula\Core\BlockControllerInterface') + ->getMock(); + $block + ->method('getType') + ->willReturn('A'); + $this->collector->add('a', $block); + $a = $this->collector->get('a'); + $this->assertEquals('A', $a->getType()); + } + + /** + * @covers BlockCollector::getBlocks + */ + public function getGetBlocks() + { + $expected = []; + $block = $this->getMockBuilder('Zikula\Core\BlockControllerInterface') + ->getMock(); + $block + ->method('getType') + ->willReturn('A'); + $expected['a'] = $block; + $this->collector->add('a', $block); + $block = $this->getMockBuilder('Zikula\Core\BlockControllerInterface') + ->getMock(); + $block + ->method('getType') + ->willReturn('B'); + $expected['b'] = $block; + $this->collector->add('b', $block); + $this->assertEquals($expected, $this->collector->getBlocks()); + } +} diff --git a/src/system/BlocksModule/Tests/Helper/Fixture/Block/TestBlock.php b/src/system/BlocksModule/Tests/Helper/Fixture/Block/TestBlock.php new file mode 100644 index 0000000000..c6ef173930 --- /dev/null +++ b/src/system/BlocksModule/Tests/Helper/Fixture/Block/TestBlock.php @@ -0,0 +1,9 @@ +helper = new InstallerHelper(); + } + + /** + * @covers InstallerHelper::upgradeFilterArray + * @dataProvider filterProvider + * @param $initialFilter + * @param $expected + */ + public function testUpgradeFilterArray($initialFilter, $expected) + { + $this->assertEquals($expected, $this->helper->upgradeFilterArray($initialFilter)); + } + + /** + * @covers InstallerHelper::upgradeBkeyToFqClassname + * @dataProvider bKeyProvider + * @param $moduleName + * @param $oldBkey + * @param $expected + */ + public function testUpgradeBkeyToFqClassname($moduleName, $oldBkey, $expected) + { + $kernel = $this + ->getMockBuilder('\Zikula\Bundle\CoreBundle\HttpKernel\ZikulaKernel') + ->disableOriginalConstructor() + ->getMock(); + $kernel + ->method('getModule') + ->will($this->returnCallback(function ($moduleName) { + if ($moduleName == 'ExceptionModule') { + // mocks situation where module is not namespaced. + throw new \Exception(); + } + $module = $this + ->getMockBuilder('Zikula\Core\AbstractModule') + ->disableOriginalConstructor() + ->getMock(); + $module + ->method('getNamespace') + ->willReturn('Zikula\BlocksModule\Tests\Helper\\' . $moduleName); + return $module; + })); + $moduleEntity = $this + ->getMockBuilder('\Zikula\ExtensionsModule\Entity\ExtensionEntity') + ->disableOriginalConstructor() + ->getMock(); + $moduleEntity + ->method('getName') + ->willReturn($moduleName); + $blockEntity = $this + ->getMockBuilder('\Zikula\BlocksModule\Entity\BlockEntity') + ->disableOriginalConstructor() + ->getMock(); + $blockEntity + ->method('getModule') + ->willReturn($moduleEntity); + $blockEntity + ->method('getBkey') + ->willReturn($oldBkey); + $FqClassName = $this->helper->upgradeBkeyToFqClassname($kernel, $blockEntity); + + $this->assertEquals($expected, $FqClassName); + } + + public function bKeyProvider() + { + return [ + ['MockModule', 'ShortNameBlock', 'MockModule:Zikula\BlocksModule\Tests\Helper\MockModule\Block\ShortNameBlock'], + ['ExceptionModule', 'ShortNameBlock', 'ExceptionModule:\ExceptionModule_Block_ShortNameBlock'], + ['ExceptionModule', 'ShortName', 'ExceptionModule:\ExceptionModule_Block_ShortName'], + ['Fixture', 'TestBlock', 'Fixture:Zikula\BlocksModule\Tests\Helper\Fixture\Block\TestBlock'], + ['Fixture', 'Test', 'Fixture:Zikula\BlocksModule\Tests\Helper\Fixture\Block\TestBlock'], + ]; + } + /** + * @return array + */ + public function filterProvider() + { + return [ + [[], []], + [ + [ + ['module' => 'FooModule'] + ], + [ + ['_zkModule', '==', 'FooModule'] + ] + ], + [ + [ + ['module' => 'FooModule', 'ftype' => 'user', 'fname' => 'bar'] + ], + [ + ['_zkModule', '==', 'FooModule'], + ['_zkType', '==', 'user'], + ['_zkFunc', '==', 'bar'], + ] + ], + [ + [ + ['module' => 'FooModule', 'ftype' => 'user', 'fname' => 'bar', 'fargs' => 'a=b&c=d&e=f'] + ], + [ + ['_zkModule', '==', 'FooModule'], + ['_zkType', '==', 'user'], + ['_zkFunc', '==', 'bar'], + ['a', '==', 'b'], + ['c', '==', 'd'], + ['e', '==', 'f'], + ] + ], + [ + [ + ['module' => 'FooModule'], + ['module' => 'BarModule'], + ['module' => 'BazModule'], + ], + [ + ['_zkModule', 'in_array', ['FooModule', 'BarModule', 'BazModule']], + ] + ], + [ + [ + ['module' => 'FooModule', 'ftype' => 'user', 'fname' => 'bar'], + ['module' => 'BarModule', 'ftype' => 'user', 'fname' => 'baz'] + ], + [ + ['_zkModule', 'in_array', ['FooModule', 'BarModule']], + ['_zkType', 'in_array', ['user']], + ['_zkFunc', 'in_array', ['bar', 'baz']], + ] + ], + [ + [ + ['module' => 'FooModule', 'ftype' => 'user', 'fname' => 'bar', 'fargs' => 'a=b&c=d&e=f'], + ['module' => 'BarModule', 'ftype' => 'user', 'fname' => 'baz', 'fargs' => 'a=z&g=h&i=j'] + ], + [ + ['_zkModule', 'in_array', ['FooModule', 'BarModule']], + ['_zkType', 'in_array', ['user']], + ['_zkFunc', 'in_array', ['bar', 'baz']], + ['a', 'in_array', ['b', 'z']], + ['c', 'in_array', ['d']], + ['e', 'in_array', ['f']], + ['g', 'in_array', ['h']], + ['i', 'in_array', ['j']], + ] + ], + ]; + } +} diff --git a/src/system/BlocksModule/Tests/Helper/ServiceNameHelperTest.php b/src/system/BlocksModule/Tests/Helper/ServiceNameHelperTest.php new file mode 100644 index 0000000000..5e5fcd6454 --- /dev/null +++ b/src/system/BlocksModule/Tests/Helper/ServiceNameHelperTest.php @@ -0,0 +1,54 @@ +helper = new ServiceNameHelper(); + } + + /** + * @dataProvider classNameProvider + * @param $expected + * @param $className + */ + public function testGenerateServiceNameFromClassName($className, $expected) + { + $this->assertEquals($expected, $this->helper->generateServiceNameFromClassName($className)); + } + + public function classNameProvider() + { + return [ + ['Acme\FooBundle\Bar\FooBar', 'acme.foo_bundle.bar.foo_bar'], + ['\Acme\FooBundle\Bar\FooBar', 'acme.foo_bundle.bar.foo_bar'], + ['AcmeFooBundle\Bar\FooBarBaz', 'acme_foo_bundle.bar.foo_bar_baz'], + ['Acme_Bar_FooBar', 'acme.bar.foo_bar'], + ['\Acme_Bar_FooBar', 'acme.bar.foo_bar'], + ]; + } +} diff --git a/src/system/BlocksModule/Twig/Extension/BlocksExtension.php b/src/system/BlocksModule/Twig/Extension/BlocksExtension.php new file mode 100644 index 0000000000..a657409140 --- /dev/null +++ b/src/system/BlocksModule/Twig/Extension/BlocksExtension.php @@ -0,0 +1,135 @@ +blockApi = $blockApi; + $this->themeEngine = $themeEngine; + $this->extensionApi = $extensionApi; + } + + /** + * Returns the name of the extension. + * + * @return string The extension name + */ + public function getName() + { + return 'zikulablocksmodule'; + } + + /** + * Returns a list of functions to add to the existing list. + * + * @return array An array of functions + */ + public function getFunctions() + { + return [ + new \Twig_SimpleFunction('showblockposition', [$this, 'showBlockPosition'], ['is_safe' => ['html']]), + new \Twig_SimpleFunction('showblock', [$this, 'showBlock'], ['is_safe' => ['html']]), + new \Twig_SimpleFunction('positionavailable', [$this, 'positionAvailable']), + ]; + } + + public function getFilters() + { + return []; + } + + /** + * Show all the blocks in a position by name. + * @todo at Core-2.0 remove all $legacy use and other checks. + * @param string $positionName + * @param bool|true $implode + * @return array|string + */ + public function showBlockPosition($positionName, $implode = true) + { + if (!\ModUtil::available('ZikulaBlocksModule')) { // @TODO refactor to Core-2.0 + + return "Blocks not currently available."; + } + $blocks = $this->blockApi->getBlocksByPosition($positionName); + foreach ($blocks as $key => $block) { + $blocks[$key] = $this->showBlock($block, $positionName); + } + + return $implode ? implode("\n", $blocks) : $blocks; + } + + /** + * Display one block. + * + * @param BlockEntity $block + * @param string $positionName @deprecated argument. remove at Core-2.0 + * @return string + */ + public function showBlock(BlockEntity $block, $positionName = '') + { + $blockInstance = $this->blockApi->createInstanceFromBKey($block->getBkey()); + $legacy = false; + $content = ''; + if ($blockInstance instanceof BlockControllerInterface) { + $content = $blockInstance->display($block->getContent()); + } elseif ($blockInstance instanceof \Zikula_Controller_AbstractBlock) { // @todo remove at Core-2.0 + $legacy = true; + $args = \BlockUtil::getBlockInfo($block->getBid()); + $args['position'] = $positionName; + $content = $blockInstance->display($args); + } + if (!$legacy) { + if (null !== $moduleInstance = $this->extensionApi->getModuleInstanceOrNull($block->getModule()->getName())) { + // @todo can remove check for null at Core-2.0 + // add module stylesheet to page - legacy blocks load stylesheets automatically on ModUtil::load() + $moduleInstance->addStylesheet(); + } + } + + return $this->themeEngine->wrapBlockContentInTheme($content, $block->getTitle(), $block->getBlocktype(), $block->getBid(), $positionName, $legacy); + } + + /** + * @param $name + * @return bool + */ + public function positionAvailable($name) + { + return $this->themeEngine->positionIsAvailableInTheme($name); + } +} diff --git a/src/system/BlocksModule/ZikulaBlocksModule.php b/src/system/BlocksModule/ZikulaBlocksModule.php index 00d77b55d5..74ba435a7e 100644 --- a/src/system/BlocksModule/ZikulaBlocksModule.php +++ b/src/system/BlocksModule/ZikulaBlocksModule.php @@ -13,6 +13,8 @@ namespace Zikula\BlocksModule; +use Zikula\BlocksModule\DependencyInjection\Compiler\BlockCollectorPass; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Zikula\Bundle\CoreBundle\Bundle\AbstractCoreModule; /** @@ -20,4 +22,10 @@ */ class ZikulaBlocksModule extends AbstractCoreModule { + public function build(ContainerBuilder $container) + { + parent::build($container); + + $container->addCompilerPass(new BlockCollectorPass()); + } } \ No newline at end of file diff --git a/src/system/BlocksModule/composer.json b/src/system/BlocksModule/composer.json index 63be4a4b2b..3cc36bcbdf 100644 --- a/src/system/BlocksModule/composer.json +++ b/src/system/BlocksModule/composer.json @@ -1,6 +1,7 @@ { "name": "zikula/blocks-module", "description": "Blocks Administration Module", + "version": "3.9.2", "type": "zikula-module", "license": "LGPL-3.0+", "authors": [ @@ -15,10 +16,34 @@ "require": { "php": ">5.4.0" }, + "suggest": { + "Scribite:>=5.0.0": "To allow WYSIWYG HTML block editing." + }, "extra": { "zikula": { + "class": "Zikula\\BlocksModule\\ZikulaBlocksModule", + "core-compatibility": ">=1.4.1", + "displayname": "BlocksModule", "url": "blocks", - "class": "Zikula\\BlocksModule\\ZikulaBlocksModule" + "oldnames": [], + "capabilities": { + "admin": {"route": "zikulablocksmodule_admin_view"}, + "hook_subscriber": {"enabled": true} + }, + "securityschema": { + "ZikulaBlocksModule::": "Block key:Block title:Block ID", + "ZikulaBlocksModule::position": "Position name::Position ID", + "ExtendedMenublock::": "Block ID:Link ID:", + "fincludeblock::": "Block title::", + "HTMLblock::": "Block title::", + "Languageblock::": "Block title::", + "Menublock::": "Block title:Link name:", + "Menutree:menutreeblock:": "Block ID:Link Name:Link ID", + "PendingContent::": "Block title::", + "Textblock::": "Block title::", + "xsltblock::": "Block title::" + } + } } } diff --git a/src/system/BlocksModule/phpunit.xml.dist b/src/system/BlocksModule/phpunit.xml.dist index e18d0f2244..5ce01e8807 100644 --- a/src/system/BlocksModule/phpunit.xml.dist +++ b/src/system/BlocksModule/phpunit.xml.dist @@ -9,7 +9,7 @@ processIsolation="false" stopOnFailure="false" syntaxCheck="false" - bootstrap="vendor/autoload.php" + bootstrap="../../lib/bootstrap.php" > diff --git a/src/system/CategoriesModule/Controller/AdminController.php b/src/system/CategoriesModule/Controller/AdminController.php index 9694bbedf1..627b4573bf 100644 --- a/src/system/CategoriesModule/Controller/AdminController.php +++ b/src/system/CategoriesModule/Controller/AdminController.php @@ -268,7 +268,7 @@ public function editregistryAction(Request $request) } $registries = $this->entityManager->getRepository('ZikulaCategoriesModule:CategoryRegistryEntity')->findBy(array(), array('modname' => 'ASC', 'property' => 'ASC')); - $modules = $this->entityManager->getRepository('Zikula\Core\Doctrine\Entity\ExtensionEntity')->findBy(array('state' => 3), array('displayname' => 'ASC')); + $modules = $this->entityManager->getRepository('Zikula\ExtensionsModule\Entity\ExtensionEntity')->findBy(array('state' => 3), array('displayname' => 'ASC')); $moduleOptions = array(); foreach ($modules as $module) { $bundle = \ModUtil::getModule($module['name']); diff --git a/src/system/ExtensionsModule/Api/AdminApi.php b/src/system/ExtensionsModule/Api/AdminApi.php index 718470c898..d16fe7a51a 100644 --- a/src/system/ExtensionsModule/Api/AdminApi.php +++ b/src/system/ExtensionsModule/Api/AdminApi.php @@ -32,8 +32,8 @@ use Zikula_AbstractVersion; use Zikula_Core; use PluginUtil; -use Zikula\Core\Doctrine\Entity\ExtensionEntity; -use Zikula\Core\Doctrine\Entity\ExtensionDependencyEntity; +use Zikula\ExtensionsModule\Entity\ExtensionEntity; +use Zikula\ExtensionsModule\Entity\ExtensionDependencyEntity; use Zikula\Bundle\CoreBundle\Bundle\Scanner; use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\DependencyInjection\ContainerAwareInterface; @@ -48,7 +48,7 @@ */ class AdminApi extends \Zikula_AbstractApi { - const EXTENSION_ENTITY = 'Zikula\Core\Doctrine\Entity\ExtensionEntity'; + const EXTENSION_ENTITY = 'Zikula\ExtensionsModule\Entity\ExtensionEntity'; /** * Update module information * @@ -1341,7 +1341,7 @@ public function getdallependencies() */ public function getalldependencies() { - $dependencies = $this->entityManager->getRepository('Zikula\Core\Doctrine\Entity\ExtensionDependencyEntity')->findBy(array(), array('modid' => 'ASC')); + $dependencies = $this->entityManager->getRepository('Zikula\ExtensionsModule\Entity\ExtensionDependencyEntity')->findBy(array(), array('modid' => 'ASC')); return $dependencies; } @@ -1364,7 +1364,7 @@ public function getdependencies($args) throw new \InvalidArgumentException(__('Invalid arguments array received')); } - $dependencies = $this->entityManager->getRepository('Zikula\Core\Doctrine\Entity\ExtensionDependencyEntity')->findBy(array('modid' => $args['modid'])); + $dependencies = $this->entityManager->getRepository('Zikula\ExtensionsModule\Entity\ExtensionDependencyEntity')->findBy(array('modid' => $args['modid'])); return $dependencies; } @@ -1389,7 +1389,7 @@ public function getdependents($args) $modinfo = ModUtil::getInfo($args['modid']); - $dependents = $this->entityManager->getRepository('Zikula\Core\Doctrine\Entity\ExtensionDependencyEntity')->findBy(array('modname' => $modinfo['name'])); + $dependents = $this->entityManager->getRepository('Zikula\ExtensionsModule\Entity\ExtensionDependencyEntity')->findBy(array('modname' => $modinfo['name'])); return $dependents; } diff --git a/src/system/ExtensionsModule/Api/ExtensionApi.php b/src/system/ExtensionsModule/Api/ExtensionApi.php new file mode 100644 index 0000000000..0373557656 --- /dev/null +++ b/src/system/ExtensionsModule/Api/ExtensionApi.php @@ -0,0 +1,91 @@ +repository = $repository; + $this->kernel = $kernel; + } + + /** + * @param array $criteria + * @param array|null $orderBy + * @param null $limit + * @param null $offset + * @return ExtensionEntity[] + */ + public function getModulesBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + /** + * return one ExtensionEntity + * @param $moduleName + * @return ExtensionEntity + */ + public function getModule($moduleName) + { + return $this->repository->get($moduleName); + } + + /** + * @param $name + * @deprecated remove at Core-2.0 + * @return null|\Zikula\Core\AbstractBundle + */ + public function getModuleInstanceOrNull($name) + { + $moduleInstance = null; + try { + $moduleInstance = $this->kernel->getModule($name); + } catch (\Exception $e) { + // silent fail + // @todo remove this try/catch block at Core-2.0 + } + + return $moduleInstance; + } +} \ No newline at end of file diff --git a/src/lib/Zikula/Core/Doctrine/Entity/ExtensionDependencyEntity.php b/src/system/ExtensionsModule/Entity/ExtensionDependencyEntity.php similarity index 99% rename from src/lib/Zikula/Core/Doctrine/Entity/ExtensionDependencyEntity.php rename to src/system/ExtensionsModule/Entity/ExtensionDependencyEntity.php index 0ff48bd05b..b55a18b4bc 100644 --- a/src/lib/Zikula/Core/Doctrine/Entity/ExtensionDependencyEntity.php +++ b/src/system/ExtensionsModule/Entity/ExtensionDependencyEntity.php @@ -12,7 +12,7 @@ * information regarding copyright and licensing. */ -namespace Zikula\Core\Doctrine\Entity; +namespace Zikula\ExtensionsModule\Entity; use Doctrine\ORM\Mapping as ORM; use ModUtil; diff --git a/src/lib/Zikula/Core/Doctrine/Entity/ExtensionEntity.php b/src/system/ExtensionsModule/Entity/ExtensionEntity.php similarity index 97% rename from src/lib/Zikula/Core/Doctrine/Entity/ExtensionEntity.php rename to src/system/ExtensionsModule/Entity/ExtensionEntity.php index e9094f77ae..371b687b4f 100644 --- a/src/lib/Zikula/Core/Doctrine/Entity/ExtensionEntity.php +++ b/src/system/ExtensionsModule/Entity/ExtensionEntity.php @@ -12,7 +12,7 @@ * information regarding copyright and licensing. */ -namespace Zikula\Core\Doctrine\Entity; +namespace Zikula\ExtensionsModule\Entity; use Doctrine\ORM\Mapping as ORM; use Zikula\Core\Doctrine\EntityAccess; @@ -20,7 +20,7 @@ /** * Extension Entity. * - * @ORM\Entity + * @ORM\Entity(repositoryClass="Zikula\ExtensionsModule\Entity\Repository\ExtensionRepository") * @ORM\Table(name="modules") */ class ExtensionEntity extends EntityAccess diff --git a/src/system/ExtensionsModule/Entity/Repository/ExtensionRepository.php b/src/system/ExtensionsModule/Entity/Repository/ExtensionRepository.php new file mode 100644 index 0000000000..4ad3207c69 --- /dev/null +++ b/src/system/ExtensionsModule/Entity/Repository/ExtensionRepository.php @@ -0,0 +1,37 @@ + $name]); + } +} \ No newline at end of file diff --git a/src/system/ExtensionsModule/Entity/RepositoryInterface/ExtensionRepositoryInterface.php b/src/system/ExtensionsModule/Entity/RepositoryInterface/ExtensionRepositoryInterface.php new file mode 100644 index 0000000000..ce74e4db3e --- /dev/null +++ b/src/system/ExtensionsModule/Entity/RepositoryInterface/ExtensionRepositoryInterface.php @@ -0,0 +1,22 @@ +variableApi->get($this->extensionName, $variableName, $default); + } + + /** + * Convenience shortcut to get all Extension Variables. + * @return array + */ + public function getVars() + { + return $this->variableApi->getAll($this->extensionName); + } + + /** + * Convenience shortcut to set Extension Variable. + * @param string $variableName + * @param string $value + * @return bool + */ + public function setVar($variableName, $value = '') + { + return $this->variableApi->set($this->extensionName, $variableName, $value); + } + + /** + * Convenience shortcut to set many Extension Variables. + * @param array $variables + * @return bool + */ + public function setVars(array $variables) + { + return $this->variableApi->setAll($this->extensionName, $variables); + } + + /** + * Convenience shortcut to delete an Extension Variable. + * @param $variableName + * @return bool + */ + public function delVar($variableName) + { + return $this->variableApi->del($this->extensionName, $variableName); + } + + /** + * Convenience shortcut to delete all Extension Variables. + * @return bool + */ + public function delVars() + { + return $this->variableApi->delAll($this->extensionName); + } +} \ No newline at end of file diff --git a/src/system/ExtensionsModule/ExtensionsModuleInstaller.php b/src/system/ExtensionsModule/ExtensionsModuleInstaller.php index 235cdcb172..e28d0f5122 100644 --- a/src/system/ExtensionsModule/ExtensionsModuleInstaller.php +++ b/src/system/ExtensionsModule/ExtensionsModuleInstaller.php @@ -19,7 +19,7 @@ use Zikula_Event; use Zikula\ExtensionsModule\ExtensionsModuleVersion; use ModUtil; -use Zikula\Core\Doctrine\Entity\ExtensionEntity; +use Zikula\ExtensionsModule\Entity\ExtensionEntity; /** * Installation and upgrade routines for the extensions module @@ -35,8 +35,8 @@ public function install() { // create tables $tables = array( - 'Zikula\Core\Doctrine\Entity\ExtensionEntity', - 'Zikula\Core\Doctrine\Entity\ExtensionDependencyEntity', + 'Zikula\ExtensionsModule\Entity\ExtensionEntity', + 'Zikula\ExtensionsModule\Entity\ExtensionDependencyEntity', 'Zikula\ExtensionsModule\Entity\ExtensionVarEntity', 'Zikula\Component\HookDispatcher\Storage\Doctrine\Entity\HookAreaEntity', 'Zikula\Component\HookDispatcher\Storage\Doctrine\Entity\HookBindingEntity', @@ -86,7 +86,7 @@ public function upgrade($oldversion) $stmt = $connection->executeQuery($sql); } case '3.7.11': - \DoctrineHelper::updateSchema($this->entityManager, array('Zikula\Core\Doctrine\Entity\ExtensionEntity')); + \DoctrineHelper::updateSchema($this->entityManager, array('Zikula\ExtensionsModule\Entity\ExtensionEntity')); case '3.7.12': // future upgrade routines } diff --git a/src/system/ExtensionsModule/Resources/config/services.xml b/src/system/ExtensionsModule/Resources/config/services.xml index 6debd3ec18..16263be10b 100644 --- a/src/system/ExtensionsModule/Resources/config/services.xml +++ b/src/system/ExtensionsModule/Resources/config/services.xml @@ -6,7 +6,9 @@ Zikula\ExtensionsModule\Api\VariableApi + Zikula\ExtensionsModule\Api\ExtensionApi Zikula\ExtensionsModule\Entity\Repository\ExtensionVarRepository + Zikula\ExtensionsModule\Entity\Repository\ExtensionRepository @@ -15,10 +17,20 @@ Zikula\ExtensionsModule\Entity\ExtensionVarEntity
+ + + Zikula\ExtensionsModule\Entity\ExtensionEntity + + + + + + + \ No newline at end of file diff --git a/src/system/ExtensionsModule/Util.php b/src/system/ExtensionsModule/Util.php index f1b0435714..86505d311e 100644 --- a/src/system/ExtensionsModule/Util.php +++ b/src/system/ExtensionsModule/Util.php @@ -19,6 +19,7 @@ use ServiceUtil; use ModUtil; use System; +use Zikula\Core\AbstractModule; /** * Helper functions for the extensions module @@ -27,6 +28,7 @@ class Util { /** * Get version metadata for a module. + * @todo refactor at Core-2.0 to eliminate legacy * * @param string $moduleName Module Name. * @param string $rootdir Root directory of the module (default: modules). @@ -56,6 +58,9 @@ public static function getVersionMeta($moduleName, $rootdir = 'modules', $module if (!$modversion instanceof Zikula_AbstractVersion) { throw new \InvalidArgumentException(__f('%s is not an instance of Zikula_AbstractVersion', get_class($modversion))); } + } elseif ($module instanceof AbstractModule) { + // Core-2.0 spec + $modversion = $module->getMetaData()->getFilteredVersionInfoArray(); } elseif (!is_dir("$rootdir/$moduleName")) { $modversion = array( 'name' => $moduleName, diff --git a/src/system/RoutesModule/Entity/Repository/Route.generated.php b/src/system/RoutesModule/Entity/Repository/Route.generated.php deleted file mode 100755 index e4b60298a7..0000000000 --- a/src/system/RoutesModule/Entity/Repository/Route.generated.php +++ /dev/null @@ -1,25 +0,0 @@ -. - * @link http://www.zikula.org - * @link http://zikula.org - * @version Generated by ModuleStudio 0.7.0 (http://modulestudio.de). - */ - -namespace Zikula\RoutesModule\Entity\Repository; - -use Zikula\RoutesModule\Entity\Repository\Base\Route as BaseRoute; - -/** - * Repository class used to implement own convenience methods for performing certain DQL queries. - * - * This is the concrete repository class for route entities. - */ -class Route extends BaseRoute -{ - // feel free to add your own methods here, like for example reusable DQL queries -} diff --git a/src/system/RoutesModule/Entity/RouteEntity.generated.php b/src/system/RoutesModule/Entity/RouteEntity.generated.php deleted file mode 100755 index 23bce5d7aa..0000000000 --- a/src/system/RoutesModule/Entity/RouteEntity.generated.php +++ /dev/null @@ -1,148 +0,0 @@ -. - * @link http://www.zikula.org - * @link http://zikula.org - * @version Generated by ModuleStudio 0.7.0 (http://modulestudio.de). - */ - -namespace Zikula\RoutesModule\Entity; - -use Zikula\RoutesModule\Entity\Base\AbstractRouteEntity as BaseAbstractRouteEntity; - -use Doctrine\ORM\Mapping as ORM; -use Gedmo\Mapping\Annotation as Gedmo; -use DoctrineExtensions\StandardFields\Mapping\Annotation as ZK; -use Symfony\Component\Validator\Constraints as Assert; -use Symfony\Component\Validator\Context\ExecutionContextInterface; - -/** - * Entity class that defines the entity structure and behaviours. - * - * This is the concrete entity class for route entities. - * @ORM\Entity(repositoryClass="\Zikula\RoutesModule\Entity\Repository\Route") - * @ORM\Table(name="zikula_routes_route", - * indexes={ -* @ORM\Index(name="workflowstateindex", columns={"workflowState"}) - * } - * ) -* @ORM\HasLifecycleCallbacks - */ -class RouteEntity extends BaseAbstractRouteEntity -{ - // feel free to add your own methods here - - /** - * Post-Process the data after the entity has been constructed by the entity manager. - * - * @ORM\PostLoad - * @see Zikula\RoutesModule\Entity\RouteEntity::performPostLoadCallback() - * @return void. - */ - public function postLoadCallback() - { - $this->performPostLoadCallback(); - } - - /** - * Pre-Process the data prior to an insert operation. - * - * @ORM\PrePersist - * @see Zikula\RoutesModule\Entity\RouteEntity::performPrePersistCallback() - * @return void. - */ - public function prePersistCallback() - { - $this->performPrePersistCallback(); - } - - /** - * Post-Process the data after an insert operation. - * - * @ORM\PostPersist - * @see Zikula\RoutesModule\Entity\RouteEntity::performPostPersistCallback() - * @return void. - */ - public function postPersistCallback() - { - $this->performPostPersistCallback(); - } - - /** - * Pre-Process the data prior a delete operation. - * - * @ORM\PreRemove - * @see Zikula\RoutesModule\Entity\RouteEntity::performPreRemoveCallback() - * @return void. - */ - public function preRemoveCallback() - { - $this->performPreRemoveCallback(); - } - - /** - * Post-Process the data after a delete. - * - * @ORM\PostRemove - * @see Zikula\RoutesModule\Entity\RouteEntity::performPostRemoveCallback() - * @return void - */ - public function postRemoveCallback() - { - $this->performPostRemoveCallback(); - } - - /** - * Pre-Process the data prior to an update operation. - * - * @ORM\PreUpdate - * @see Zikula\RoutesModule\Entity\RouteEntity::performPreUpdateCallback() - * @return void. - */ - public function preUpdateCallback() - { - $this->performPreUpdateCallback(); - } - - /** - * Post-Process the data after an update operation. - * - * @ORM\PostUpdate - * @see Zikula\RoutesModule\Entity\RouteEntity::performPostUpdateCallback() - * @return void. - */ - public function postUpdateCallback() - { - $this->performPostUpdateCallback(); - } - - /** - * Pre-Process the data prior to a save operation. - * - * @ORM\PrePersist - * @ORM\PreUpdate - * @see Zikula\RoutesModule\Entity\RouteEntity::performPreSaveCallback() - * @return void. - */ - public function preSaveCallback() - { - $this->performPreSaveCallback(); - } - - /** - * Post-Process the data after a save operation. - * - * @ORM\PostPersist - * @ORM\PostUpdate - * @see Zikula\RoutesModule\Entity\RouteEntity::performPostSaveCallback() - * @return void. - */ - public function postSaveCallback() - { - $this->performPostSaveCallback(); - } -} diff --git a/src/system/SearchModule/Block/SearchBlock.php b/src/system/SearchModule/Block/SearchBlock.php index 2a3568272f..f73672201c 100644 --- a/src/system/SearchModule/Block/SearchBlock.php +++ b/src/system/SearchModule/Block/SearchBlock.php @@ -159,7 +159,7 @@ public function update($blockinfo) { // list of vars that don't need to be saved $search_reserved_vars = array('authid', 'csrftoken', 'bid', 'title', 'positions', 'language', 'submit', - 'refresh', 'filter', 'type', 'functions', 'customargs'); + 'filter', 'type', 'functions', 'customargs'); // Get current content $vars = BlockUtil::varsFromContent($blockinfo['content']); diff --git a/src/system/UsersModule/Block/OnlineBlock.php b/src/system/UsersModule/Block/OnlineBlock.php index bd7e53a196..e2f85f0601 100644 --- a/src/system/UsersModule/Block/OnlineBlock.php +++ b/src/system/UsersModule/Block/OnlineBlock.php @@ -81,7 +81,7 @@ public function display($blockinfo) $cacheid = $blockinfo['bkey'].'/bid'.$blockinfo['bid'].'/'.($uid ? $uid : 'guest'); // We use an individual cache with a lifetime specified on the block configuration. $this->view->setCaching(Zikula_View::CACHE_INDIVIDUAL) - ->setCacheLifetime($blockinfo['refresh']) +// ->setCacheLifetime($blockinfo['refresh']) ->setCacheId($cacheid); // check out if the contents are cached. diff --git a/src/themes/Andreas08Theme/Resources/views/admin.html.twig b/src/themes/Andreas08Theme/Resources/views/admin.html.twig index e4fc260e84..81894917fa 100644 --- a/src/themes/Andreas08Theme/Resources/views/admin.html.twig +++ b/src/themes/Andreas08Theme/Resources/views/admin.html.twig @@ -10,7 +10,7 @@
  • {{ __('Extensions') }}
  • {% endif %} {% if hasPermission('ZikulaBlocksModule::','::','ACCESS_EDIT') %} -
  • {{ __('Blocks') }}
  • +
  • {{ __('Blocks') }}
  • {% endif %} {% if hasPermission('ZikulaUsersModule::','::','ACCESS_MODERATE') %}
  • {{ __('Users') }}
  • diff --git a/src/themes/BootstrapTheme/Resources/views/Include/main_menu.html.twig b/src/themes/BootstrapTheme/Resources/views/Include/main_menu.html.twig index b4b1a3858e..4c39336321 100644 --- a/src/themes/BootstrapTheme/Resources/views/Include/main_menu.html.twig +++ b/src/themes/BootstrapTheme/Resources/views/Include/main_menu.html.twig @@ -20,7 +20,7 @@
  • {{ __('Extensions') }}
  • {% endif %} {% if hasPermission('ZikulaBlocksModule::', '::', 'ACCESS_EDIT') %} -
  • {{ __('Blocks') }}
  • +
  • {{ __('Blocks') }}
  • {% endif %} {% if hasPermission('ZikulaUsersModule::', '::', 'ACCESS_MODERATE') %}
  • {{ __('Users') }}
  • diff --git a/src/themes/SeaBreezeTheme/Resources/views/Include/adminheader.html.twig b/src/themes/SeaBreezeTheme/Resources/views/Include/adminheader.html.twig index d05c514659..b2271f18d5 100644 --- a/src/themes/SeaBreezeTheme/Resources/views/Include/adminheader.html.twig +++ b/src/themes/SeaBreezeTheme/Resources/views/Include/adminheader.html.twig @@ -16,7 +16,7 @@ {{ __('Extensions') }}
  • - {{ __('Blocks') }} + {{ __('Blocks') }}
  • {{ __('Users') }}