Render additional html at the beginning or end of action view - php

I have Zend Framework MVC application with module structure like that above:
/application
/layouts
/sripts
/layout.phtml
/modules
/default
/controllers
/IndexController.php
/OtherController.php
/views
/scripts
/index
/index.phtml
/second.phtml
/third.phtml
/fourth.phtml
/other
/index.phtml
/second.phtml
/third.phtml
/fourth.phtml
In my layout.phtml i have a line
<div id="main">
<?= $this->layout()->content ?>
</div>
I want to wrap rendered action views in every action of IndexController and OtherController, except fourth, with some code, like <div id='top'></div> at the beggining, and <div id='bottom'></div> at the end of rendered action view.
I don't want to do it manually in every action view *.phtml file. There are too many in real application, besides code looks messy with that solution.
How to do it?

In a layout file, you can echo a layout variable. This is usually where we put the html rendered by an action. You can append the rendering from several actions into a single layout variable, and they will be displayed in LIFO order. Here is how that variable is inserted into the layout file:
<?php echo $this->layout()->myLayoutVariable; ?>
You can also set up a placeholder variable inside your layout file:
<?php echo $this->placeholder('myPlaceholderVariable'); ?>
In one of your view files, you can then provide the html content for this placeholder variable:
<?php
$this->placeholder('myPlaceholderVariable')->append('<p>HTML GOES HERE</p>');
?>
If you don't set any value for the placeholder variable, nothing will be rendered in the layout file. But if you do set a value for that placeholder variable, it will be inserted into the html.

You could set a different layout only for IndexController and OtherController : in the init() method of each controller, you can add the following:
Zend_Layout::getMvcInstance()->setLayout('some other layout');

