Better way to create html code from php variables? - php

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
}
?>

Related

How to set and output the buffer contents php

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);

How can I run PHP code in an specific html section

I have a section in my .html page where I want to run some PHP code, which reads data from a database and 'echoes' the table filled up with that information. I kinda did it object-oriented so I'm trying to keep that along the project.
I have this exact function or method in the Class (Class Servicio):
public static function listaServicios(){
$servicios = array();
$query = "";
$db = Database::getInstance();
$query = "SELECT descripcion, precio FROM servicio";
$resultado = $db->conn()->query($query);
foreach($resultado as $item){
$servicio = new Servicio();
$servicio->setDescripcion($item['descripcion']);
$servicio->setPrecio($item['precio']);
array_push($servicios,$servicio);
}
return $servicios;
}
As you can see, the function just returns an array filled up with as many objects as rows there is in the table. The PHP page would call this method, and then print the table with the selected data inside (there is no problem with this).
The thing is how can I print it in the specific section (div with id='datos') previously mentioned, which simply is:
<section class="principal">
<div id="datos">
</div>
</section>
I kinda of have an idea but I really don't know to implement it. Maybe using a document.ready function in jQuery calling the PHP code? I would really like to use this language even if it is a very tiny function in order to learn.
You can use jquery's load function to load content via a remote file into the div. But you will need to update your listaServicios to return html instead of the array.
jquery:
$(document).ready(function(){
$('#datos').load('phpfile.php');
});
phpfile.php
<?php
$serv = new Servicio();
echo $serv->listaServicios();
?>
Correct answer to your question depends on the interface of your future application you want to reach.
If you want some kind of SPA, then you should make AJAX-requests using JavaScript (jQuery or something else) and create a separate controller to response with data.
But I think in your particular case you can do everything on server side.
First of all you should add new method to your class, name f.e. render:
public static function render(){
$services = static::listaServicios();
include 'path/to/your/template.php';
}
Then inside your template.php write next:
<section class="principal">
<div id="datos">
<?php
foreach($services as $service) {
// echo your $service here as you wish
}
?>
</div>
</section>
So after calling render() PHP will render that part of template.
To access the properties of Servicio is better you construct your table in php:
<?php $servicios = Servicio::listaServicios(); ?>
<section class="principal">
<div id="datos">
<table style="width:100%">
<tr>
<th>Descripcion</th>
<th>Precio</th>
</tr>
<?php foreach ($servicios as $servicio): ?>
<tr>
<td><?= $servicio->getDescripcion() ?></td>
<td><?= $servicio->getPrecio() ?></td>
</tr>
<?php endforeach; ?>
</table>
</div>
</section>

Using html code in php function or no?

i would to know what is good practice for writing code to put all HTML code inside PHP function and in my front index.php file just call function to show code.
class.php:
public function test() {
$sql='select id,title from test ';
$nem=$this->db->prepare($sql);
$nem->execute();
$nem->bind_result($id,$title);
echo '<ul class="centreList">';
while($nem->fetch())
{
echo '<li>'.$id.'<a href="'.$title.'" >Download</a></li>';
}
echo '</ul>';
}
index.php:
<?php $connection->test(); ?>
This work fine, but I would like to know is this proper way or is not a good practice to use html code inside PHP functions?
It's ok to build HTML within PHP, but I would not echo to the screen directly from within the function. Instead, return the built HTML string.
$html = '<ul class="centreList">';
while($nem->fetch())
{
$html .= '<li>'.$id.'<a href="'.$title.'" >Download</a></li>';
}
$html .='</ul>';
return $html
The function should not be responsible for pushing content to the browser because it really limits what you can do with your code. What if you wanted to further process the HTML? What if you run into a condition later in the code and decided to abort? What if you wanted to set some response headers later? Some content would already be gone so none of these things would be possible without clever workarounds.
In general you want to separate your responsibilities: I would even break things down further:
one piece of code is in charge of retrieving info from the DB and returning
Another piece is in charge of building the HTML string
A third piece is in charge of displaying the HTML (probably your index.php)
New index.php
<?= $connection->test(); ?>
Do not use echo to print the html directly, wrap the html within while loop surrounded by php tags
public function test() {
$sql='select id,title from test ';
$nem=$this->db->prepare($sql);
$nem->execute();
$nem->bind_result($id,$title);
return $nem;
}
<ul class="centreList">
<?php $res = test()->fetch();
while( $res->fetch() ) { ?>
<li> <?php echo $id ?> Download </li>;
<?php } ?>
</ul>

Logic and markup, html and php

