Zikula Core 1.3.7 introduces a lot of forward compatibility for new features that will come in Zikula 1.4.0. For safety sake, please only upgrade from Zikula Core 1.3.6
- Before uploading the new files please delete the
plugins/
,lib/
,system/
,themes/
andztemp/
folders entirely (replace any custom themes afterwards). - Delete your
config/config.php
andconfig/personal_config.php
keeping a note of your database settings. - Upload new files.
- Copy your new
config/config.php
andconfig/personal_config.php
and updateconfig/personal_config.php
with your database settings. - Copy
app/config/parameters.yml
toapp/config/custom_parameters.yml
and update values with your database settings. - Make
app/cache
andapp/logs
writable. - Run
http://yoursiteurl/upgrade.php
.
Note:
ztemp
is now located in the app/cache/<kernel-mode>/ztemp
location automatically.
The following is for module developers only.
All of the following changes are optional and forward compatible with Zikula Core 1.4. Module developers can begin adopting these immediately without risking any compatibility problems. The reason for these changes are to allow rapid adoption of various Symfony Components and rapidly modernize the Core.
There is a refactor tool zikula-tools
which is referred to in this
document for the purposes of refactoring modules to the new standards
below with very little effort.
Zikula now uses Bootstrap 3 with FontAwesome 4 and jQuery.
There are a few small oddities to maintain compatibility with Prototype but in general it's pretty straightforward. Core modules have been refactored so there are also working examples in the code.
Documentation: http://zikula.github.io/bootstrap-docs/
Zikula Core 1.3.7 supports PHP namespaces and module should be refactored for namespace compliance which should MUST be in line with PSR-0, PSR-1 and PSR-2.
In order to be PSR-0 compliant, module the PHP assets in lib/Modname/*
need to moved into the module root (see below).
The current specification mandates: (still in dev) Vendor - PSR-0 mandates a class must contain a vendor. The examples will illustrate this.
Foo
is the vendor and 'MyModule' is the module name (Module
suffic required).
Here are a a few examples of how module classes should look like:
Controllers:
-
Named like
Foo\MyModule\Controller\UserController
-
Stored in
Foo/MyModule/Controller/UserController.php
-
Example:
<?php namespace Foo\MyModule\Controller; class UserController extends \Zikula_AbstractController { }
Apis:
-
Named like
Foo\MyModule\Api\UserApi
-
Stored in
Foo/MyModule/Api/UserApi.php
-
Example:
<?php namespace Foo\MyModule\Api; class UserApi extends \Zikula_AbstractApi { }
Entities:
-
Named like
Foo\MyModule\Entity\BarEntity
-
Stored in
Foo/MyModule/Entity/BarEntity.php
-
Example:
<?php namespace Foo\MyModule\Entity; class BarEntity { }
.. note::
The namespace can be as deep as required, e.g
Zikula\Module\AdminModule
so you might have a class like
called Zikula\Module\AdminModule\Controller\AdminController
<?php
namespace Zikula\Module\AdminModule\Controller;
class AdminController
{
}
There is a script to do some of the refactoring for you:
zikula-tools module:ns --dir=module/MyModule --vendor=Foo --module=MyModule
Module code must be PSR-1 and PSR-2 compliant. You can fix formatting with PHP-CS-Fixer: https://github.com/fabpot/PHP-CS-Fixer
PSR-1: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md PSR-2: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md
Interfaces and traits names should be suffixed with Interface
or Trait
.
Abstract classes should be prefixed with Abstract
Generally classes should be suffixed with whatever they are and kept in a
folder. So listeners would be stored in Listener/
and called FooListener
.
You can see concrete examples in the module structure section next.
The final structure looks as follows:
foo-my/
Foo/
MyModule/
Api/
AdminApi.php (was Admin.php)
UserApi.php (was User.php)
Controller/
AdminController.php (was Admin.php)
UserController.php (was User.php)
Entity/
FooEntity.php
Listener/
FooListener.php
Hook/
FooHook.php
Resources/
config/
docs/
locale/
foomymodule.pot
public/
css/
images/
js/
views/
Admin/
view.tpl
User/
list.tpl
view.tpl
plugins/
Tests/
AdminControllerTest.php
vendor/
MyModuleInstaller.php (was Installer.php)
MyModuleVersion.php (was Version.php) (todo - this file may go away)
FooMyModule.php
CHANGELOG.md
LICENSE
README.md
composer.json (this file is required, see example)
phpunit.xml.dist
The last file FooMyModule.php
is new and should look like this
combining the vendor name (Foo
with the class name).
<?php
namespace Foo\MyModule;
use Zikula\Core\AbstractModule;
class FooMyModule extends AbstractModule
{
}
.. note::
The namespace can be as deep as required, e.g
Zikula\Module\AdminModule
would result in a class
called Zikula\Module\AdminModule\ZikulaAdminModule
There is a script to restructure the module for you:
zikula-tools module:restructure --dir=module/MyModule --vendor=Foo --module=MyModule
You should commit these changes immediately. Your module will continue to work with the interrim structure created, and you can begin refactoring to namespaces.
.. note::
It's wise to git mv
the files to rename/move file before making changes
to the file contents (which should be made in a separate commit).
It is also recommended you place templates in the Resource/views
folder in a
hierarchy as follows:
Resources/
views/
Admin/
view.tpl
list.tpl
User/
view.tpl
This necessitates a change in template calls such as:
$this->view->fetch('Admin/view.tpl');
Modules must have a composer.json
manifest which looks like the following:
{
"name": "foo/my-module",
"description": "My Module",
"type": "zikula-module",
"license": "LGPL-3.0+",
"authors": [
{
"name": "Example",
"homepage": "http://example.com/"
}
],
"autoload": {
"psr-0": { "Foo\\MyModule\\": "" }
},
"require": {
"php": ">5.3.3"
},
"extra": {
"zikula": {
"class": "Foo\\MyModule\\FooMyModule"
}
}
}
PhpStorm 6 and MOST 0.6.1 have create tools for this.
All public controller methods meant to be accessible from the browser request should now be
suffixed with Action
, so public function view()
should now read public function viewAction()
There is a script to automate this change:
zikula-tools module:controller_actions --dir=module/MyModule/Controller
Old method names will continue to work for the time being.
The default action should be named indexAction()
however please not that all routes
must be explicitly referenced so there is in fact no default route any more for a module.
Arguments of controller methods now automatically receive the request. For example if ?name=Fred&age=21 then
public function fooAction($name, $age)
{
return new Response("Hello $name, you are $age");
}
Argument order does not matter.
You can also get the request object using this:
public function fooAction(Request $request)
{
$name = $request->query->get('name');
return new Response("Hello $name");
}
Controllers should return a Symfony\Component\HttpFoundation\Response
.
If you wish to not display the theme, it should emit a
Zikula\Core\Response\PlainResponse
.
Zikula will wrap controller return in an appropriate Response.
Documentation: http://symfony.com/doc/master/components/http_foundation/introduction.html#response
This change is internal so is referenced for completeness only.
The Zikula_ServiceManager has been replaced with the Symfony2 Dependency Injection 2.2 component.
Zikula specifically uses the ContainerBuilder
without compilation.
Documentation: http://symfony.com/doc/master/components/dependency_injection/index.html
The event system has been switched out for Symfony2 Event Dispatcher 2.2 component.
Zikula specifically uses the ContainerAwareEventDispatcher
. Please use the Symfony2 API
only. You should change any typehints from Zikula_EventManager
to ContainerAwareEventDispatcher
.
The main changes are:
-
Listener priorities are reversed. Higher numbers are executed first. When attaching listeners using the
Zikula_EventManager::attach()
API is fully BC, and translates the priorities to theEventDispatcher
standard. -
Introduced a new generic event object called
Zikula\Core\Event\GenericEvent
. This is compatible withZikula_Event
and you should switch to using it immediately. -
Events are triggered by
->dispatch($name, $event)
instead of->notify($event)
.
Example in Core 1.3.0-1.3.6
$event = new Zikula_Event('event.name', $subject, $args, $data);
$eventManager->notify($event);
Example in Core 1.3.7+
$event = new Zikula\Core\Event\GenericEvent($subject, $args, $data);
$dispatcher->dispatch('event.name', $event);
Please note, while they will still work, you should also update event method calls if you use them:
$event->stop() ======= $event->stopPropagation()
$event->isStopped() == $event->isPropagationStopped()
$event->hasArg() ===== $event->hasArgument()
$event->getArg() ===== $event->getArgument()
$event->getArgs() ==== $event->getArguments()
$event->setArg() ===== $event->setArgument()
$event->setArgs() ==== $event->setArguments()
Documentation: http://symfony.com/doc/master/components/event_dispatcher/introduction.html
There are lots of new events you can see them here:
http://symfony.com/doc/current/book/internals.html#events http://symfony.com/doc/current/components/http_kernel/introduction.html#component-http-kernel-event-table
The following list of even names have been removed:
boostrap.getconfig
- there is no replacementbootstrap.custom
- there is no replacementfrontcontroller.predispatch
- there is no replacementfrontcontroller.exception
- Subscribe to Kernel::EXCEPTION insteadsetup.errorreporting
- there is no replacementsystemerror
- there is no replacement
Hooks have been altered to use the Symfony2 Event Dispatcher 2.2 component.
The main changes are:
-
Four new Hook objects with no name arg in the constructor:
Zikula\Core\Hook\DisplayHook
(wasZikula_DisplayHook
).Zikula\Core\Hook\FilterHook
(wasZikula_FilterHook
).Zikula\Core\Hook\ProcessHook
(wasZikula_ProcessHook
).Zikula\Core\Hook\ValidationHook
(wasZikula_ValidationHook
).
-
hooks are triggered by
->dispatch($name, $hook)
instead of->notify($hook)
Example in Core 1.3.0-1.3.6
$hook = new Zikula_DisplayHook('hook.name', $id, $url);
$eventManager->notify($hook);
Example in Core 1.3.7+
$hook = new Zikula\Core\Hook\DisplayHook($id, $url);
$hookDispatcher->dispatch('hook.name', $hook);
New class list:
Zikula\Core\Hook\ValidationProviders
(wasZikula_Hook_ValidationProviders
).Zikula\Core\Hook\ValidationResponse
(wasZikula_Hook_ValidationResponse
).Zikula\Core\Hook\DisplayResponse
(wasZikula_Response_DisplayHook
).Zikula\Core\Hook\AbstractHookListener
(wasZikula_Hook_AbstractHandler
).Zikula\Component\HookDispatcher\SubscriberBundle
(wasZikula_HookManager_SubscriberBundle
).Zikula\Component\HookDispatcher\ProviderBundle
(wasZikula_HookManager_ProviderBundle
).
The Request
object is now switched to Symfony\Component\HttpFoundation\Request
Please refactor the following calls:
$request->getGet()->*() becomes $request->query->*()
$request->getPost()->*() becomes $request->post->*()
$request->isGet() becomes $request->isMethod('GET')
$request->isPost() becomes $request->isMethod('POST')
There is a legacy layer in place so the old methods continue to work.
Please note the follow APIs have changed (BC break)
$request->.....->filter() // the argument order has changed
$request->files-> // this API now returns an object, not an array
Documentation: http://symfony.com/doc/master/components/http_foundation/introduction.html#request
If you use Sluggable
, you must change the annotation in your Doctrine entities from:
from:
/**
* @ORM\Column(name="tag", type="string", length=36)
* @Gedmo\Sluggable(slugField="slug")
*/
private $tag;
/**
* @ORM\Column(name="slug", type="string", length=128)
* @Gedmo\Slug
*/
private $slug;
to:
/**
* @ORM\Column(name="tag", type="string", length=36)
*/
private $tag;
/**
* @ORM\Column(name="slug", type="string", length=128)
* @Gedmo\Slug(fields={"tag"})
*/
private $slug;
The Doctrine Extension Paginate is deprecated. If you are using it, you should refactor it to Doctrine\ORM\Tools\Pagination\Paginator
.
Modules should have core_min = 1.3.7
.
You now can add a reason for each dependency. Add a reason
key to any dependency array you want. Example:
$meta['dependencies'] = array(
array('modname' => 'Scribite',
'minversion' => '5.0.0',
'maxversion' => '',
'status' => ModUtil::DEPENDENCY_RECOMMENDED,
'reason' => 'Scribite adds a html editor.'),
);
Note: This only works for modules using the new >= 1.3.7 structure. Modules with the < 1.3.7 structure are ignoring this setting.
Theme's look very similar to modules.
foo-my/
Foo/
MyTheme/
Resources/
config/
admin.ini
home.ini
master.ini
overrides.yml
pageconfigurations.ini
themepalettes.ini
themevariables.ini
docs/
locale/
foomytheme.pot
public/
css/
images/
js/
views/
blocks/
includes/
modules/
ZikulaSearchModule/
Block/
search.tpl
admin.tpl
home.tpl
master.tpl
plugins/
Tests/
MyThemeVersion.php (was Version.php) (todo - this file may go away)
FooMyTheme.php
CHANGELOG.md
LICENSE
README.md
composer.json (this file is required, see example)
phpunit.xml.dist
Themes must have a composer.json
manifest which looks like the following:
{
"name": "foo/my-theme",
"description": "My Theme",
"type": "zikula-theme",
"license": "LGPL-3.0+",
"authors": [
{
"name": "Zikula",
"homepage": "http://zikula.org/"
}
],
"autoload": {
"psr-0": { "Foo\\Theme\\MyTheme\\": "" }
},
"require": {
"php": ">5.3.3"
},
"extra": {
"zikula": {
"class": "Foo\\Theme\\MyTheme\\FooMyTheme"
}
}
}
.. note::
The chosen namespace can be simplified to Foo\MyTheme\