Try this:
$(document).ready(function(){
$("#main").before(//insert header html here);
$("#main").after(//insert footer html here);
});
I'm not sure what you mean by the fourth, but if you want to target a specific controller/action you could grab the window.location.href and make your function dependent on a specific URL you want to look for.
Hope that helps.

Related

Yii render view in another view

I have a rendered view in my application and when I export to PDF I'd like to use the data that I rendered before. Now I'm using another way to do it, I load all things again to export. How can I do it?
I've used this code but don't had success:
array('label'=>'Export pdf', 'url'=>array($this->renderPartial(
'ViewPDF2', array('sessao' => $GLOBALS['session'],'name_project'=>$model->name_project,'id_project'=>$model->i‌d_project,'dataStart'=>$model->data_start,'dataEnd'=>$model->data_end))))
I'm not sure how you've got that code in your view? You're passing that array as an argument to some function? All we can see right now is you're defining an array.
The general approach for rendering a view within in a view would be something like this (this is the container view file):
<?php //view code here ?>
<!-- some html in your view-->
<div id='included_view' >
<?php $this->renderPartial('viewName', array('argForView'=>$foo)); ?>
</div>
<!-- rest of view -->
Note that the use of $foo there means that you previously passed that variable to the container view (or that you defined $foo in a PHP code block before the renderPartial)
In url parameter you should use an URL Address which refer to an action which that action render the view that exporting to PDF.
The renderPartial method just render a view file in your self layout format.

Passing extra scripts from view to header

So I'm basically trying to pass the <link> and <script> tags into my original header file from a modules view file (which is displayed in the body of the page). How can I pass variables that include these references?
Currently I have just put extra <head></head> tags into my module's view, but it just feels messy and dodgy to do so, as that means the head tags are used up the top of the page, and also mid-way down.
Edit: Didn't realise that stack overflow edited out my tags that are crucial to this question! Sorry guys!
It sounds like you are really in need of a Template setup for CodeIgniter. Here are links to some of my favorites:
http://williamsconcepts.com/ci/codeigniter/libraries/template/reference.html
http://philsturgeon.co.uk/demos/codeigniter-template/user_guide/
And my personal favorite for simplicity:
http://maestric.com/doc/php/codeigniter_template
EDIT:
Per #Sneaksta's question, here is how I add css scripts to my template:
In my master template I have this code:
<?php if (!empty($cssFiles)): ?>
<?php foreach ($cssFiles as $styleSheet): ?>
<link rel="stylesheet" media="screen" href="<?= base_url(); ?>styles/<?= $styleSheet; ?>" />
<?php endforeach; ?>
<?php endif; ?>
Then in my controllers that might need to load different CSS files per function I do this:
$cssFiles = array('style1.css', 'style2.css', 'style3.css');
$this->template->set('cssFiles', $cssFiles);
Sneaksta,
I think I understand what you are asking about, but I am not 100% sure because you don't have any code examples posted.
So I will give you an example of how you can have a "telescoping" View that allows you to modularly load different style tags inside the head tags.
As Damien Pirsy mentioned, Views are buffered, which means that CI makes a special output buffer and will concatenate a series of View objects together, and then output the final buffer content as a finished web page.
My example below is built on this sort of chain of thinking:
End User
(calls) --> Page Controller, which then:
(calls & passes params) --> Base View
(calls multiple fragment views) --> Fragment View +
--> Fragment View +
--> Fragment View = Final Cumulative Page --> (sent back as output ) --> End User
First make the "base View", which we will call "base.php" for reference sake:
<!doctype html>
<html>
<head>
<!-- Base View -->
<?php
//This "if" + "isset()" statement is important,
// because if you forget to pass the variable in the controller
// CI will throw an error.
// Also important: the name of variable ($style) MUST match the
// the name of the associative element in the controller! (See
// remarks below on handling this in the controller)
if(isset($style))
{
//Loading views is like a telescoping effect:
//A view may load other views into itself recursively
$this->load->view($style);
}
else
{
//This echo statement will show a comment in
// source code if an error occurred during loading a view
echo "<!-- Style not found -->");
}
?>
</head>
<body>
<!-- Page Content Here -->
</body>
</html>
Next you create the Style View (note: the following code fragment would be in a separate file all by itself) which we will call "style1.php", and must located with your other views in order for CI to find it, e.g. inside the "application/views" folder. This lets you swap out an inline style block declared in the header by just changing which style view is loaded:
<style type="text/css">
/*Style 1:*/
/*Just do something simple and obvious, i.e. turn text red*/
body { color: red; }
</style>
Next you create the alternate Style View (note: the following code fragment would be in a separate file all by itself) which we will call "style2.php", and must located with your other views in order for CI to find it, e.g. inside the "application/views" folder. This lets you swap out an inline style block declared in the header by just changing which style view is loaded:
<style type="text/css">
/*Style 2:*/
/*Just do something simple and obvious, i.e. turn text blue*/
body { color: blue; }
</style>
Now inside of our controller "example.php" we tell base.php to load the style1.php file into its header. We do this by passing the file name as a parameter when we load the base.php view, by passing the file name as an element of an associative array, code igniter will parse that parameter array and create a variable with the same name as the associative element, and make that variable available to you inside the base.php view:
<?php
class Example extends CI_Controller
{
//Constructor
function __construct(){ parent::__construct(); }
//Base View request handler
function baseview()
{
//Note: Make an array, be certain to name the element
// the same as what will be expected inside base.php
$params = array("style" => "style1.php");
//Switching to load a different style is now easy
// just comment out the line above, and uncomment the line below:
//$params = array("style" => "style2.php");
//Pass the parameters array into the CI load view method:
$this->load->view("base.php", $params);
}
}
?>
The cumulative result should be the modular ability to switch the style tags inside the page header, by just specifying which "style view" to load (you could even build a model that retrieves which "style views" to load from a database table). Obviously this approach has certain processing overhead constraints inside of a web browser, as you are constructing actual inline HTML source code, rather than linking to a CSS file through a link tag. This means that the browser will not cache the css content for each page load, but will have to download it on each subsequent request.

Basic flow of pages in Zend Framework PHP

How does Zend link $this->layout()->content with scripts/index/index.phtml?
I think I'm failing to understand the basics of how the pages are supposed to stick together. I've looked at the quick start on the zend site but it's far too simplistic.
So as Tomáš Fejfar explained that's how the $this->layout()->content works. Yet what is interesting is that 'content' is not just a variable in the layout. In fact, 'content' is a key in a View placeholder called 'Zend_Layout'. For this reason, the following snippets are equivalent to echo $this->layout()->content in your layout.phtml:
$placeHolder = Zend_View_Helper_Placeholder_Registry::getRegistry()->getContainer('Zend_Layout');
echo $placeHolder['content'];
// or
echo $this->placeholder('Zend_Layout');
// or
echo $this->placeholder('Zend_Layout')->content;
This can be very useful. What I mean is that you can define some places in your layout.phtml that will be display values of your custom keys from 'Zend_Layout' placeholder. For instance, imagine that you would like to have a layout.phtml and you want to be able to modify text in your footer. You could do this by defining layout.phtml which will contain the following in the footer:
<div id="footer">
<?php echo $this->layout()->myFooterText; ?>
</div>
You could setup a default value for this footer in e.g. your Bootstrap.php. However, if you wanted you could modify this text in your actions as follows;
$this->view->placeholder('Zend_Layout')->myFooterText = 'Some text only for this action';
That's it what I wanted to add. Off course one could think of other scenerios, because $this->view->placeholder('Zend_Layout') is an instance of Zend_View_Helper_Placeholder_Container so you could do other things with Zend_Layout placeholder.
EDIT:
Key 'content' is a default name. You can change it to something else using setContentKey method of Zend_Layout, e.g.:
protected function _initSetNewLayoutContentKey() {
$layout = $this->bootstrap('layout')->getResource('layout');
// instead of 'content' use 'viewoutput'
$layout->setContentKey('viewoutput');
}
With this change, in your layout.phtml you would use echo $this->layout()->viewoutput; instead of echo $this->layout()->content;.
What's rendered in your view (the PHTML file) is saved into the content variable. That can be echoed in the layout template (another phtml file - preferably layout.phtml). And that'S the 'final product' :) (or maybe you want to specify you question more).
Layout is nothing more then a controller plugin which creates its own view after all dispatching has been done so it can take final response object and sets the content property of its view to response body .
So basically in your case buffer of index.phtml , gets stored in response object first then later layout takes this value and change it its own view buffer .

