I'm new to zend and i'm struggling with some items.
I tried using Helpers, but then realized it doesn't do what I wanted it to do...
either i'm using $this->placeHolder... wrong or it doesn't do what I want it to do
I want to do the following:
I want to create a custom class that basically has 2 methods addScriptContent, and getScriptContent...
addScriptContent adds what ever is passed into it to a string that is global for the page.
getScriptContent will just output whatever data that has been added using addScriptContent
i.e.
this->addScriptContent('var x="foo";')
....some html
this->addScriptContent('var y="feee";')
....some html
echo this->getScriptContent() //writes out var x="foo"; var y="fee";
The placeholder helper does exactly what you are after:
<?php $this->placeholder('scriptContent')->set('var x="foo";') ?>
....some html
<?php $this->placeholder('scriptContent')->append('var y="feee";') ?>
....some html
<?php echo $this->placeholder('scriptContent')?>
the key methods on the helper are set, append and prepend; which overwrite, add to, and add to the start of the content respectively.
If you really want to write your own helper for this, this wouldn't be too difficult. Take a look at the headTitle or headScript helpers for an example, but would be something along the lines of:
class My_View_Helper_ScriptContent extends Zend_View_Helper_Placeholder_Container_Standalone
{
public function scriptContent($script)
{
$this->append($script);
}
}
usage would then be:
<?php $this->scriptContent('var x="foo";') ?
....some html
<?php $this->scriptContent('var y="feeee";') ?>
....some html
<?php echo $this->scriptContent() ?>
Related
I'am really very new to PHP.
I have this code:
<?php cms_loop('500');?>
<div class="item">
<p class="contents"></p>
</div>
<?php cms_loop_end('500');?>
I want to output everything between cms_loop and cms_loop_end functions.
I do it this way:
function cms_loop($id){
ob_start();
echo ob_get_contents();
}
and
function cms_loop_end(){
ob_end_flush();
}
But that's not working. Any help appreciated
Below you can find the working code:
<?php
/**
* Start buffering
* #param $id
*/
function cms_loop($id){
ob_start();
}
/**
* Output everything buffered
*/
function cms_loop_end(){
ob_end_flush();
}
?>
<?php cms_loop('500');?>
<div class="item">
<p class="contents">Hello from buffered content</p>
</div>
<?php cms_loop_end('500');?>
Please note that I removed the echo ob_get_contents(); from your cms_loop() function.
Demo: https://onecompiler.com/php/3wuscawt7
(There is an option to run without account)
I'm assuming you're trying to achieve some kind of template rendering as you apparently trying to render some piece of HTML for later use. For that to happen, PHP needs to be aware of that piece. In your example, though, both PHP and HTML co-exist side by side without either side having any knowledge about the other. Your HTML isn't part of PHP's realm yet.
Let's change that.
The piece of HTML you've given is often called a partial, i.e. something that's meant to be part of something bigger. Like a sidebar being a conceptual part of an index.html file, but not a physical one unless included:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h1>Welcome!</h1>
<!-- Partial -->
<?php include_once('sidebar.html') ?>
</body>
</html>
So let's take a similar approach and factor out the HTML into its own file first:
<div class="item">
<p class="contents"></p>
</div>
partial.html.php
Now we need to find a way to transfer this piece of HTML into the realm of PHP. The simplest approach would be to read it and assign it to a variable:
$html = file_get_contents('partial.html.php');
Let's get back to your function for a second, because now you could do:
function cms_loop($html){
echo $html;
}
I have taken $id off of the list of the function's parameters, mostly because of the following reasons:
you don't read nor write to a database yet
if you did, this would be the wrong place
you don't use any variables in your template, so there's no need to pass any in
Though let's ponder the last one a bit. Wouldn't it be nice if we could pass data into our template, for example to dynamically change the classes we have assigned to both HTML elements?
It would most definitely be nice, and it's possible, too - what we need for that is just a little bit of output buffering. But first, let's change our template to meet our new needs:
<div class="<?php echo $class_outer ?>">
<p class="<?php echo $class_inner ?>"></p>
</div>
So we'll have to define both values up front. But we might end up with a lot more template variables once we get the hang of it, so let's best use an array as a container to store our current and any future values:
$data = [
'class_outer' => 'item',
'class_inner' => 'contents',
];
Next, we'll need some function to render our template with the values we just defined, so it'll need two parameters: The path to the template file and our data array. Also, we want it to return our rendered template. That said, it'll probably look like this:
function render(string $template_path, array $data): string {
if (!is_file($template_path)) {
return false; // Or some better error handling
}
// Let's have some sugar in our templates: Import all indexes
// of our data array as variables into the current scope so
// they can easily be accessed by the template we're about to render.
//
// In other words, we now have two new variables:
//
// - $class_outer (extracted from $data['class_outer'])
// - $class_inner (extracted from $data['class_inner'])
//
// Cf. https://www.php.net/manual/en/function.extract.php
extract($data);
// Start output buffering
ob_start();
// Render template
include $template_path; // By including it, it has access to all
// variables defined in the current scope, i.e.
// inside this very function - like the variables
// we just extracted from $data
$rendered = ob_get_contents(); // Assign all output to a variable, so we can return it.
// End output buffering
ob_end_clean();
return $rendered;
}
Now, we can call that like:
$rendered = render('templates/partial.html.php', $data);
My website consists of many products that are each contained in a div with the id content block. The link, image, background, description and price are all loaded from a mySQL table. My original plan was to save the below html code as a string and loop over the rows in the mySQL table filling the string I created with php/mySQL values.
I was wondering if I am going about this the right way, or is there a better way to create html code from php variables?
<div id="contentblock" style="background-image:url(images/$BACKGROUND.png);">
<div id="picture"><img src="$IMAGELINK"/></div>
<div id="description"><p>$DESCRIPTION</p></div>
<div id="price"><p class=price>$PRICE</p></div>
</div>
Firstly PHP is a template engine - in my experience template engines that layer ontop of PHP are only good for the simplest of cases and are easily outgrown.
Secondly the original code is as good as any method. At risk of stating the obvious to make it better abstract it into a function;
function output_block($BACKGROUND, $LINK, $IMAGELINK, $DESCRIPTION, $PRICE)
{
echo "<div id='contentblock' style='background-image:url(images/$BACKGROUND.png);'>
<div id='picture'><a href='$LINK'><img src='$IMAGELINK'/></a></div>
<div id='description'><p>$DESCRIPTION</p></div>
<div id='price'><p class=price>$PRICE</p></div>
</div>";
}
If you want to make it much better then adopt a framework, an entire admin config page is show below. All of the HTML glue is provided by the framework - the following code is real, but really to illustrate how a framework can provide a lot of the grunge work for you.
In the example below if I want to edit a single entity I'd change the TableViewEdit into a FormView and provide an instance of an entity rather than an iterable list.
$entity = new CbfConfig(); // Database entity
$page = new AdminWebPage("Site Configuration"); // Page for output
/*
* build the view
*/
$vil = new ViewItemList();
$col = &$vil->add(new ViewItem("description","Description"));
$col->get_output_transform()->allow_edit(false); // this field cannot be editted
$col = &$vil->add(new ViewItem("value","Value"));
$v1 = new TableViewEdit($entity, $vil,"admin_values"); // present as standard editable table
/*
* output the page
*/
$page->begin();
$iterable_list = CbfConfig::site_begin();
$page->add_body($v1->get_output($iterable_list,'admin_config'));
$page->end();
Id just have all my html code outside of php tags, then whereever I need a variable from php do as follows
<div id="description"><p><?php echo $DESCRIPTION; ?></p></div>
You can loop around non php code too. For example
<?php
for($i = 0; $i < 10; $i++) {
?>
<div id="description"><p><?php echo $i; ?></p></div>
<?php
} //end for loop
?>
Obviously this is just an example.
well if im without a template engine for somereason i usually do something like:
function partial($file, $args = array()) {
extract($args);
ob_start();
include($file);
return ob_get_clean();
}
Really, there are 3 ways of doing this. Use whichever is easiest for you in the context that you are using it in.
<?php
while(($row=mysql_fetch_assoc($result))!==false)
{
echo "<div>{$row['fieldName']}</div>";
}
?>
<?php
while(($row=mysql_fetch_assoc($result))!==false)
{
echo '<div>'.$row['fieldName'].'</div>';
}
?>
<?php
while(($row=mysql_fetch_assoc($result))!==false)
{
?>
<div><?= $row['fieldName']; ?></div>
<?php
}
?>
I have some HTML code portions that repeat a lot through pages. I put this html code inside a function so that it is easy to maintain. It works perfectly. I, however feel this may not be very good practice.
function drawTable($item){
?>
HTML CODE HERE
<?php
}
I also run into the problem that when I want to return data using json the following won't work as it will be NULL:
$response['table'] = drawTable($item);
return json_encode($response);
What's the correct way to handle HTML code that repeats a lot??
Thanks
You may want to look into using templates instead of using ugly heredoc's or HTML-embedded-within-PHP-functions, which are just plain unmaintainable and are not IDE-friendly.
What is the best way to include a php file as a template?
If you have a repeating segment, simply load the template multiple times using a loop.
Although templates help with D.R.Y., the primary focus is to separate presentation from logic. Embedding HTML in PHP functions doesn't do that. Not to mention you don't have to escape any sort of quotes or break the indentation/formatting.
Example syntax when using templates:
$data = array('title' => 'My Page', 'text' => 'My Paragraph');
$Template = new Template();
$Template->render('/path/to/file.php', $data);
Your template page could be something like this:
<h1><?php echo $title; ?></h1>
<p><?php echo $text; ?></p>
function drawTable( $item ) { return '<p>something</p>'; }
function yourOtherFunction() {
$response['table'] = drawTable($item);
return json_encode($response);
}
Use this function definition
function drawTable($item){
return 'HTML CODE HERE';
}
Called with
print drawTable($item);
Which will also work for your json return value.
I use codeigniter. I have footer_view.php, header_view.php and other view php files for pages like aboutus, contactus, etc... for example for about us page, I create model for db actions, than I create a controller to get db variables and send variable to about us view as:
$this->load->view('aboutus/',$data);
Everything is fine until this point, but when I need to get data from db at footer, how will I use in the CodeIgniter Way?
If I create a footer_model, I cannot make view('footer/') because it is actually a part if page, not a page itself :/
You can use $this->load->vars($data);
This will make all data available to all views, footer_view.php, header_view.php and any other views.
$data['your_info'] = $this->user_model->get_info();
$data['your_latest_info'] = $this->user_model->get_latest_info();
$data['your_settings_info'] = $this->user_model->get_settings_info();
$this->load->vars($data);
$this->load->view('your_view');
You view can and will access the data like so:
Your "primary" view
<?php
// your_view.php
// this can access data
$this->load->view('header_view');
<?php foreach ($your_info as $r):?>
<?php echo $r->first_name;?>
<?php echo $r->last_name;?>
<?php endforeach;?>
$this->load->view('footer_view');
?>
Your header_view
<?php
// header_view.php
<?php echo $your_latest_info->site_name;?>
?>
Your footer_view
<?php
// footer_view.php
<?php foreach ($your_setting_info as $setting):?>
<?php echo $setting->pages;?>
<?php endforeach;?>
?>
No need for any template library...
I wrote a blog post about this http://joshhighland.com/blog/2008/11/09/how-i-do-layouts-and-views-in-codeigniter/
basically, you want to load all the data that all your views are going to need in the controller. I use an array of data elements, then pass that to the layout view. My blog post explains more about this, and shows more detail. Here is a sample of my controller.
$this->load->model('search');
$lastest_albums = $this->search->last_n_albumsAdded(10);
$popular_songs = $this->search->popular_n_songs(10);
$featuredAlbums = $this->search->getFeaturedAlbums();
$body_data['featured'] = $featuredAlbums;
$body_data['newest'] = $lastest_albums;
$body_data['popular'] = $popular_songs;
$layout_data['content_body'] = $this->load->view(’home/homePage’, $body_data, true);
$this->load->view('layouts/main', $layout_data);
I'm developing a application with CakePHP, and I have two layouts: one for the home page, and another for the rest of the application. Except for some coding on the header, they're almost exactly the same. Is there something I can do to keep DRY, without using if () statements all over the layout?
I'd suggest using a ton of elements. This way, you can still keep all of the code in one place. For example, if this is your home page layout (boilerplate excluded):
<body>
<?php echo $this->renderElement('pageHeader'); ?>
<?php echo $this->renderElement('frontPageNotification'); ?>
<?php echo $this->renderElement('navAndOtherStuff'); ?>
...
</body>
And this is your interior layout (where you want to display everything except for the frontPageNotification stuff:
<body>
<?php echo $this->renderElement('pageHeader'); ?>
<?php echo $this->renderElement('navAndOtherStuff'); ?>
...
</body>
Now, if they're almost exactly alike, I would probably just use a single layout and have a few if statements within the layout itself to determine what's to be displayed. Also, you can choose which elements get displayed by looking at the $this->params array to figure out which controller and action is behind the page being loaded. Like:
<body>
<?php echo $this->renderElement('pageHeader'); ?>
<?php if($this->params['controller'] == 'pages' && $this->params['action'] == 'index') { echo $this->renderElement('frontPageNotification'); } ?>
<?php echo $this->renderElement('navAndOtherStuff'); ?>
...
</body>
Which is, admittedly, rather ugly. Just trying to present all the options I could think of :)
Good luck
Define an interface to a layout type. Every place you have an "if layout main" or "if layout other" define an interface function
interface IMyLayout
{
function DrawArea1(...)
...
}
class CMyMainLayout implements IMyLayout
{
function DrawArea1()
{
//... draw area 1 for main
}
...
}
class CMyOtherLayout implements IMyLayout
{
function DrawArea1()
{
//... draw area 1 for other
}
}
Then you just select one or the other by newing the correct object
if ($main)
{
$layout = new CMyMainLayout;
}
else
{
$layout = new CMyOtherLayout;
}
$layout->DrawArea1();