I am learning php. I see that people recommend to separate html and php or logic and markup. But in some specific occasions I am not sure how to do it. For readability and maintainability I try to put all the php in a separate file but now I have to download a title from a database and the only way I see is to put this with the rest of the html and with this html and php mixed. In this specific case, is there a more clean and organized way? is ok to put this peace of php in the "design" file? can or should I put this php code with the rest of the php?
<?php
include("../../externs/includes/connexio.php");
$result = mysqli_query($con, "SELECT * FROM myTable");
while ($row = mysqli_fetch_array($result)) {
$id = $row["id"];
$title = $row["title"];
$subtitle = $row["subtitle"];
?>
<div class="title" id="<?php echo $id; ?>"><?php echo $title; ?> </div>
<div class="subtitle"><?php echo $subtitle;?> </div>
<br>
<?php
}//end while items
?>
First of all I would recommend to read about MVC (Model-View-Controller), you can start at this Wikipedia article:
http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller
For a simple case as the one fro you question, your solution is, in my opinion, the best. Anything else would be to add unnecessary complexity.
That being said, I will try to use that simple case and offer one possible way to separate logic from presentation with the hope that some basic concepts will become clear from it.
my_controller.php
include("../../externs/includes/connexio.php");
$result = mysqli_query($con, "SELECT * FROM myTable");
$myList = array();
while ($row = mysqli_fetch_array($result))
{
$myList[] = $row;
}
// Now load the view.
include "my_view.php";
my_view.php
<?php foreach ($myList as $row ) : ?>
<div class="title" id="<?php echo $row['id']; ?>"><?php echo $row['title']; ?></div>
<div class="subtitle"><?php echo $row['subtitle'];?></div>
<br>
<?php endforeach; ?>
As you see, I just took your code and separated it in what would be business logic and presentation.
The idea here is that data to be presented should be generated outside the View. The View should know nothing about how the data was "generated".
In this example, the View only knows about the variable $myList containing the fields: id, title and subtitle. If you ever change databases or decide to fetch data from a file or even a Web service; you would not have to touch the View at all.
At the same time, the controller doesn't care about how the View shows the data. Regardless of the source: database, Web service, file, etc; it will always produce an array containing at least the fields expected by the View.
The next step to MVC would be to move data manipulation from controller to a model. I won't go there in detail, but this is how the controller would look like:
include "my_model.php";
$myList = fetchData();
include "my_view.php;
The fetchData() function inside the my_model.php file would basically do the same as my_controller.php above.
A very debatable and indeed debated issue is whether having any PHP code inside the View is a good practice. Some argue that other templating languages such as Smarty should be used. My opinion is that changing the syntax by adding another language doesn't change the inevitable fact that you need some logic in the View, otherwise you would be unable to introduce dynamism to your applications.
As you feel more comfortable reading PHP code, you will be able to look into the several frameworks around and see how they do it. One thing they all have in common is that they all have some logic in the presentation layer, whether it is PHP or something else.
Following are the best practices you can follow while mixing PHP with markup.
(Not a best practice)
1) if for example you have a logic on the top and you wish to generate markup, one not so good way you can do is:
<?php
$query = mysql_query("SELECT id,name FROM table");
while($row = mysql_fetch_assoc($query)){
$id = $row['id'];
$name = $row['name'];
?>
<div>ID:<?php echo $id;?></div>
<div>NAME:<?php echo $name;?></div>
<?php
}
?>
In the above code you have to keep track of the ending curly brace, if your application is complex it can create a problem especially in more then one level of iteration.
2) Good way to do is to make use of PHP tags such as
<?php if(count($array)):?>
<?php foreach($array as $result):?>
<div><?php echo result;?></div>
<?php endforeach;?>
<?php else:?>
<div>NO results found</div>
<?php endif;?>
Your code has no presentation issues but if it is a complex application then you need to follow best practices.
<?php
$array = array();
$query = mysql_query("SELECT id,name FROM table");
while($row = mysql_fetch_assoc($query)):
$array[] = $row;
endwhile;
?>
Outside of PHP tag check the count of $array, if there is count then generate markup.
<?php if(count($array)):?>
<?php foreach($array as $result):?>
<div>ID<?php echo result['id'];?></div>
<div>ID<?php echo result['name'];?></div>
<?php endforeach;?>
<?php else:?>
<div>NO results found</div>
<?php endif;?>
Using this kind of formatting you can achieve pleasing results. Try to separate or avoid mixing too much PHP with markup. If you want your presentation logic to be separated from business logic then I recommend you to use MVC model as it increases readability and maintainability.

How to retrieve all arguments used in a method on a page from another page?

