I'm trying to clear a custom placeholder from a viewscript, let's say I have a controller plugin that creates a sidebar:
$bootstrap = Zend_Controller_Front::getInstance()->getParam('bootstrap');
$view = $bootstrap->getResource('view');
$partial = $view->render('partials/_sidebar.phtml');
$view->placeholder('sidebar')->append($partial);
My partial contains my submenu (rendered through Zend_Navigation view helper).
In order to render that sidebar, I have this in my layout:
<?= $this->placeholder('sidebar'); ?>
But what if in some pages I don't want to display my sidebar (login page for example) ? How can I handle these cases?
I thought I could reset/clear my placeholder using $this->placeholder('sidebar')->exchangeArray(array()); but it seems that I can't access my placeholder from a viewscript:
// in /application/modules/default/views/account/login.phtml
<?php $placeholder = $this->placeholder('sidebar');
Zend_Debug::dump($placeholder); ?>
// output:
object(Zend_View_Helper_Placeholder_Container)#217 (8) {
["_prefix":protected] => string(0) ""
["_postfix":protected] => string(0) ""
["_separator":protected] => string(0) ""
["_indent":protected] => string(0) ""
["_captureLock":protected] => bool(false)
["_captureType":protected] => NULL
["_captureKey":protected] => NULL
["storage":"ArrayObject":private] => array(0) {
}
}
Any idea how to do such a thing?
Thanks.
Edit:
My problem was very simple actually, since my plugin was registered and executed in the postDispatch() method, then my viewscript was executed before the plugin and the layout was executed after the plugin.
From now on, what are my options? I can't really declare my sidebar in the preDispatch method because there won't be any script directory set, and therefore I won't be able to determine which view script to execute at this step.
I could also use an action() helper, what do you think? A question has been already asked about it. I still feel like this is not the proper way to do it, and it sounds overkilling to me.
Also, another idea would be to move my plugin into a the preDispatch() method of my controller, but that would lead me to copy/paste on every controller my sidebar, or create a baseController, but I still don't like this idea, I feel like I'm doing it wrong.
Any idea?
You were pretty close actually. You just needed to add the name of your placeholder, sidebar in this case:
$this->placeholder('sidebar')->exchangeArray(array()); should work.
See http://framework.zend.com/manual/en/zend.view.helpers.html#zend.view.helpers.initial.placeholder
EDIT:
That's strange that the above did not work for you. I tested this out on my own ZF website and it worked. Possibly different scenario. I don't know.
Here is another alternative, albeit more involved.
//Get the placeholder object directly
$placeholderObj = $this->getHelper('placeholder')
//This may be why you were getting null in your example above. Since your were using the magic method in the View class to call the placeholder view helper method directly.
//For example you could call the placeholder like so:
$placeholderObj->placeholder('sidebar')->set("Some value");
//Now the alternative way to remove the placeholder value is as follows.
$registry = $placeholderObj->getRegistry()
$registry->deleteContainer('sidebar');
EDIT3
It should work as a Zend_Controller_Plugin using preDispatch hook. I think the only you need to make sure of is that you order that plugin after you setting your view script/helper paths and layout paths. This can be done in the same plugin or in another plugin.
Here is a code example based on something I use on my website. The relevant part is just the stuff in preDispatch where I set the view script paths, etc
class RT_Theme extends Zend_Controller_Plugin_Abstract
{
private $_sitename;
private $_assets;
private $_appPath;
private $_appLibrary;
/**
* Constructor
*
* #param string $sitename
* #param SM_Assets $assets
* #param string $appPath
* #param string $appLibrary
*/
public function __construct($sitename, $assets, $appPath, $appLibrary)
{
$this->_sitename = $sitename;
$this->_assets = $assets;
$this->_appPath = $appPath;
$this->_appLibrary = $appLibrary;
}
/**
* Sets up theme
*
* Sets up theme template directory and assets locations (js, css, images)
*
* #param Zend_Controller_Request_Abstract $request
*/
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$module = $request->getModuleName();
$controller = $request->getControllerName();
$action = $request->getActionName();
$layout = Zend_Layout::getMvcInstance();
$view = $layout->getView();
$view->sitename = $this->_sitename;
$view->headTitle()->setSeparator(' - ')->headTitle($view->sitename);
$layout->setLayoutPath($this->_appPath . "/html/$module/layout/");
$view->setScriptPath($this->_appPath . "/html/$module/view/");
$view->addScriptPath($this->_appPath . "/html/$module/view/_partials/");
$view->addScriptPath($this->_appLibrary . '/RT/View/Partials/');
$view->addHelperPath('RT/View/Helper', 'RT_View_Helper');
$view->addHelperPath($this->_appPath . '/html/view/helpers','My_View_Helper');
$viewRenderer =
Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
$viewRenderer->setView($view);
//Ignore this line. Not relevant to the question
$this->_assets->loadFor($controller, $action);
//Example: Now I can set the placeholder.
$view->placeholder('header_title')->set($view->sitename);
}
}
Related
I've got a search form with some select boxes. I render it in the headnavi on every page using ebedded controllers. (http://symfony.com/doc/current/book/templating.html#embedding-controllers)
I want to use the form output to redirect to my list-view page like this:
/list-view/{city}/{category}?q=searchQuery
My form and the request is working well when I call the controller through a route, but unfortunately when I embed the controller, I'm stumblig over two problems. Like I've read here (Symfony 2 - Layout embed "no entity/class form" validation isn't working) my request isn't handeled by my form because of the sub-request. There is a solution in the answer, but its not very detailed.
The other problem, after fixing the first one, will be that I can't do a redirect from an embedded controller (Redirect from embedded controller).
Maybe anyone has an easier solution for having a form on every page that lets me do a redirect to its data?
Many thanks and greetings
Raphael
The answer of Symfony 2 - Layout embed "no entity/class form" validation isn't working is 100% correct, but we use contexts and isolate them, so an action which always uses the master request would break the rules. You have all requests (one master and zero or more subrequests) in the request_stack. Injecting Request $request into your controller action is the current request which is the subrequest with only max=3 (injecting the Request is deprecated now). Thus you have to use the 'correct' request.
Performing a redirection can be done in many ways, like return some JS script code to redirect (which is quite ugly imho). I would not use subrequests from twig because it's too late to start a redirection then, but make the subrequest in the action. I didn't test the code, but it should work. Controller::forward is your friend, since it duplicatest the current request for performing a subrequest.
Controller.php (just to see the implementation).
/**
* Forwards the request to another controller.
*
* #param string $controller The controller name (a string like BlogBundle:Post:index)
* #param array $path An array of path parameters
* #param array $query An array of query parameters
*
* #return Response A Response instance
*/
protected function forward($controller, array $path = array(), array $query = array())
{
$path['_controller'] = $controller;
$subRequest = $this->container->get('request_stack')->getCurrentRequest()->duplicate($query, null, $path);
return $this->container->get('http_kernel')->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
}
YourController.php
public function pageAction() {
$formResponse = $this->forward('...:...:form'); // e.g. formAction()
if($formResponse->isRedirection()) {
return $formResponse; // just the redirection, no content
}
$this->render('...:...:your.html.twig', [
'form_response' => $formResponse
]);
}
public function formAction() {
$requestStack = $this->get('request_stack');
/* #var $requestStack RequestStack */
$masterRequest = $requestStack->getCurrentRequest();
\assert(!\is_null($masterRequest));
$form = ...;
$form->handleRequest($masterRequest);
if($form->isValid()) {
return $this->redirect(...); // success
}
return $this->render('...:...:form.html.twig', [
'form' => $form->createView()
]);
}
your.html.twig
{{ form_response.content | raw }}
I am trying to implement URL based translation in Zend Framework so that my site is SEO friendly. This means that I want URLs like the below in addition to the default routes.
zend.local/en/module
zend.local/en/controller
zend.local/en/module/controller
zend.local/en/controller/action
The above are the ones I have problems with right now; the rest should be OK. I have added a controller plugin that fetches a lang parameter so that I can set the locale and translation object in the preDispatch method. Here are some of my routes (stored in a .ini file):
; Language + module
; Language + controller
resources.router.routes.lang1.type = "Zend_Controller_Router_Route_Regex"
resources.router.routes.lang1.route = "(^[a-zA-Z]{2})/(\w+$)"
resources.router.routes.lang1.defaults.controller = index
resources.router.routes.lang1.defaults.action = index
resources.router.routes.lang1.map.1 = "lang"
resources.router.routes.lang1.map.2 = "module"
; Language + module + controller
; Language + controller + action
resources.router.routes.lang2.type = "Zend_Controller_Router_Route_Regex"
resources.router.routes.lang2.route = "(^[a-zA-Z]{2})/(\w+)/(\w+$)"
resources.router.routes.lang2.defaults.module = default
resources.router.routes.lang2.defaults.action = index
resources.router.routes.lang2.map.1 = "lang"
resources.router.routes.lang2.map.2 = "controller"
resources.router.routes.lang2.map.3 = "action"
As the comments indicate, several URL structures will match the same route, which makes my application interpret the format incorrectly. For instance, the following two URLs will be matched by the lang1 route:
zend.local/en/mymodule
zend.local/en/mycontroller
In the first URL, "mymodule" is used as module name, which is correct. However, in the second URL, "mycontroller" is used as module name, which is not what I want. Here I want it to use the "default" module and "mycontroller" as controller. The same applies for the previous lang2 route. So I don't know how to distinguish between if the URL is of the structure /en/module or /en/controller.
To fix this, I experimented with the code below in my controller plugin.
// Get module names as array
$dirs = Zend_Controller_Front::getInstance()->getControllerDirectory();
$modules = array_keys($dirs);
// Module variable contains a module that does not exist
if (!in_array($request->getModuleName(), $modules)) {
// Try to use it as controller name instead
$request->setControllerName($request->getModuleName());
$request->setModuleName('default');
}
This works fine in the scenarios I tested, but then I would have to do something similar to make the lang2 route work (which possibly involves scanning directories to get the list of controllers). This just seems like a poor solution, so if it is possible, I would love to accomplish all of this with routes only (or simple code that is not so "hacky"). I could also make routes for every time I want /en/controller, for instance, but that is a compromise that I would rather not go with. So, if anyone knows how to solve this, or know of another approach to accomplish the same thing, I am all ears!
I've reproduced your problem here and come out with the following (not using config files though):
Router
/**
* Initializes the router
* #return Zend_Controller_Router_Interface
*/
protected function _initRouter() {
$locale = Zend_Registry::get('Zend_Locale');
$routeLang = new Zend_Controller_Router_Route(
':lang',
array(
'lang' => $locale->getLanguage()
),
array('lang' => '[a-z]{2}_?([a-z]{2})?')
);
$frontController = Zend_Controller_Front::getInstance();
$router = $frontController->getRouter();
// Instantiate default module route
$routeDefault = new Zend_Controller_Router_Route_Module(
array(),
$frontController->getDispatcher(),
$frontController->getRequest()
);
// Chain it with language route
$routeLangDefault = $routeLang->chain($routeDefault);
// Add both language route chained with default route and
// plain language route
$router->addRoute('default', $routeLangDefault);
// Register plugin to handle language changes
$frontController->registerPlugin(new Plugin_Language());
return $router;
}
Plug-in
/**
* Language controller plugin
*/
class Plugin_Language extends Zend_Controller_Plugin_Abstract
{
/**
* #var array The available languages
*/
private $languages = array('en', 'pt');
/**
* Check the URI before starting the route process
* #param Zend_Controller_Request_Abstract $request
*/
public function routeStartup(Zend_Controller_Request_Abstract $request)
{
$translate = Zend_Registry::get('Zend_Translate');
$lang = $translate->getLocale();
// Extracts the URI (part of the URL after the project public folder)
$uri = str_replace($request->getBaseUrl() . '/', '', $request->getRequestUri());
$langParam = substr($uri, 0, 3);
// Fix: Checks if the language was specified (if not, set it on the URI)
if((isset($langParam[2]) && $langParam[2] !== '/') || !in_array(substr($langParam, 0, 2), $this->languages)) { {
$request->setRequestUri($request->getBaseUrl() . '/' . $lang . "/" . $uri);
$request->setParam('lang', $lang);
}
}
}
Basically, there's the route chain for applying the language settings within the module default route. As a fix, we ensure that the URI will contain the language if the user left it out.
You'll need to adapt it, as I'm using the Zend_Registry::get('Zend_Locale') and Zend_Registry::get('Zend_Translate'). Change it to the actual keys on your app.
As for the lang route: [a-z]{2}_?([a-z]{2})? it will allow languages like mine: pt_BR
Let me know if it worked for you.
Recently I've been doing some research into SEO and how URIs that use hyphens or underscores are treated differently, particularly by Google who view hyphens as separators.
Anyway, eager to adapt my current project to meet this criteria I found that because Kohana uses function names to define pages I was receiving the unexpected '-' warning.
I was wondering whether there was any way to enable the use of URIs in Kohana like:
http://www.mysite.com/controller/function-name
Obviously I could setup a routeHandler for this... but if I was to have user generated content, i.e. news. I'd then have to get all articles from the database, produce the URI, and then do the routing for each one.
Are there any alternative solutions?
Note: This is the same approach as in Laurent's answer, just slightly more OOP-wise. Kohana allows one to very easily overload any system class, so we can use it to save us some typing and also to allow for cleaner updates in the future.
We can plug-in into the request flow in Kohana and fix the dashes in the action part of the URL. To do it we will override Request_Client_Internal system class and it's execute_request() method. There we'll check if request->action has dashes, and if so we'll switch them to underscores to allow php to call our method properly.
Step 1. Open your application/bootstrap.php and add this line:
define('URL_WITH_DASHES_ONLY', TRUE);
You use this constant to quickly disable this feature on some requests, if you need underscores in the url.
Step 2. Create a new php file in: application/classes/request/client/internal.php and paste this code:
<?php defined('SYSPATH') or die('No direct script access.');
class Request_Client_Internal extends Kohana_Request_Client_Internal {
/**
* We override this method to allow for dashes in the action part of the url
* (See Kohana_Request_Client_Internal::execute_request() for the details)
*
* #param Request $request
* #return Response
*/
public function execute_request(Request $request)
{
// Check the setting for dashes (the one set in bootstrap.php)
if (defined('URL_WITH_DASHES_ONLY') and URL_WITH_DASHES_ONLY == TRUE)
{
// Block URLs with underscore in the action to avoid duplicated content
if (strpos($request->action(), '_') !== false)
{
throw new HTTP_Exception_404('The requested URL :uri was not found on this server.', array(':uri' => $request->uri()));
}
// Modify action part of the request: transform all dashes to underscores
$request->action( strtr($request->action(), '-', '_') );
}
// We are done, let the parent method do the heavy lifting
return parent::execute_request($request);
}
} // end_class Request_Client_Internal
What this does is simply replacing all the dashes in the $request->action with underscores, thus if url was /something/foo-bar, Kohana will now happily route it to our action_foo_bar() method.
In the same time we block all the actions with underscores, to avoid the duplicated content problems.
No way to directly map a hyphenated string to a PHP function so you will have to do routing.
As far as user generated content, you could do something like Stack Exchange does. Each time user content is saved to the database, generated a slug for it (kohana-3-2-how-can-i-use-hyphens-in-uris) and save it along with the other information. Then when you need to link to it, use the unique id and append the slug to the end (ex:http://stackoverflow.com/questions/7404646/kohana-3-2-how-can-i-use-hyphens-in-uris) for readability.
You can do this with lambda functions: http://forum.kohanaframework.org/discussion/comment/62581#Comment_62581
You could do something like
Route::set('route', '<controller>/<identifier>', array(
'identifier' => '[a-zA-Z\-]*'
))
->defaults(array(
'controller' => 'Controller',
'action' => 'show',
));
Then receive your content identifier in the function with Request::current()->param('identifier') and parse it manually to find the relating data.
After having tried various solutions, I found that the easiest and most reliable way is to override Kohana_Request_Client_Internal::execute_request. To do so, add a file in your application folder in "application\classes\kohana\request\client\internal.php" then set its content to:
<?php defined('SYSPATH') or die('No direct script access.');
class Kohana_Request_Client_Internal extends Request_Client {
/**
* #var array
*/
protected $_previous_environment;
/**
* Processes the request, executing the controller action that handles this
* request, determined by the [Route].
*
* 1. Before the controller action is called, the [Controller::before] method
* will be called.
* 2. Next the controller action will be called.
* 3. After the controller action is called, the [Controller::after] method
* will be called.
*
* By default, the output from the controller is captured and returned, and
* no headers are sent.
*
* $request->execute();
*
* #param Request $request
* #return Response
* #throws Kohana_Exception
* #uses [Kohana::$profiling]
* #uses [Profiler]
* #deprecated passing $params to controller methods deprecated since version 3.1
* will be removed in 3.2
*/
public function execute_request(Request $request)
{
// Create the class prefix
$prefix = 'controller_';
// Directory
$directory = $request->directory();
// Controller
$controller = $request->controller();
if ($directory)
{
// Add the directory name to the class prefix
$prefix .= str_replace(array('\\', '/'), '_', trim($directory, '/')).'_';
}
if (Kohana::$profiling)
{
// Set the benchmark name
$benchmark = '"'.$request->uri().'"';
if ($request !== Request::$initial AND Request::$current)
{
// Add the parent request uri
$benchmark .= ' « "'.Request::$current->uri().'"';
}
// Start benchmarking
$benchmark = Profiler::start('Requests', $benchmark);
}
// Store the currently active request
$previous = Request::$current;
// Change the current request to this request
Request::$current = $request;
// Is this the initial request
$initial_request = ($request === Request::$initial);
try
{
if ( ! class_exists($prefix.$controller))
{
throw new HTTP_Exception_404('The requested URL :uri was not found on this server.',
array(':uri' => $request->uri()));
}
// Load the controller using reflection
$class = new ReflectionClass($prefix.$controller);
if ($class->isAbstract())
{
throw new Kohana_Exception('Cannot create instances of abstract :controller',
array(':controller' => $prefix.$controller));
}
// Create a new instance of the controller
$controller = $class->newInstance($request, $request->response() ? $request->response() : $request->create_response());
$class->getMethod('before')->invoke($controller);
// Determine the action to use
/* ADDED */ if (strpos($request->action(), '_') !== false) throw new HTTP_Exception_404('The requested URL :uri was not found on this server.', array(':uri' => $request->uri()));
/* MODIFIED */ $action = str_replace('-', '_', $request->action()); /* ORIGINAL: $action = $request->action(); */
$params = $request->param();
// If the action doesn't exist, it's a 404
if ( ! $class->hasMethod('action_'.$action))
{
throw new HTTP_Exception_404('The requested URL :uri was not found on this server.',
array(':uri' => $request->uri()));
}
$method = $class->getMethod('action_'.$action);
$method->invoke($controller);
// Execute the "after action" method
$class->getMethod('after')->invoke($controller);
}
catch (Exception $e)
{
// Restore the previous request
if ($previous instanceof Request)
{
Request::$current = $previous;
}
if (isset($benchmark))
{
// Delete the benchmark, it is invalid
Profiler::delete($benchmark);
}
// Re-throw the exception
throw $e;
}
// Restore the previous request
Request::$current = $previous;
if (isset($benchmark))
{
// Stop the benchmark
Profiler::stop($benchmark);
}
// Return the response
return $request->response();
}
} // End Kohana_Request_Client_Internal
Then to add an action with hyphens, for example, "controller/my-action", create an action called "my_action()".
This method will also throw an error if the user tries to access "controller/my_action" (to avoid duplicate content).
I know some developers don't like this method but the advantage of it is that it doesn't rename the action, so if you check the current action it will be consistently called "my-action" everywhere. With the Route or lambda function method, the action will sometime be called "my_action", sometime "my-action" (since both methods rename the action).
I have build a CMS using Zend Framework (1.11). In the application I have two modules, one called 'cms' which contains all the CMS logic and an other 'web' which enables a user to build their own website around the CMS. This involves adding controllers/views/models etc all in that module.
The application allows you to serve multiple instances of the app with their own themes. These instances are identified by the hostname. During preDispatch(), a database lookup is done on the hostname. Based on the database field 'theme' the app then loads the required css files and calls Zend_Layout::setLayout() to change the layout file for that specific instance.
I want to extend this functionality to also allow the user to run different web modules based on the 'theme' db field. However, this is where I am stuck. As it is now, the web module serves the content for all the instances of the application.
I need the application to switch to a different web module based on the 'theme' database value (so indirectly the hostname). Any ideas?
Well, in my opinion,
You should write a front controller plugin for the web module, and do it so, that when you need another plugin, you can do so easily.
The front controller plugin should look something like this:
class My_Controller_Plugin_Web extends My_Controller_Plugin_Abstract implements My_Controller_Plugin_Interface
{
public function init()
{
// If user is not logged in - send him to login page
if(!Zend_Auth::getInstance()->hasIdentity()) {
// Do something
return false;
} else {
// You then take the domain name
$domainName = $this->_request->getParam( 'domainName', null );
// Retrieve the module name from the database
$moduleName = Module_fetcher::getModuleName( $domainName );
// And set the module name of the request
$this->_request->setModuleName( $moduleName );
if(!$this->_request->isDispatched()) {
// Good place to alter the route of the request further
// the way you want, if you want
$this->_request->setControllerName( $someController );
$this->_request->setActionName( $someAction );
$this->setLayout( $someLayout );
}
}
}
/**
* Set up layout
*/
public function setLayout( $layout )
{
$layout = Zend_Layout::getMvcInstance();
$layout->setLayout( $layout );
}
}
And the My_Controller_Plugin_Abstract, which is not an actual abstract and which your controller plugin extends,looks like this:
class My_Controller_Plugin_Abstract
{
protected $_request;
public function __construct($request)
{
$this->setRequest($request);
$this->init();
}
private function setRequest($request)
{
$this->_request = $request;
}
}
And in the end the front controller plugin itself, which decides which one of the specific front controller plugins you should execute.
require_once 'Zend/Controller/Plugin/Abstract.php';
require_once 'Zend/Locale.php';
require_once 'Zend/Translate.php';
class My_Controller_Plugin extends Zend_Controller_Plugin_Abstract
{
/**
* before dispatch set up module/controller/action
*
* #param Zend_Controller_Request_Abstract $request
*/
public function routeShutdown(Zend_Controller_Request_Abstract $request)
{
// Make sure you get something
if(is_null($this->_request->getModuleName())) $this->_request->setModuleName('web');
// You should use zend - to camelCase convertor when doing things like this
$zendFilter = new Zend_Filter_Word_SeparatorToCamelCase('-');
$pluginClass = 'My_Controller_Plugin_'
. $zendFilter->filter($this->_request->getModuleName());
// Check if it exists
if(!class_exists($pluginClass)) {
throw new Exception('The front controller plugin class "'
. $pluginClass. ' does not exist');
}
Check if it is written correctly
if(!in_array('My_Controller_Plugin_Interface', class_implements($pluginClass))) {
throw new Exception('The front controller plugin class "'
. $pluginClass.'" must implement My_Controller_Plugin_Interface');
}
// If all is well instantiate it , and you will call the construct of the
// quasi - abstract , which will then call the init method of your
// My_Plugin_Controller_Web :)
$specificController = new $pluginClass($this->_request);
}
}
If you have never done this, now is the time. :)
Also, to register your front controller plugin with the application, you should edit the frontController entry in your app configuration. I will give you a json example, i'm sure you can translate it to ini / xml / yaml if you need...
"frontController": {
"moduleDirectory": "APPLICATION_PATH/modules",
"defaultModule": "web",
"modules[]": "",
"layout": "layout",
"layoutPath": "APPLICATION_PATH/layouts/scripts",
// This is the part where you register it!
"plugins": {
"plugin": "My_Controller_Plugin"
}
This might be a tad confusing, feel free to ask for a more detailed explanation if you need it.
I need a method of inserting javascript which is controller/action specific into a layout. That javascript needs to go inside the <head> of the document, far from where normal content is placed. I already have an infrastructure in place which allows use of multiple views per page, and the Zend_Layout I already have takes full advantage of this:
<?php
$script = $this->layout()->script;
if (!is_null($script)) : ?>
<script type="text/javascript"> // <![CDATA[
<?php echo $script; ?>
// ]]>
</script>
<?php endif; ?>
However, I'd like the script output to be automatically selected, just like the normal view is automatically placed into $this->layout()->content of the layout by default. I understand this facility is provided by the ViewRenderer class. Basically, what I'd like to do is check for an instance of /VIEWPATH/scripts/CONTROLLER/ACTION.js.php, and render it as the script named output segment if it exists.
I could relatively simply create a Zend_Controller_Plugin which would automatically do that in post dispatch, but then controllers would have no way of setting values on the script's view. I also would need some way of replicating how the ViewRenderer controller plugin is inflecting the controller and action names.
Ideally I'd just somehow tack this on to the ViewRenderer helper, but it doesn't seem to support that kind of thing.
Am I going about this entirely wrong? Is there some mechanism for embedding page specific Javascript built into the framework? (I can't be the only person with this problem....)
Billy3
Extending my comment
Here is the doc for what are you looking for:
http://framework.zend.com/manual/1.12/en/zend.view.helpers.html#zend.view.helpers.initial.headscript
You can use captureStart() and create your scripts dynamically inside each related view.
With this approach you don't need to create *.js.php files.
I think there is no build in mechanism. Iam using an small controller plugin like this:
class My_Controller_Plugin_JavaScript extends Zend_Controller_Plugin_Abstract
{
/**
* preDispatch
* Check controller name, and include javaScript library
*
* #param Zend_Controller_Request_Abstract $request
* #return void
*/
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$layout = Zend_Layout::getMvcInstance();
$view = $layout->getView();
$controller = $request->getControllerName();
$jsFile = $controller . '-lib.js';
$jsPath = $view->baseUrl() .
'/js/' . $controller .
'/';
$sPath = PUBLIC_PATH . DIRECTORY_SEPARATOR . 'js' . DIRECTORY_SEPARATOR;
$sPath .= $controller . DIRECTORY_SEPARATOR . $jsFile;
if (file_exists($sPath)) { // load as last js (offset 100)
$view->headScript()->offsetSetFile(
100,
$jsPath . $jsFile
);
}
}
}
It adds an js file by controller name. Layout iam echoing it
<?= $this->headScript(); ?>
You could extend it to use action to. Iam sure there are better ways, but it works!
Zend Framework had view helpers to add javascript file(first snippet) + text javascript(second snippet)
you could add javascript files
<?php
$this->headScript()->appendFile($this->baseUrl("js/jquery-1.4.2.min"))
->appendFile($this->baseUrl("js/jquery-ui-1.8.2.custom.min"));
$this->headScript()->appendScript("js/dummy.js");
echo $this->headScript();
?>
then in some where else , you could add
<?php $this->headScript()->captureStart() ?>
// start jquery functions
var action = '<?php echo $this->baseUrl ?>';
$('foo_form').action = action;
// end jquery functions
<?php $this->headScript()->captureEnd() ?>
The following assumptions are made:
The script will be appended to the
stack. If you wish for it to replace
the stack or be added to the top, you
will need to pass 'SET' or 'PREPEND',
respectively, as the first argument to
captureStart(). The script MIME type
is assumed to be 'text/javascript'; if
you wish to specify a different type,
you will need to pass it as the second
argument to captureStart(). If you
wish to specify any additional
attributes for the tag, pass
them in an array as the third argument
to captureStart().to captureStart().
source : http://framework.zend.com/manual/en/zend.view.helpers.html