I want to create different view scripts for each modules in my application. My structure look like that:
-- application
-- modules
-- default
-- views
-- default
-- scripts
-- fluid
--scripts
I set default script path in Zend Controller Plugin, which preDispatch() is executed with the request:
$view->setScriptPath(sprintf('%s/modules/%s/views/%s/scripts', APPLICATION_PATH, $module, $views));
Everything works great until i call action from view:
$this->action('activity-stream', 'index', 'observation');
Application throws an exception with message:
script 'index/activity-stream.phtml' not found in path (C:/wamp/www/erp/application/modules/observation/views\scripts/;C:\wamp\www\erp\application/modules/user/views/fluid/scripts/)
Looks like, when calling module with View Action Helper, script path is not set properly. Any idea how to achieve that?
Problem not solved, but i dit what i want in a different way. Each controller within any module of my application inherits my custom action controller that inherits Zend_Controller_Action. Inside that custom controller i have something like this:
public function init() {
parent::init();
$module = $this->_request->getModuleName();
$config = new Zend_Config_Ini(APPLICATION_PATH . "/configs/modules.ini", $module);
$layout = isset($config->layout) ? $config->layout : 'default';
$views = isset($config->views) ? $config->views : 'default';
$this->view->layout()->setLayout($layout);
$this->view->setScriptPath(sprintf('%s/modules/%s/views/%s/scripts', APPLICATION_PATH, $module, $views));
}
It's not exactly what i wanted, but solves my problem.
Related
I have setup in my MVC site a Session variable to carry ids to be used on any subsequent pages.
In my controller, var_dumping the session shows its there with the correct values but when I pass said values to the view and trying to echo them there, it comes up blank.
Any pointers as to whats going on to cause them to not appear.
Please note, the view is a partial view, not the main one.
Bootstrap session related code:
protected function _initSession(){
Zend_Session::start();
$SessAuto2Auto = new Zend_Session_Namespace('SessAuto2Auto');
$SessAuto2Auto->cityIds = "1,2,3"; // Hard code values for testing purposes
$SessAuto2Auto->IndustryIds = "3,4"; // Hard code values for testing purposes
}
Controller related code : ProductController.php
public function indexAction()
{
// .. Unrelated code removed for brevity
$response = $this->getResponse();
$response->insert('sidebar', $this->view->render('sidebar.phtml'));
// This code is dumping the values correctly
echo('<pre>');
var_dump($this->sessionAuto2Auto);
echo('</pre>');
// .. Unrelated code removed for brevity
$this->view->filterCity = $this->sessionAuto2Auto['cityIds'];
$this->view->filterIndustryIds = $this->sessionAuto2Auto['IndustryIds'];
}
View partial : sidebar.phtml
<?php
// This code does NOT show the value, comes up blank
echo($this->filterCity);
?>
If you are calling sidebar.phtml using the partial helper, partials have their own variable scope, they can only access variables which are passed in to them. You need to either include your session variables in your partial helper call:
echo $this->partial('sidebar.phtml', array(
'filterCity' => $this->filterCity,
'filterIndustryIds' => $this->filterIndustryIds
)
or use render instead (which uses the same scope as the other view scripts):
<?=$this->render('sidebar.phtml')?>
at the moment I´m working with a custom Silverstripe Controller with a Director rule:
---
Name: myroutes
After: framework/routes#coreroutes
---
Director:
rules:
'category/$Action/$Slug': 'Category_Controller'
The Controller looks like that:
class Category_Controller extends Page_Controller {
public function show($arguments) {
echo "Slug: " . $arguments->param("Slug");
}
}
When I open in the browser the URL http://mysite.com/category/show/mobile
then the output look fine like this: "Slug: mobile".
I just wonder how I can use a Category.ss Template from the Folder "themes/templates/Layout" to render the Output. Then of course the container html (with header/footer) from Page.ss should be included as well. Just as usual when you have a custom Page Controller/Class and a corresponding Template in the Layout Folder.
I just tried this:
public function show($arguments) {
echo $this->renderWith("Category");
}
It uses Category.ss for rendering the output, but there is no container html...
Thx for any help.
Regards,
Florian
you can also pass an array to renderWith(), and it will try through the array until it finds a template.
so lets say $this->renderWith(array('Category', 'Page'));
it will first look for a template called Category.ss, but will not find it (in the templates folder, not layout folder), it will then find Page.ss and use it.
Now it hits $Layout inside Page.ss and it checks the array again inside the Layout folder, it will now find the Category.ss, which is exactly what you where looking for if I got the question right.
if you do not want to do return $this->renderWith(); you can also just do return $this; and silverstripe will get the action you called and the class hierarchy of $this and use that as array for renderWith()
So if your classes are Category_Controller > Page_Controller > ContentController the array will look like this:
array(
'Category_show', // because your action is show
'Category',
'Page_show',
'Page',
'ContentController_show',
'ContentController',
)
(I am not a 100% sure if it also includes Page_show and ContentController_show.)
How can I overwrite the default view object in zend framework so I could have the custom one?
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap {
function _initViewHelpers() {
$this->bootstrap('view');
$view = $this->getResource('view');
$view->doctype('HTML4_STRICT');
$view->setHelperPath(APPLICATION_PATH . '/helpers', '');
$view->headMeta()->appendHttpEquiv('Content-type', 'text/html;charset=utf-8')
->appendName('description', 'Zend Framework');
$view->headTitle()->setSeparator(' - ');
$view->headTitle('Zend Custom View');
$view->setScriptPath(APPLICATION_PATH . '/themes/admin');
return $view;
}
}
The default view contains default script path for module. I want one path for all modules, to enable template system. The setScriptPath method should overwrite the default path generated by the view object, but it doesn't.
array(2) { [0]=> string(66) "C:/xampp/htdocs/NEOBBS_v6/application/modules/admin/views\scripts/" [1]=> string(51) "C:\xampp\htdocs\NEOBBS_v6\application/themes/admin/" }
it has two scriptPaths. Can this be done by overwriting the default view object?
What ArneRie posted is correct, however the ViewRenderer checks to see whether the standard script path is set and adds it if not. Since the paths are checked LIFO, what's happening is that the ViewRenderer is adding the standard path after your one and then always using that one.
What worked for me was to set both the standard path and my custom path at the same time, with the custom one being last, something like:
$view->setScriptPath(array(
APPLICATION_PATH . '/views/scripts/', // or whatever the standard path is
APPLICATION_PATH . '/themes/admin'
));
there may be a better solution for this though.
Try to add:
$viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer();
$viewRenderer->setView($view);
Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
I need same 2 lines in all my controllers, each controller have its own init logic, but these two lines are common for all of them.
public function init()
{
$fm =$this->_helper->getHelper('FlashMessenger');
$this->view->messages = $fm->getMessages();
}
How can I avoid repeat code ?
Update:
Ok, the FlashMessenger was only an example, let's say I need write a log line in every action except for 'someAction' # 'someController'. So the new common lines should be.
$this->logger = new Zend_Log();
$writer = new Zend_Log_Writer_Stream(APPLICATION_PATH.'/../logs/log.txt');
$this->logger->addWriter($writer);
$this->logger->log('Some Message',Zend_Log::DEBUG);
The question is, where should I place these lines in order to avoid repeat them in all init() of each controller.
These lines should be placed at bootstrap?. If so: How can skip log lines for 'someAction'.
Or should I implement a 'BaseController' and make all my controller extend from it. If so: How can I Autoload it? (Fatal error: Class 'BaseController' not found) .
Just subclass the controller:
class Application_ControllerAction extends Zend_Controller_Action {
public function init()
{
$fm =$this->_helper->getHelper('FlashMessenger');
$this->view->messages = $fm->getMessages();
}
}
class IndexController extends Application_ControllerAction {
}
You may also achieve the same writing Controller Plugin.
Edit:
Front controller plugins are executed on each request, just like the Controllers and have the same hook methods:
routeStartup(): prior to routing the request
routeShutdown(): after routing the request
dispatchLoopStartup(): prior to entering the dispatch loop
preDispatch(): prior to dispatching an individual action
postDispatch(): after dispatching an individual action
dispatchLoopShutdown(): after completing the dispatch loop
I addition, you may check controller params to execute the code only on selected requests:
if ('admin' == $this->getRequest()->getModuleName()
&& 'update' == $this->getRequest()->getActionName() ) …
You can access your flash messages through (you dont need to send anything from your controller to your view, it's all automated)
$fm = new Zend_Controller_Action_Helper_FlashMessenger();
Zend_Debug::dump($fm->getMessages());
in you view, i would also recommand that you encapsulate this code in a view helper like it is shown on this site http://grummfy.be/blog/191
In your bootstrap:
protected function _initMyActionHelpers() {
$fm = new My_Controller_Action_Helper_FlashMessenger();
Zend_Controller_Action_HelperBroker::addHelper($fm);;
}
How can I avoid repeat code ?
Write your own custom controller, implement that in init method of that controller, and then extend all controllers in your app from your custom controller.
But approach with separate view helper as #Jeff mentioned (look at link) is often taken as a better solution.
In your controller do only:
$this->_helper->flashMessanger('My message');
and view helper will do the rest.
It's not the reason for creating new custom controller. Just add this line to all you init() methods.
$this->view->messages = $this->_helper->getHelper('FlashMessenger')->getMessages();
I have an action which is rendering some content via a layout.
I actually want to send this output in an email. What is the best way to achieve this in the Zend Framework?
I know I need to use the Zend_Mail component to send the email, but I'm unclear about how to attach the output of my action to Zend_Mail.
I've done some reading on the ContextSwitch action helper, and I think that might be appropriate, but I'm still not convinced.
I'm still new to Zend Framework. I'm used to using techniques like output buffering to capture output, which I don't think is the correct way to do this in Zend.
From your controller:
// do this if you're not using the default layout
$this->_helper->layout()->disableLayout();
$this->view->data = $items;
$htmlString = $this->view->render('foo/bar.phtml');
If you're doing this from a class that's not an instance of Zend_Controller_Action, you may have to create an instance of a Zend_view first, to do this:
$view = new Zend_view();
// you have to explicitly define the path to the template you're using
$view->setScriptPath(array($pathToTemplate));
$view->data = $data;
$htmlString = $view->render('foo/bar.phtml');
public static function sendMail($data = array(), $template = ''){
$html = new Zend_View();
$html->setScriptPath(APPLICATION_PATH . '/modules/default/views');
// assign valeues
if(count($data['Assigni'])){
foreach($data['Assigni'] as $assign){
$html->assign($assign['key'], $assign['value']);
}
}
// create mail object
$mail = new Zend_Mail('utf-8');
// render view //'scripts/newsletter/emailtemplate.phtml'
$bodyText = $html->render($template);
$mail->addTo($data['To']);
$mail->setSubject($data['Subject']);
$mail->setFrom($data['From'], $data['FromName']);
$mail->setBodyHtml($bodyText);
$mail->send();
}
when you dispatch the action, you can catch the event in postDispatch() method of plugin, that you can dynamically add to the stack from desired action. In that you recieve the contents of response by
//in action
//...some php code
Zend_Controller_Front::getInstance()->registerPlugin(new My_Plugin());
//in plugin
$htmlCode = $this->_response->getBody();
I can't give you a super-detailed answer, but if you want the full output (including the layout), I think you want to write your email function as an Action helper, and insert it at the PostDispatch hook of the Zend_Controller_Action->dispatch() loop.
See http://nethands.de/download/zenddispatch_en.pdf for the full Zend Framework Dispatch Process Overview.
If you don't need the layout included in your email content, then you could do this at many points, including by the use of a context switch, as you mentioned.