CakePHP how to addScript() from inside element?

I have a navigation menu inside a CakePHP element file (views/elements/nav_default.ctp).
The file is included inside another element that is the header (views/elements/header_default.ctp) which is then included in the layout file (views/layouts/default.ctp).
I am trying to tell Cake to load a js file (webroot/js/mega_drop.js) from within the nav element like so:
<?php
$this->addScript('mega_drop');
?>
It does not get included. I looked at the documentation for addScript which just says:
Adds content to the internal scripts
buffer. This buffer is made available
in the layout as $scripts_for_layout.
This method is helpful when creating
helpers that need to add javascript or
css directly to the layout. Keep in
mind that scripts added from the
layout, or elements in the layout will
not be added to $scripts_for_layout.
This method is most often used from
inside helpers, like the Javascript
and Html Helpers.
The key part:
Keep in mind that scripts added from the layout, or elements in the layout will not be added to $scripts_for_layout.
So how do I do it then?
I guess I could add a <script src="/js/mega_drop.js"></script> to the default.ctp layout. That doesn't feel right though as it would tightly tie the layout and the element together.
Whats the CakePHP best practice way to do this?
addScript() does not load a file; it adds actual code to the $scripts_for_layout variable. The idea being that the layout is a good, common place to load your JavaScript files and code. That way you can output all the code in one location - in the head block or at the end - either way it's together. So if you are in a situation where you've got JavaScript code in the view, rather than output it inline, you can pass it up to the layout.
The best way to load a script file is with the HTML Helper- echo $this->Html->script("script or array('of', 'scripts')"); With that in mind, you could $this->set('scripts', 'mega_drop'); in the element and then call the Html Helper with that $scripts variable from the layout.
The problem with that: it won't work if your nav_default.ctp is called from the layout. $this->set() works inside of a view (or an element called from a view) because the View is rendered before the Layout. If you are calling your element from the layout, then it is too late to be setting viewVars for use in the layout. The best thing to do is set() the scripts variable from the Controller and use a if(isset($scripts)) { echo $this->Html->script($scripts); } in the layout.
Correct and valid 1.3.x CakePHP 2.0 Dev is from example.ctp file:
$this->addScript($this->Javascript->link('tab_enabler'));
$this->addScript($this->Html->css('jquery.tabs'));
This is an example of how to properly include CSS and JS files from the view and adding in the variable $scripts_for_layout to not generate validation error with the W3C as it is not correct to add the link to a css file in <BODY></BODY>
try
$this->Html->script('mega_drop', $inline=false);
in your element without the echo.
The Second parameter says to add it to the $scripts_for_layout variable.
You should be able to do this in your element, so that the javascript is only included when the element is.

