I must hard code to add new layout. Then i want find some way to add template map dynamic in ZF2.
My module.config.php
'view_manager' => array (
'display_not_found_reason' => true,
'display_exceptions' => true,
'doctype' => 'HTML5',
'not_found_template' => 'error/404',
'exception_template' => 'error/index',
'template_map' => array (
'layout/layout' => __DIR__ . '/../../../template/layout/layout.phtml',
'layout/custom' => __DIR__ . '/../../../template/layout/custom.phtml',
'error/404' => __DIR__ . '/../../../template/error/404.phtml',
'error/index' => __DIR__ . '/../../../template/error/index.phtml'
),
'template_path_stack' => array (
__DIR__ . '/../view/'
)
)
And I set new layout by this way
$e->getApplication()->getEventManager()->getSharedManager()->attach('Zend\Mvc\Controller\AbstractActionController', 'dispatch', function($e) {
$controller = $e->getTarget();
$controller->layout('template_name');
}, 100);
Please lets me some advise/sample
Thanks !
==================
Update 12/08/2012:
I found the solution for this and apply to my "hierarchy template system"
Modify module.config.php
'template_path_stack' => array (
__DIR__ . '/../view/',
__DIR__ . '/../../../' //Parent folder of template path
)
In Module.php added :
$e->getApplication()->getEventManager()->getSharedManager()->attach('Zend\Mvc\Controller\AbstractActionController', 'dispatch', function($e) {
$controller = $e->getTarget();
$controllerClass = get_class($controller);
//Get routing info
$controllerArr = explode('\\', $controllerClass);
$currentRoute = array(
'module' => strtolower($controllerArr[0]),
'controller' => strtolower(str_replace("Controller", "", $controllerArr[2])),
'action' => strtolower($controller->getEvent()->getRouteMatch()->getParam('action'))
);
//Get curr route
$currAction = implode('/',$currentRoute);
$currController = $currentRoute['module'] . '/' . $currentRoute['controller'];
$currModule = $currentRoute['module'];
//Template file location
$templatePath = __DIR__ .'/../../template/';
//Set template
$template = 'layout/layout'; // Default template
if (file_exists($templatePath . $currAction.'.phtml')) {
$template = $currAction;
}else if(file_exists($templatePath . $currController.'.phtml')) {
$template = $currController;
}else if(file_exists($templatePath . $currModule.'.phtml')) {
$template = $currModule;
}else{
if($currentRoute['controller']=='admin'){
$template = 'admin/layout'; // Admin default template
}
}
$controller->layout('template/'.$template); //Pevert duplicate layout
}, 100);
Note: If you set the key same variable between your 'layout' and 'view'. It will render duplicate the 'layout' and don't understand your current view
In your controller when you create a new viewmodel you can set the template you've created there.
public function someAction() {
$viewModel = new ViewModel();
$viewModel->setTemplate('layout/custom');
return $viewModel;
}
Just make sure the layout.phtml file is in the path you set in your template_map
Related
I have two module in my ZF2 application, both module have different configuration for themself, and both module have different Module.php with different configruation inside it.
I have a login process for Admin, which is defined in Module.php like below:
in onBootstrap funtion:
public function onBootstrap($e) {
$e->getApplication()->getEventManager()->getSharedManager()->attach('Zend\Mvc\Controller\AbstractActionController', 'dispatch', function($e) {
$controller = $e->getTarget();
$controllerClass = get_class($controller);
$moduleNamespace = substr($controllerClass, 0, strpos($controllerClass, '\\'));
if ('Admin' === $moduleNamespace) {
$controller->layout('layout/admin');
}
}, 100);
$application = $e->getApplication();
$eventManager = $application->getEventManager();
..........
..........
$eventManager->attach(MvcEvent::EVENT_DISPATCH, array($this, 'boforeDispatch'), 100);
}
boforeDispatch function which is called inside the onBootstrap for login process check
function boforeDispatch(MvcEvent $event) {
......
//did something
......
}
Whenever I am going to run Front module, Admin module's function beforeDispatch is running. I also tried to define another function inside Front module with no content inside so that it could not merge it.
2
I have written different 404 template for both module, but Front's template is running. Here is the code.:
'view_manager' => array(
'display_not_found_reason' => true,
'display_exceptions' => true,
'doctype' => 'HTML5',
'not_found_template' => 'error/404',
'exception_template' => 'error/index',
'template_map' => array(
'layout/front' => __DIR__ . '/../view/layout/layout.phtml',
'front/index/index' => __DIR__ . '/../view/front/index/index.phtml',
'error/404' => __DIR__ . '/../view/error/404.phtml',
'error/index' => __DIR__ . '/../view/error/index.phtml',
),
'template_path_stack' => array(
__DIR__ . '/../view',
),
),
both's files are inside its module folder with same structure.
Q: How to prevent merging one module configuration from another?
You shouldn't prevent merging. There is a similar problem with loading different layout for 2 modules - take a look https://stackoverflow.com/a/11921330/949273
Unfortunately, Your issue is a bit contradictory because if you got a 404 page, there is no way to know what module is that - because of that it's called 404 page not found.
Anyway you can dispatch MvcEvent::EVENT_DISPATCH_ERROR event and check with regular expression URL and set different view file.
Code example
in your admin module config
'template_map' => array(
'error-admin/404' => __DIR__ . '/../view/error/404.phtml',
),
than on EVENT_DISPATCH_ERROR inject your logic
public function onBootstrap(MvcEvent $e)
{
$app = $e->getTarget();
$em = $app->getEventManager();
$em->attach(MvcEvent::EVENT_DISPATCH_ERROR, function (\Zend\Mvc\MvcEvent $e) {
$app = $e->getParam('application');
$uri = $app->getRequest()->getUri()->getPath();
if(strpos($uri, '/admin') === 0){
$view = new \Zend\View\Model\ViewModel();
$view->setTemplate('error-admin/404');
$e->setViewModel($view);
}
});
}
After lots of search I got the solution of my question.
Main problem was getting the Module name. here is my code.
I generated it with the help of MvcEvent::getRouteMatch()->getParam()
function boforeDispatch(MvcEvent $event) {
$controller = $event->getRouteMatch()->getParam('controller');
$request_module = substr($controller, 0, strpos($controller, '\\'));
if ($request_module == __NAMESPACE__) {
//do stuff
}
}
In my company we developing a ZF2 application, no programm;-), right now. We are at a point where we want to test some part of the application by bringing it into the public www.
We prepared a STAGE-environment and i do some performance tuning now. I read that using the ClassMapAutoloader is much faster than the StandardAutoLoader like described e.g. http://samminds.com/2012/11/zf2-performance-quicktipp-2-classmap-autoloading/ . I do understand why it should be faster but in my case i profiled the site with and without ClassMapAutoloader using xdebug profiling, WinCacheGring/QCacheGrind and it is slower about 0,2%.
Does anyone has an idea why this could be slower?
I am using CentOS and PHP Version => 5.6.12
EDIT ADDED INFORMATION:
Example of one autoload_classmap.php:
<?php
// Generated by ZF2's ./bin/classmap_generator.php
return array(
'Search\Elasticsearch\Document\AbstractDocument' => __DIR__ . '/src/Search/Elasticsearch/Document/AbstractDocument.php',
'Search\Elasticsearch\Document\ArticleDocument' => __DIR__ . '/src/Search/Elasticsearch/Document/ArticleDocument.php',
'Search\Elasticsearch\Document\BookingDocument' => __DIR__ . '/src/Search/Elasticsearch/Document/BookingDocument.php',
'Search\Elasticsearch\Document\DocumentType' => __DIR__ . '/src/Search/Elasticsearch/Document/DocumentType.php',
'Search\Elasticsearch\Document\InvoiceDocument' => __DIR__ . '/src/Search/Elasticsearch/Document/InvoiceDocument.php',
'Search\Elasticsearch\Document\OfficeDocument' => __DIR__ . '/src/Search/Elasticsearch/Document/OfficeDocument.php',
'Search\Elasticsearch\Document\OfficeMemberDocument' => __DIR__ . '/src/Search/Elasticsearch/Document/OfficeMemberDocument.php',
'Search\Elasticsearch\Document\ProductDocument' => __DIR__ . '/src/Search/Elasticsearch/Document/ProductDocument.php',
'Search\Elasticsearch\Document\ProfileDocument' => __DIR__ . '/src/Search/Elasticsearch/Document/ProfileDocument.php',
'Search\Elasticsearch\Document\RatingDocument' => __DIR__ . '/src/Search/Elasticsearch/Document/RatingDocument.php',
'Search\Elasticsearch\Document\AbstractWebSearchDocument' => __DIR__ . '/src/Search/Elasticsearch/Document/AbstractWebSearchDocument.php',
'Search\Elasticsearch\AutoSuggestionQueryHandler' => __DIR__ . '/src/Search/Elasticsearch/AutoSuggestionQueryHandler.php',
'Search\Elasticsearch\SearchStatisticIndexHandler' => __DIR__ . '/src/Search/Elasticsearch/SearchStatisticIndexHandler.php',
'Search\Elasticsearch\TermRecognizerQueryHandler' => __DIR__ . '/src/Search/Elasticsearch/TermRecognizerQueryHandler.php',
'Search\Elasticsearch\SearchIndexHandler' => __DIR__ . '/src/Search/Elasticsearch/SearchIndexHandler.php',
'Search\Elasticsearch\SearchQueryHandler' => __DIR__ . '/src/Search/Elasticsearch/SearchQueryHandler.php',
'Search\Elasticsearch\TermRecognizerIndexHandler' => __DIR__ . '/src/Search/Elasticsearch/TermRecognizerIndexHandler.php',
'Search\Exception\Exception' => __DIR__ . '/src/Search/Exception/Exception.php',
'Search\Factory\AutoSuggestQueryHandlerFactory' => __DIR__ . '/src/Search/Factory/AutoSuggestQueryHandlerFactory.php',
'Search\Factory\AutoSuggestServiceFactory' => __DIR__ . '/src/Search/Factory/AutoSuggestServiceFactory.php',
'Search\Factory\DocumentStorerServiceFactory' => __DIR__ . '/src/Search/Factory/DocumentStorerServiceFactory.php',
'Search\Factory\QueueWorkerServiceFactory' => __DIR__ . '/src/Search/Factory/QueueWorkerServiceFactory.php',
'Search\Factory\SearchIndexHandlerFactory' => __DIR__ . '/src/Search/Factory/SearchIndexHandlerFactory.php',
'Search\Factory\SearchQueryHandlerFactory' => __DIR__ . '/src/Search/Factory/SearchQueryHandlerFactory.php',
'Search\Factory\SearchServiceFactory' => __DIR__ . '/src/Search/Factory/SearchServiceFactory.php',
'Search\Factory\SearchSimpleServiceFactory' => __DIR__ . '/src/Search/Factory/SearchSimpleServiceFactory.php',
'Search\Factory\SearchStatistikIndexHandlerFactory' => __DIR__ . '/src/Search/Factory/SearchStatistikIndexHandlerFactory.php',
'Search\Factory\TermRecognizerServiceFactory' => __DIR__ . '/src/Search/Factory/TermRecognizerServiceFactory.php',
'Search\Factory\TermrecognizerIndexHandlerFactory' => __DIR__ . '/src/Search/Factory/TermrecognizerIndexHandlerFactory.php',
'Search\Factory\TermrecognizerQueryHandlerFactory' => __DIR__ . '/src/Search/Factory/TermrecognizerQueryHandlerFactory.php',
'Search\Factory\RequestHandlerFactory' => __DIR__ . '/src/Search/Factory/RequestHandlerFactory.php',
'Search\Logger\LoggerInterface' => __DIR__ . '/src/Search/Logger/LoggerInterface.php',
'Search\Logger\StatisticLogger' => __DIR__ . '/src/Search/Logger/StatisticLogger.php',
'DatabaseQueue' => __DIR__ . '/src/Search/Queue/DatabaseQueue.php',
'Search\Search\QueryWordReducer' => __DIR__ . '/src/Search/Search/QueryWordReducer.php',
'Search\Search\RecognizedTermConsumer' => __DIR__ . '/src/Search/Search/RecognizedTermConsumer.php',
'Search\Search\SearchService' => __DIR__ . '/src/Search/Search/SearchService.php',
'Search\Search\SuggestionListBuilder' => __DIR__ . '/src/Search/Search/SuggestionListBuilder.php',
'Search\Search\Util' => __DIR__ . '/src/Search/Search/Util.php',
'Search\Search\ViewState' => __DIR__ . '/src/Search/Search/ViewState.php',
'Search\Search\ViewStateToSearchRequestTransformer' => __DIR__ . '/src/Search/Search/ViewStateToSearchRequestTransformer.php',
'Search\Search\SearchSimpleService' => __DIR__ . '/src/Search/Search/SearchSimpleService.php',
'Search\AutoSuggester' => __DIR__ . '/src/Search/AutoSuggester.php',
'Search\QueryCleaner' => __DIR__ . '/src/Search/QueryCleaner.php',
'Search\Request' => __DIR__ . '/src/Search/Request.php',
'Search\RequestHandler' => __DIR__ . '/src/Search/RequestHandler.php',
'Search\SearchSource' => __DIR__ . '/src/Search/SearchSource.php',
'Search\Util' => __DIR__ . '/src/Search/Util.php',
'Search\QueueWorker' => __DIR__ . '/src/Search/QueueWorker.php',
'Search\AbstractDocumentStorer' => __DIR__ . '/src/Search/AbstractDocumentStorer.php',
'Search\DocumentStorer' => __DIR__ . '/src/Search/DocumentStorer.php',
'Search\TermRecognizer' => __DIR__ . '/src/Search/TermRecognizer.php',
'Search\Module' => __DIR__ . '/Module.php',
);
Extract from the correlating Module.php:
public function getAutoloaderConfig() {
return [
'Zend\Loader\ClassMapAutoloader' => [
__DIR__ . '/autoload_classmap.php'
],
'Zend\Loader\StandardAutoloader' => [
'namespaces' => [
__NAMESPACE__ => __DIR__ . '/src/' . str_replace('\\', '/', __NAMESPACE__)
]
]
];
}
I checked already that the Autoloader uses the classmap.
EDIT ADDED INFORMATION:
Sorry for the late answer. Right now your app loads for half a second - 0.6s to be precise. So I the autoloader is doing his works. Your queries are also executed fast. There are two more ways I can think of to speed up your applications.
First way - using template map
Locate your templatemap_generator.php file. It should be in your vendor/zendframework/zendframework/bin folder. Navigate to your module folder e.g. Application directory where the src, view, config folders are. Open a terminal and type php ../../vendor/zendframework/zendframework/bin/templatemap_generator.php ZF will create a template map in your module directory. Now to use this template, simply modify your module.config.php file. The file structure is similar to the one from clasmap_autoloader.php
return array(
// Telling where the views are
'view_manager' => array(
'display_not_found_reason' => true,
'display_exceptions' => true,
'doctype' => 'HTML5',
'not_found_template' => 'error/404',
'exception_template' => 'error/index',
'template_map' => include __DIR__ . '/../template_map.php', // <-- add this line. You can remove `template_path_stack`
),
In your controllersfor each action add a view template.
public indexAction()
{
$view = new ViewModel();
$view->setTemplate("aplication/index/index");
return $view;
}
Second way - Using module cache in production environment.
Let's say you have this line in your .htaccess - SetEnv APPLICATION_ENV "development"
In your public/index.php file if you haven't done something similar, add this:
/**
* Set global ENV. Used for debugging
*/
if (isset($_SERVER['APPLICATION_ENV']) && $_SERVER["APPLICATION_ENV"] === 'development') {
define("APP_ENV", 'development');
} else {
define("APP_ENV", "production");
}
This will ensure that you have a global env across your application which says if debugging is on or off and it helps you avoid DRY code.
Now from your root folder open config/application.config.php
<?php
$modules = [];
if (APP_ENV === 'development') {
$modules[] = 'ZendDeveloperTools';
$modules[] = 'BjyProfiler';
$modules[] = 'SanSessionToolbar';
}
$modules[] = 'Application';
$modules[] = 'Admin';
return [
// This should be an array of module namespaces used in the application.
'modules' => $modules,
// These are various options for the listeners attached to the ModuleManager
'module_listener_options' => [
// This should be an array of paths in which modules reside.
// If a string key is provided, the listener will consider that a module
// namespace, the value of that key the specific path to that module's
// Module class.
'module_paths' => [
'./module',
'./vendor',
],
// An array of paths from which to glob configuration files after
// modules are loaded. These effectively override configuration
// provided by modules themselves. Paths may use GLOB_BRACE notation.
'config_glob_paths' => [
'config/autoload/{{,*.}global,{,*.}local}.php',
],
// Whether or not to enable a configuration cache.
// If enabled, the merged configuration will be cached and used in
// subsequent requests.
'config_cache_enabled' => (APP_ENV === 'production'),
// The key used to create the configuration cache file name.
'config_cache_key' => md5('app_config'),
// Whether or not to enable a module class map cache.
// If enabled, creates a module class map cache which will be used
// by in future requests, to reduce the autoloading process.
'module_map_cache_enabled' => (APP_ENV === 'production'),
// The key used to create the class map cache file name.
'module_map_cache_key' => md5('module_map'),
// The path in which to cache merged configuration.
'cache_dir' => dirname(__DIR__)."/data/cache",
// Whether or not to enable modules dependency checking.
// Enabled by default, prevents usage of modules that depend on other modules
// that weren't loaded.
'check_dependencies' => (APP_ENV !== 'production'),
],
// Used to create an own service manager. May contain one or more child arrays.
//'service_listener_options' => [
// [
// 'service_manager' => $stringServiceManagerName,
// 'config_key' => $stringConfigKey,
// 'interface' => $stringOptionalInterface,
// 'method' => $stringRequiredMethodName,
// ],
// )
// Initial configuration with which to seed the ServiceManager.
// Should be compatible with Zend\ServiceManager\Config.
// 'service_manager' => [],
];
config_cache_* will activate and cache your route config when your app is in production. All your module routes will be cached. Also If the website is in production the debugging modules will not be loaded.
You can replace md5('app_config') with whatever you want.
I have a problem. I want to add my custom library when the webapplication starts and i want use it in application layout. I want to create a form (composed by 2 concatenated select with ajax functions) and it must be visible in all parts of the application. when i tried to use my helper custom library, this is the error message:
Fatal error: Class 'SelectSearchList' not found in C:\Program Files (x86)\xampp\htdocs\Easyanimal\module\Application\view\layout\layout.phtml on line 118
this is the code of vendor/composer/autoload_namespaces.php:
<?php
// autoload_namespaces.php generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'Zend\\' => $vendorDir . '/zendframework/zendframework/library/',
'ZendTest\\' => $vendorDir . '/zendframework/zendframework/tests/',
'MyHelpLib\\' => $vendorDir . '/MyHelpLib/',
);
this is my help library in vendor/MyHelpLib/LoaderSelect.php:
namespace MyHelpLib
class SelectSearchList {
public $select;
public function showOpt (){
return $select = '<option value="">Select...</option>';
}
}
and this my layout in application/view/layout
<?php
use MyHelpLib\LoaderSelect;
$Opt = new SelectSearchList();
echo $Opt->showOpt();
?>
i tried to add this in Application/module.php but it isn't work again!
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
'MyHelpLib' => __DIR__ . '/../../vendor/MyHelpLib',
),
),
);
}
thanks so much for the help
Create view helper. http://framework.zend.com/manual/2.3/en/modules/zend.view.helpers.advanced-usage.html#writing-custom-helpers
Index\src\View\Helper\MyHelpLib
namespace Index\View\Helper;
use Zend\View\Helper\AbstractHelper;
class MyHelpLib extends AbstractHelper
{
public function __invoke()
{
return 'MyHelper'
}
}
Index\config\module.config.php
return array(
...
'view_helpers' => array(
'invokables' => array(
'MyHelpLib' => '\Index\View\Helper\MyHelpLib'
)
)
);
layout.phtml
echo $this->MyHelpLib();
I'm using twig, and i'm attempting to add a function.
$Func = new \Twig_SimpleFunction('placeholder', function ($title) {
$this->module->CurrentPage->addPlaceholder($title);
});
\App::make('twig')->addFunction($Func);
I will get the following exception
Unable to add function "placeholder" as extensions have already been initialized.
I've checked twice that the "addFunction" is executed before the twig "loadTemplate". So, it does not seem to be the problem.
Does anyone have a hint, or an idea about this? Or what its all about.
Thanks in advance.
You need to add twig functions right after you created Twig_Environment instance. For example, the following WILL NOT work:
$loader = new Twig_Loader_Filesystem($this->resourceRoot . '/views');
$twig = new Twig_Environment($loader, array(
'cache' => storage_path('twig'),
'debug' => Config::get('app.debug'),
'strict_variables' => true,
));
$lexer = new Twig_Lexer($twig, array(
'tag_comment' => array('{#', '#}'),
'tag_block' => array('{%', '%}'),
'tag_variable' => array('{^', '^}'),
'interpolation' => array('#{', '}'),
));
$twig->setLexer($lexer);
$function = new Twig_SimpleFunction('widget', function ($widget, array $params) {
WidgetFactory::renderWidget($widget, $params);
});
$twig->addFunction($function);
Because Lexer is initialized before functions are added. You need to make it like this:
$loader = new Twig_Loader_Filesystem($this->resourceRoot . '/views');
$twig = new Twig_Environment($loader, array(
'cache' => storage_path('twig'),
'debug' => Config::get('app.debug'),
'strict_variables' => true,
));
$function = new Twig_SimpleFunction('widget', function ($widget, array $params) {
WidgetFactory::renderWidget($widget, $params);
});
$twig->addFunction($function);
$lexer = new Twig_Lexer($twig, array(
'tag_comment' => array('{#', '#}'),
'tag_block' => array('{%', '%}'),
'tag_variable' => array('{^', '^}'),
'interpolation' => array('#{', '}'),
));
$twig->setLexer($lexer);
Code:
$app->register(new Silex\Provider\TranslationServiceProvider(), array(
'locale' => 'sr_Latn',
'translation.class_path' => __DIR__ . '/../vendor/symfony/src',
'translator.messages' => array('sr_Latn' => __DIR__ .'/../vendor/symfony/src/Symfony/Bundle/FrameworkBundle/Resources/translations/validators.sr_Latn.xlf')
));
$app['translator.loader'] = new Symfony\Component\Translation\Loader\XliffFileLoader();
and I still get validation messages in english. any idea?
You need to add a call to Translator::addResource:
$file = __DIR__ .'/../vendor/symfony/src/Symfony/Bundle/FrameworkBundle/Resources/translations/validators.sr_Latn.xlf';
$app['translator']->addResource('xliff', $file, 'sr_Latn', 'validators');
See also Symfony\Bundle\FrameworkBundle\DependencyInjection::registerTranslatorConfiguration.