I am not sure if I just have a bad structure for my code or this is a problem not normally found, but I don't even know how to start looking for a solution for my problem. I have my own simple translation script which is called like this:
<?php echo $Translate->text("Name"); ?>
It would return (and echo) a string with a keyword 'Name'. The problem is, for several reasons (name: misstranslations, report, development, translation in situ), I might want to retrieve all strings' keywords that are on a page. A simple page (example.com/campus/index.php) looks like this:
<h1> <?php echo $Translate->text(Campus); ?> </h1>
<p style="text-align:justify;">
<?php echo $Translate->text(126); ?>
</p>
<p style="text-align:justify;">
<?php echo $Translate->text(129); ?>
</p>
<a href="<?php $Link->create("campus/about"); ?>">
<h2 class="bodymenu"><?php echo $Translate->text(About); ?> </h2>
</a>
<p style="text-align:justify;">
<?php echo $Translate->text(146); ?>
</p>
<a href="<?php $Link->create("campus/learning_center"); ?>">
<h2 class="bodymenu"><?php echo $Translate->text(Learning_center); ?> </h2>
</a>
<p style="text-align:justify;">
<?php echo $Translate->text(147); ?>
</p>
<a href="<?php $Link->create("campus/residence"); ?>">
<h2 class="bodymenu"><?php echo $Translate->text(Residence); ?> </h2>
</a>
<p style="text-align:justify;">
<?php echo $Translate->text(128); ?>
</p>
And I would like to obtain in some situations: $Translations=array("Campus","126","129","About","146","Learning_center","147","Residence","128"); for further processing (EDIT) from another page.
In some cases there's much more php logic mixed in the page, in some others it's like this. There's much more logic code and classes that it's included automatically before and after every page. So, basically, I'd like to know (for this example but being able to extend it) how could I retrieve all the keywords.
I am thinking about 2 methods basically, but I don't think either is optimal. First would be to parse the php code as is using regex. Since I know the bits that I'm looking for, I thing it would be possible. Second one is that, depending on a SESSION variable, I render the html and parse it, so the echo $Translate->text(Campus); would return something like <span id="Translation">Campus</span> and then parse only the html and retrieve all the ids. Can you think about any other way to retrieve the ids before I get on this?.
PS, I DON'T want to hardcode all the id's in an array at the beginning or end of a page.
Do not reinvent the wheel by implementing a translating system. The gettext extension is there for painless, on the fly, language switching.
Basicly you write your site in a default language:
<?php echo _("Name"); ?>
Do not write <?php echo $Translate->text(147); ?>, noboby knows what that is. Write:
<?php echo _("Learning Centre"); ?>
For managing translations there is a choice of editors for Windows, Linux and Mac, POEdit for example.
Switching to a different language is easy:
public function SetDomain( $path )
{
define( 'DOMAIN', 'messages' );
bindtextdomain( DOMAIN, $path );
bind_textdomain_codeset( DOMAIN, "UTF-8" );
textdomain( DOMAIN );
}
note: if you set short_open_tags to on you can write:
<?= _("Name"); ?>
if i understood it correct,
modify your Translate class a little: add a variable which will collect all the strings you are using, like:
public $aStrings = array();
then, add in your function text($arg) something like:
$this->aStrings[] = $arg;
then you will have all the strings on page in your Translate->aStrings variable, then to print it use somethin like:
print_r($Translate->aStrings);
Subclass the Translate class with one that collects the values in an array, then use that in your page:
class MyTranslate extends Translate {
public $texts = array();
public function text($which) {
$this->texts[] = $which;
return parent::text($which);
}
}
$Translate=new MyTranslate($User->Language);
ob_start();
require('/path/to/other/page');
ob_end_clean();
var_dump($Translate->texts);
Create 2 file in english folder. ( You can specify it later but usually location for languages file in languages directory )
campus.about.php:
<?php
$lang["Name"] = "Name";
$lang["Address"] = "Address";
?>
*campus.learning_center.php*:
<?php
$lang["Learning"] = "Learning";
$lang["Residence"] = "Residence";
?>
Your Class Translate File ( root directory ):
class Translate {
public $_text= array(); // Change it into private properties coz you create
// text method for get the value, I set it public just for easy to debug it.
private $_language;
function __construct($language){ // Set Language
$this->_language= $language;
}
public function create($page){ // Get Language File
// $page= campus/about change into this campus.about
// Get language file Ex: english/campus.about.php
require($this->_language.'/'.$page.'.php');
$this->_text= array_merge($this->_text, $lang);
}
public function text($text){ // Display Keywords
echo $this->_text[$text];
}
}
$Translate= new Translate('english');
$Translate->create('campus.about');
print_r($Translate->_text);
$Translate->create('campus.learning_center');
print_r($Translate->_text);

Categories