Zend organization question

So I had a question on general organization of code for the Zend framework with regard to the layout.
My layout is basically this:
(LAYOUT.PHTML)
<div id='header'>
<?= $this->Layout()->header ?>
</div>
<div id='main'>
<?= $this->Layout()->main ?>
</div>
<div id='footer'>
<?= $this->Layout()->footer ?>
</div>
and so on and so forth. Now, in order to keep my code in my header separate from the code of my main and the code of my footer, I've created a folder for my view that holds header.phtml, main.phtml, footer.phtml. I then use this code to assign the content of header.phtml into $this->layout()->header:
(INDEX.PHTML)
$this->Layout()->header = file_get_contents('index/header.phtml');
$this->Layout()->main = file_get_contents('index/main.phtml');
$this->Layout()->footer = file_get_contents('index/footer.phtml');
That was working great, but I've hit a point where I don't want main to be static HTML anymore. I would like to be able to insert some values with PHP. So in my Controller in indexAction, I want to be able to load from my database and put values into index/main.phtml. Is there a way to do this without restructuring my site?
If not is there a way to do it so that I can have:
The ability to put code into different sections of my layout, such as Layout()->header, Layout->footer.
Separate these pieces into different files, so that they're easy to find and organize, like my index/footer.phtml, index/main.phtml etc.
Not have to put that code into quotes unnecessarily to turn it into a string to pass it to Layout()->header etc.
Thank you guys so much for your help.
-Ethan
Here is an idea:
Assign layout()->header the filename instead of the contents.
Put your code in this file
In your layout file, include() or require() the layout->header().
Since your layout headers/footers are now parsed, you can use them just like a view.
The ->header in $this->layout()->header is response segment. You can render parts of response using $this->_helper->viewRenderer->setResponseSegment('header'); in an action.
If you use
$this->layout()->header = $this->render('index/header.phtml');
It will even use the view, therefore keeping all your variables defined when rendering the header.
I would suggest using something like
<?php echo ($header = $this->layout()->header)?
$header : $this->render('headerDefault.phtml'); ?>
in your layout file - it will render a default header from the layout folder if the view script doesn't override it.
Have you tried looking at view helpers. They are a way of structuring view logic into reusable and modular code. In this case you would use a view helper to generate each of your required segments. So your example view script would look like
$this->Layout()->header = $this->header();
$this->Layout()->main = $this->main();
$this->Layout()->footer = $this->footer();
The benefit of using view helpers over include and require statements is that all of the file handling and name resolution is handled by the framework. The manual has more information on how to set up the paths and usage examples etc.
helpers are good. Another option is like the above, putting filenames in header/footer - put the template names and use $this->render($this->layout()->header)), etc etc. This is just like the include/require above, but more consistent.

Categories