I am currently trying to create a small template engine for a project that I am working on, and I am using a system where I am replacing {$tag} with a preset tag. So say I put {username} in my template file, it will return a string which is the username. Now I want to go beyond just a simple string replacing a string. So using the same code I put
$tpl->replace('getID', '<?php echo "test"; ?>);
And it didn't work, so when I went to inspect element, I saw that it returned <!--? echo "test"; ?-->...
So now I am just trying to figure out why it returned commented code.
Here is my class file:
class template {
private $tags = [];
private $template;
public function getFile($file) {
if (file_exists($file)) {
$file = file_get_contents($file);
return $file;
} else {
return false;
}
}
public function __construct($templateFile) {
$this->template = $this->getFile($templateFile);
if (!$this->template) {
return "Error! Can't load the template file $templateFile";
}
}
public function set($tag, $value) {
$this->tags[$tag] = $value;
}
private function replaceTags() {
foreach ($this->tags as $tag => $value) {
$this->template = str_replace('{'.$tag.'}', $value, $this->template);
}
return true;
}
public function render() {
$this->replaceTags();
print($this->template);
}
}
And My index file is:
require_once 'system/class.template.php';
$tpl = new template('templates/default/main.php');
$tpl->set('username', 'Alexander');
$tpl->set('location', 'Toronto');
$tpl->set('day', 'Today');
$tpl->set('getID', '<?php echo "test"; ?>');
$tpl->render();
And my template file is:
<!DOCTYPE html>
<html>
<head></head>
<body>
{getID}
<div>
<span>User Name: {username}</span>
<span>Location: {location}</span>
<span>Day: {day}</span>
</div>
</body>
</html>
You're redeclaring PHP in a php file when there is no need to. i.e. you're trying to print <?php which is why it's messing up.
So, you can replace this:
$tpl->set('getID', '<?php echo "test"; ?>');
with this
$tpl->set('getID', 'test');
But, you obviously already know that, you're just trying to go further, the way to do this is by using php inside the set. So, as an idea, you could try this:
$tpl->set('getID', testfunction());
(You're calling testfunction here to define the 'getID' here btw)
So, now you want to write a little function to do something fancy, for the sake of this example:
function testfunction(){
$a = 'hello';
$b = 'world';
$c = $a . ' ' . $b;
return $c;
}
The above should then return hello world in place of {getID}
In reference to your comments - if you want to go one step further and start being more advanced with the return results, you can do the following:
function testfunction(){
$content = "";
foreach ($a as $b){
ob_start();
?>
<span><?php echo $b->something; ?></span>
Some link
<div>Some other html</div>
<?php
$content += ob_get_clean();
}
return $content
}
Related
I am parsing a JSON Object and using a foreach loop to output the data.
function do_api_call() {
$place_id = get_theme_mod('place_id_setting_field');
$url = "https://maps.googleapis.com/maps/api/place/details/json?placeid=" . $place_id . "&key=myapikey";
$data = file_get_contents($url);
$rev = json_decode($data, true);
$reviews = $rev["result"]["reviews"];
foreach($reviews as $review) {
$review_snippet = $review["text"];
echo $review_snippet . '<br>';
}
}
This works fine when I call it within an HTML element with:
<?php echo do_api_call() ?>
The short of it is that I get back 5 reviews from this loop and I need each review to go to their own html element in a different file called reviews.php, this file contains 5 unique bootstrap cards with a div that needs to hold a unique review so I need to output a unique review into each of these cards.
Like so:
<div> review 1 text </div>
<div> review 2 text </div>
<div> review 3 text </div>
<div> review 4 text </div>
<div> review 5 text </div>
You access a direct review with $rev["result"]["reviews"][0] (for the first) $rev["result"]["reviews"][1] (for the second) etc. So you can pass which review as a function arg.
However to cut down on re-loading an external source with every call of the function, you may want to do the data loader outside the function:
$place_id = get_theme_mod('place_id_setting_field');
$url = 'https://maps.googleapis.com/maps/api/place/details/json?placeid='.
$place_id .'&key=myapikey';
$data = file_get_contents($url);
$rev = json_decode($data,true);
$reviews = $rev['result']['reviews'];// this is now setup and ready to use
And then setup the anonymous function using the global (php 5.3+):
$get_review = function ($r) use (&$reviews) {
if (isset($reviews[$r])) {
return '<div>'. $reviews[$r]['text'] .'<div>';
}
return '';// no review to return
};
Then down in your html where you want to begin outputting them, you call it as such (note the $ is intentional with anonymous functions assigned to variables):
<body>
blah blah other stuff
<?php echo $get_review(0);?>
more blah
<?php echo $get_review(1);?>
</body>
Or if you need to loop on how many reviews you have:
<body>
<?php for($r=0;$r < count($reviews);$r++) { echo $get_review($r); } ?>
</body>
If you are afraid of using anonymous functions as I have above, you can adjust it to this instead:
function get_review ($r,&$reviews) {
if (isset($reviews[$r])) {
return '<div>'. $reviews[$r]['text'] .'<div>';
}
return '';// no review to return
}
// call it as thus
echo get_review(0,$reviews);
echo get_review(1,$reviews);
// etc
Class Method:
Of course you COULD also turn this into a small class object, where you first load_api, then get_review as methods of the class:
class Reviews {
public static $reviews;
public static function load_api() {
$place_id = get_theme_mod('place_id_setting_field');
$url = 'https://maps.googleapis.com/maps/api/place/details/json?placeid='.
$place_id .'&key=myapikey';
$data = file_get_contents($url);
$rev = json_decode($data,true);
self::$reviews = $rev['result']['reviews'];// this is now setup and ready to use
}
public static function get_review($r) {
if (isset(self::$reviews[$r])) {
return '<div>'. self::$reviews[$r]['text'] .'<div>';
}
return '';// no review to return
}
}
// to initialize
Reviews::load_api();
// to call and output
echo Reviews::get_review(0);
I want to create my own template for building my next web projects.
But my problem is that I am trying to create my own template system with my own function, also to learn more about coding on my on aswell.
I'm trying to improve my code to be me clean/smooth as I code.
But now I ran into this problem
a-function-file.php
<?php
$Website_info = array("SiteTitle"=>"CLiCK", "BaseUrl"=>"http://localhost/CLick/");
//css styles her
$website_styles = array(
array("src"=>"libs/css/bootstrap.min.css", "type"=>"text/css"),
array("src"=>"libs/themes/click.css", "type"=>"text/css")
);
//javascripts her
$website_scripts = array(
array("src"=>"libs/js/bootstrap.min.js", "type"=>"text/javascript")
);
$website_navigation_top_links = array(
array("link"=>"index.php","name"=>"Home")
);
function Click_styles()
{
global $website_styles;
$styleOutput = "";
foreach ($website_styles as $key => $CssStyle):
$styleOutput .= "<link href='".$CssStyle["src"]."' rel='stylesheet' type='".$CssStyle["type"]."'>\n";
endforeach;
return $styleOutput;
}
//my function to create html codes within head tags
function Click_header()
{
//Getting website info into function
global $Website_info;
global $website_styles;
$ImpotedStyles = Click_styles();
//creating the html (can maybe be created more clean later)
$Header_output = "<title>".$Website_info["SiteTitle"]."</title>\n";
$Header_output .= "<base href='".$Website_info["BaseUrl"]."' />\n";
$Header_output = $Header_output.$ImpotedStyles;
// return the complied output (as HTML)
return $Header_output;
}
?>
So far so good, because this works if I write
<?php echo Click_header();?>
But I want to use the function like this with, by passing it a function as an argument
<?php
//the function that doesnt work
function printHTML($ThisShouldBeAFunctionNotAVar, $Description="none") {
echo $ThisShouldBeAFunctionNotAVar
}
?>
<?php
//how I want to use the function
printHTML(Click_header(), "The website header");
//and maybe if I had a footer I could display the return of that function too
printHTML(Click_foter(), "a smart footer function");
?>
I hope you can help me with this or get a better understanding for maybe something smarter
I fount this solution on my own
<?php
function printHTML($CustomFunction,$Description="")
{
$function = ($CustomFunction;
echo $function();
}
?>
I am using a translator class i found online. It works phenomenally when I use it to directly echo the message. The problem occurs when I do conditional checks at the beginning of the page and I need to have the translated text in the variable to then send it to other places on the page to be displayed.
My code:
if ($condition_1){
$message = $translate->__('Text 1');
}
elseif ($condition_2){
$message = $translate->__('Text 2');
}
elseif ($condition_3){
$message = $translate->__('Text 3');
}
This code echos the text in the place where this condition is put, not used as the variable $message and then echos when I need it to. Can you help me to figure out how to use the text as a variable.
If I use the text with no translator class. I can easily use it as a variable.
This is the class i use:
class Translator {
private $language = 'sl';
private $lang = array();
public function __construct($language){
$this->language = $language;
}
private function findString($str) {
if (array_key_exists($str, $this->lang[$this->language])) {
echo $this->lang[$this->language][$str];
return;
}
echo $str;
}
private function splitStrings($str) {
return explode('=',trim($str));
}
public function __($str) {
if (!array_key_exists($this->language, $this->lang)) {
if (file_exists($this->language.'.txt')) {
$strings = array_map(array($this,'splitStrings'),file($this->language.'.txt'));
foreach ($strings as $k => $v) {
$this->lang[$this->language][$v[0]] = $v[1];
}
return $this->findString($str);
}
else {
echo $str;
}
}
else {
return $this->findString($str);
}
}
}
The translated text is in the a *.txt file, looking like this:
text 1=text 1 translated
text 2=text 2 translated
text 3=text 3 translated
The problem was in the "echo" in the class. I changed the "echo" with "return" and it works like a charm!
Here is the class:
functions.php
class buildPage {
public function Set($var,$val){
$this->set->$var = $val;
}
function Body(){
ob_start();
include('pages/'.$this->set->pageFile);
$page = ob_get_contents();
ob_end_clean();
return $page;
}
function Out(){
echo $this->Body();
}
}
So here is the main (index) page of the script.
index.php
include_once('include/functions.php');
$page = new buildPage();
$page->Set('pageTitle','Old Title');
$page->Set('pageFile','about.php');
$page->Out();
Now as you can see, it includes about.php file through class, actually inside the class.
And now, I want to access the same buildPage() class to change the page title.
about.php
<?php
$this->Set('pageTitle','New Title');
echo '<h1>About Us</h1>';
?>
But unfortunately, nothing happens.
Please be kind to take few minutes to give me some help!
OK. I've managed to fix the problem myself.
Changed function Body() and Out() as follows :
function Body(){
$pageFile = $this->Get('pageFile');
if(empty($pageFile)){
$pageFile = 'home.php';
}
$page_path = 'pages/'.$pageFile;
ob_start();
include($page_path);
if(!empty($page_set_arr) && is_array($page_set_arr)){
foreach($page_set_arr AS $k=>$v){
$this->Set($k,$v);
}
}
$page = ob_get_clean();
return $page;
}
function Out(){
$body = $this->Body();
echo $this->Header();
echo $body;
echo $this->Footer();
}
And then changed the file about.php as follows :
<?php
$page_set_arr = array(
'pageTitle' => 'About Us'
);
?>
<h1>About Us</h1>
Alright, I'm using a page creating class I found as below but when I want to use a php page -that again includes and uses a class file- for the content it either echoes on the top or the bottom of the page... I even tried to make the page a function() and call it at the $Content string but no use, again it echoed on the top of the page... How can i use a php page as a content in this class, or what should i change to use a php file?
Please keep in mind that I'm new to classes so feel free to assume some beginner mistakes.
<?php
class Page {
var $Title;
var $Keywords;
var $Content;
function Display( ) {
echo "<HTML>\n<HEAD>\n";
$this->DisplayTitle( );
$this->DisplayKeywords( );
echo "\n</HEAD>\n<BODY>\n";
echo $this->Content;
echo "\n</BODY>\n</HTML>\n";
}
function DisplayTitle( ) {
echo "<TITLE>" . $this->Title . "</TITLE>\n";
}
function DisplayKeywords( ) {
echo '<META NAME="keywords" CONTENT="' . $this->Keywords . '">';
}
function SetContent( $Data ) {
$this->Content = $Data;
}
}
?>
Usage:
<?php
include "page.class";
$Sample = new Page;
$Content = "<P>I want my php file's contents here.</P>";
$Sample->Title = "Using Classes in PHP";
$Sample->Keywords = "PHP, Classes";
$Sample->SetContent( $Content );
$Sample->Display( );
?>
What if I wanted to make the content something like $Content = " < ? echo 'test'; ? >"; I know this isn't valid but what i'm trying to do is something like that or something like $Content = " output of the whateversinhere.php ";. how should I object orient another page therefore getting its contents into a string here?
You should NOT echo anything inside your class, instead the class should have a method getMarkup(), which will return a string containing the whole markup. Then you can echo that string in your view.
Additional tipps:
variables and method names start with a small letter!
title and keywords should have getters and setters too
make your variables private (private $title, etc.)
let me clean this up for you, you will notice some changes:
class Page
{
private $title = 'No Title';
private $keywords = array();
private $content = '';
public function setTitle($title)
{
$this->title = (string)$title;
}
public function addKeywords($keywords)
{
$this->keywords = array_merge($this->keywords, (func_num_args() > 1) ? func_get_args() : (array)$keywords;
}
function setContent($content)
{
$this->content = $content;
}
function appendContent($content)
{
$this->content .= $content;
}
function prependContent($content)
{
$this->content = $content . $this->content;;
}
private function display()
{
/*
* Display output here
*/
echo $this->title;
echo implode(',',str_replace(',','',$this->title));
echo $this->contents;
}
}
pretty simple usage:
$Page = new Page;
$Page->setTitle("Hello World");
$page->addKeywords("keyword1","keyword2","keyword3","keyword4");
//Content
$this->setContent("World");
$this->prependContent("Hello");
$this->appendContent(".");
//Display
$this->display();
Just got to fill in the blanks, you will learn as time goes on that you should not be using html directly within your class, and that you would split the above into several class such as Head,Body,Footer,Doctype and have a page class that brings them all together.
Use Output Control Functions.
<?php
include "page.class";
$Sample = new Page;
ob_start();
include "foobar.php";//What you want to include.
$content = ob_get_contents();
ob_end_clean();
$Sample->Title = "Using Classes in PHP";
$Sample->Keywords = "PHP, Classes";
$Sample->SetContent($content);
$Sample->Display( );
?>