Dependencies with templates

When I suggested a breather a little earlier, I was hoping that some might have taken that as a hint to calm things down a little. Please confine the discussion to the topic at hand, rather than each other.

3 Likes

I’m in strong support. I think I have openly declared myself a dunce and agreed to writing meaningless lines of PHP. The other guy swatted off my “bro” and arm of friendship. Let’s hope he comes up with the expert solution to the issue at hand like I begged him to in my last post so we can all learn and I can elevate from my dense ignorance.

Ok. Here is your partial solution. The basics on a templating system in PHP.

https://paulund.co.uk/php-template-system

This is also a good read about a great template system called twig. It is probably one of the best in the industry.

http://twig.sensiolabs.org/doc/api.html

And this is how the API looks for includes, which is what I think you are looking for.

http://twig.sensiolabs.org/doc/tags/include.htm

And here is the way twig also handles inheritance, which might be of interest to you too.

http://twig.sensiolabs.org/doc/templates.html#template-inheritance

Scott

A very basic and functional example of what I believe your trying to achieve could be:

function template($path, $global=null) {
  //Extract any global set values
  if (!empty($global)) {
     extract($global);
     }

  ob_start();
  include $path;
  $contents = ob_get_contents();
  ob_end_clean();

  return $contents;
  }

$global_array = array('pageOwner' => 1,
                      'info' => array()); //etc.

echo template('/path/to/template/file', $global_array); 

The key used in the global array decide the variable name it get when parsed in the function, i.e. ‘pageOwner’ become $pageOwner etc.

If you want to make your own solution, the code above can refactored into OOP with getter/setters etc. to fit what you need.

In the event you just need a basic template engine, Twig would not be a bad choice.

^^^ Thank you all.

Even though this may be against the site’s rules but I’d like to PM with anyone willing to help me solve some issue concerning the last section of my site(Mods please edit off this part if it’s against the site’s rules). If anyone is chanced or would volunteer, kindly click my profile and send a message. Thank you once again.

If it was against the rules to PM then they’d have turned off that option on the forum so that members couldn’t PM one another through the forum.

People don’t need your email address to PM you, they just need to click on your forum name and then select to message you.

Oh! Does site point have an inbuilt PM feature? How lovely. Thanks! I’ll edit my post now

Hello there. Sorry for my inability to reply earlier. Your function might be befitting for a single page application but in my case, I don’t have the luxury of simply buffering output of variables pre-known to me. I sometimes need unique user pages that would display their datas long after the process that brought about their page creation is done meaning my needs involve

  1. getting contents from a template, instead of swapping out placeholders.
  2. specifying an ID with which that page can grab associated data from the model for output.
  3. then write a fresh file with the string from step 2 above.

In fact I think my situation has spiralled out of the initial scope the thread was opened in. But, all the same, you can take a look at my next reply.

Hello there. Thank you very much for your reply. I eventually took a deeper look into templating and after being through a lot of links leading to both tutorials, opinions and helper frameworks regarding the topic, I’ve come to understand that the underlying principle for a valid or acceptable templating system is separating logic concerns from the view. I visited your twig links and discovered that the only advantage with using such frameworks is probably that it makes the view easier for non developers to read (as seen from here https://paulund.co.uk/php-template-system). Call me lazy, but the idea of learning a new syntax for simply templating is a huge turn off for me plus I don’t know what a non developer would be doing with my code in the first place.

Special reference to this http://code.tutsplus.com/tutorials/roll-your-own-templating-system-in-php--net-16596 and this https://www.smashingmagazine.com/2011/10/getting-started-with-php-templating/:
So we are on the same page, the idea on those links is for implementing templating on a one page scale (Please correct me if I’m wrong) much like how Angular.js works. However, in my case, like mentioned in my comment above, I need something a bit on a larger scale. Basically, I definitely need attachment of concerns since the variables on these pages are dynamic content being read from the server and are bound to change when a user updates his settings. I think this goes to say I can’t do without server code on that page (which is what I did on this thread before being condemned but let’s not go down that line).

That now brings me to http://platesphp.com/simple-example/ which seems to be what I’m looking for. I don’t seem to see much difference between what they’re doing on their site and what I’m doing in the snippet I posted in #28 except, I have database calls and theirs is wrapped in a nifty class that makes it look more refined (Again, please correct me and point out if I’m wrong. I’m neither arguing nor trying to prove I know all. I’m talking off my understanding so far).

So my new goal is to, in like manner, wrap my template engine (controller) and its associated components in a nifty class with the following steps outlined:

  1. The class is initialized with a primary key and its properties are populated (not from _POST but from my user classes’ construct) then sent to the model.
  2. Grab the template as a string and
    b. init the new page by running the template against the primary key like I did in #28.
    c. create the file using string from 2b

As I stated earlier, if I remove the PHP tags from the views, I can neither replace the placeholder I use (as was suggested in the links I posted earlier) nor get live content pertaining to a user. But if you feel there’s a workaround this, I’m open to your ideas.

I hope that made at least some sense.

Firstly, I appreciate you taking the advice offered in the end. The fact you did take time to try and learn makes me feel much more motivated to help you now. Thank you! :thumbsup:

The idea of a templating system is to give designers a way to design, without having to learn PHP. And yes, the idea is to abstract the “view” or display logic away from core logic of the application. If you don’t know about MVC architecture, please do read up on it.

The stuff the designers need to learn, the things you feel are not necessary to learn, is what is necessary for them to make their static HTML design become dynamic. If you aren’t building a system where other people are going to be working on the design and who aren’t developers themselves, then you don’t really need a templating system.

I like the fact that you are open to being wrong. Because, you are wrong. :smile: At least from what I am understanding from your post, it sounds like you are wrong. A PHP templating system can never be a “one page” system ala an Angular SPA (if that is what you meant). PHP is a server based language and Angular is a framework built in Javascript that works on the client only. Nothing in PHP works on the client, so the comparison is quite off on that basis alone.

[quote=“nmeri17, post:43, topic:220571”]
Basically, I definitely need attachment of concerns since the variables on these pages are dynamic content being read from the server and are bound to change when a user updates his settings. I think this goes to say I can’t do without server code on that page (which is what I did on this thread before being condemned but let’s not go down that line). [/quote]

Somehow I got lost here. PHP is a server-side language. It is “server code”. If you serve a page (with templates or not) through PHP, it is coming from the server no matter what! :smile:

Very good! I’d say it is a fairly good solution for what it seems you need to get done.

Well, they aren’t storing data in separate files for each request made to the server. I’d say that is a big difference. :smile:

Database calls and classes have no direct relation to each other, so the comparison isn’t quite correct and shouldn’t lead to any deduction that you might need a class now.

All this makes no sense to me, again. Sorry.

Can you try this please? Can you, without using any tech programming jargon, like using PHP or OOP features, explain what should be happening when a user calls a certain page. What data is it you need to have, use, display, store, etc. Explain the whole thing from the user’s perspective first, then try and explain what the server should be doing, but like I said, without any programming jargon. Maybe I can get an understanding of your problem and help you solve it starting from a higher level, instead of at the programming level.

Scott

2 Likes

Hey Molinari. I would be unable to reply fully for now. Yesterday I got hit by a terrible bout of the illness I have and don’t think I’ll do much without an operation. I’ll reply as soon as I can.

Get well soon!!!

Scott

1 Like

Thank you. I am back–at least for now. I’ll reply your posts shortly

I’ll be posting everything this time and try my best to be as simplistic and clear as possible with all concerned code and accompanying comments + explanations.
Now, in my confirm.php script, after confirming new user and updating the database that holds confirmed users, I create a unique page for this new user. This new page picks its format (the way the layout should look a.k.a front end and how data from back end should be arranged) from a prearranged template–which will soon follow-- and initializes it with a primary key. This primary key is what determines the database row we want its info to be displayed on this very page. So, for the relevant line in confirm.php, we have:

include "../classes/member_template_class.php";
$p = new Member_page($row['username'], "member_template_file.php");

$row['username'] is just username. Remember I’m fetching all data from the temporary sign up table into confirm table but that is pointless in the current discussion. Just saying, for clarity sake but think of it as $username: primary key.
We continue.
Then in “…/classes/member_template_class.php”, we have a class that initializes the user’s unique page as its primary function. Secondary function is to supply a helper function to fetch the data pertaining to the page owner. So in “…/classes/member_template_class.php”, I have the following:

class Member_page {
	/*
	* @Author: Al Nmeri
	* @Description: inits new page for user from template supplied
	* ======@constructor=======
	* @param: PAGEOWNER: username of page owner
	* @param: template_file: the file containing member template
	**/
	public function __construct ($PAGEOWNER, $template_file) {
		//fetch template

		$replace_arr = array('/* this loop should check where the array for where the new object matches, fetch that object then store it in the instance static variable */');
		$template_file = str_replace($replace_arr, '', file_get_contents($template_file));

		// init new dir for user
		$pagename = str_replace('_', '.', $PAGEOWNER);
					
		if (mkdir("../$pagename")) {
			file_put_contents("../$pagename/index.php", "<?php define('PAGEOWNER','$PAGEOWNER'); ?>\n");
			
			file_put_contents("../$pagename/index.php", $template_file, FILE_APPEND);
		}
	}

	/*
	* @param: pageOwner: username of current page owner
	* @return: An object with user info as properties
	* SIDE-NOTE: We can't use the Member::fetch_me() because that is dependent on current session name instead * of the PAGEOWNER constant
	**/
	public static function my_data ($pageOwner) {
		$a = $conn->prepare("SELECT * FROM user_info WHERE username=?");
		$a->bindParam(1, $uname);
		$uname = $pageOwner;
		$a->execute();
		return $a->fetch(PDO::FETCH_OBJ);
	}

}

If you’re following, now you know why I have the second parameter in the class I submitted in the confirm.php script so let’s visit the file member_template_file.php.

<?php
session_start();
include "../classes/my_conn.php";
include "../classes/member_template_class.php";

$sess = $_SESSION['username'];

// get connection
$conn = new My_conn($conn_details);
$conn = $conn->gc();

// get user info for page usage
$owner = Member_page::my_data(PAGEOWNER);

	// test whether this is user's first ever login
	if($sess == PAGEOWNER):

	$welcome = $conn->query("SELECT sign_up_date, last_login FROM users WHERE username=PAGEOWNER");
		while ($welcome->fetch(PDO::FETCH_ASSOC)):
			if ($welcome['sign_up_date'] == $welcome['last_login']):
				echo '<p style="background: black; color: #f0f0f0;">Your profile is ready. Click on preferences below to update your info so your friends can find you.</p>';
			endif;
		endwhile;
	endif;
?>

<!DOCTYPE html>
<html lang=en>
<head>
	<meta charset=utf-8>
	
	<link href='../register/member.css' rel='stylesheet' type='text/css'>
	<link href='https://fonts.googleapis.com/css?family=Lato' rel='stylesheet' type='text/css'>
	<link href='https://fonts.googleapis.com/css?family=Raleway' rel='stylesheet' type='text/css'>
	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
	<link type="x-image/icon" rel="icon" href="../../favicon.ico">
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>

	<title> <?php echo $owner->name; ?> </title>
</head>

<body>
	<?php include '../header.php'; ?>	
	<main>
	<aside>
	
		<h2> <?php echo $owner->name; ?> </h2>
		<div id=profilePic> <br>
			<img src='<?php echo $owner->profile_pic; ?>' alt="">
		</div>
	
	<div id=bio> <?php echo $owner->bio; ?> </div>
	
	<div id=misc>
		<ul>
		<?php if($sess == PAGEOWNER) {
		?>
			<li> <a href='../a/comments?u=<?php echo PAGEOWNER; ?>'><i class="fa fa-comments"></i> view my comments </a></li>
			<li> <a href='../a/mentions?u=<?php echo PAGEOWNER; ?>'> <span style='font-weight: bold;'>@ </span>my mentions </a> </li>
			<li> <a href='../preferences/'><i class="fa fa-cog"></i> account settings </a> </li>
		<?php
		}
		else {
		?>
			<li> <a href='../a/comments?u=<?php echo PAGEOWNER; ?>'><i class="fa fa-comments"></i> view <?php echo explode(' ', $owner->name)[0] . "'s"?> comments </a></li>
			<li> <a href='../a/published/?author=<?php echo PAGEOWNER; ?>'> <i class="fa fa-file-text"></i> <?php echo explode(' ', $owner->name)[0] . "'s"?> published posts </a> </li>
		<?php
		}
		?>
		</ul>
	</div>
	</aside>
	
		<?php
		if($sess == PAGEOWNER) {
		include $_SERVER['DOCUMENT_ROOT'] . '/register/make_new_post.php';
		}
		?>
	</main>
	
	<?php include '../footer.php'; ?>	
</body>
</html>

So the above script is my template file which as you can see, contains markup expecting dynamic content (and can’t be tied to ‘dumb’/html). Let me recap what the above code I have posted does (or at least is expected to do :sweat_smile: )

  1. When a new user is confirmed, call class Member_page and supply
    a. the primary key
    b. the template file
  2. The Member_page class should take the template file (the view if you like) and initialize it/create it with a primary key–in our case, username. Then append the template as a string to it.
    b. Fill in the placeholders in our view with info from our database (model if you like). This is done using the my_data static method.

So I have my “nifty class” which I mentioned earlier on, which I use to grab information pertaining to a particular user, then display it on that person’s page. I had explaining myself to a six year old in mind, not sure how good that went. But I hope I have not created a bigger disaster by all that long talk and code chunks. If so, just read the last part of the post where I outlined everything in two points.

Hello there. Good thing no one has replied yet. I observed the class I posted in the post directly above this was not robust enough to accommodate needs outside the specific use case of each user’s page. For instance, in the scenario I posted on post #10 of this thread. So I have re-modified the class and also would also rewrite that code in post #10 as a test case of the class. The templating class constructor itself now looks like this

public function __construct ($primary_key, $pagename, $template_file, $pagename_manipulate=NULL) {
		//fetch template

		$replace_arr = array('/* this loop should check where the array for where the new object matches, fetch that object then store it in the instance static variable */');
		$template_file = str_replace($replace_arr, '', file_get_contents($template_file));

		// any page name manipulations go here
		if (!is_null($pagename_manipulate)) {
			$pagename = $pagename_manipulate();
		}

		// init new dir for user
		$pagename = explode('/', $pagename);

		for ($i=0; $i<count($pagename)-1; $i++) { //-1 since we don't need the last part
			if (!is_dir($pagename[$i])) {
				mkdir("../". $pagename[$i]);
			}
		}
		//then repack the page name
		$pagename = implode('/', $pagename);
		file_put_contents("../$pagename/index.php", "<?php define('PAGEOWNER','$primary_key'); ?>\n");
		
		file_put_contents("../$pagename/index.php", $template_file, FILE_APPEND);
	}

So in my confirm.php, I now have


		// create user's unique page
		function manipulate($pagename) {
			return $pagename = str_replace('_', '.', $PAGEOWNER);
		}

		// the second argument can take a function or string as long as the function return a string
		$p = new Member_page($row['username'], $row['username'], "member_template_file.php", manipulate ($row['username']));

So, as a modification to post #10, on that CMS page, I have:

	include "../classes/member_template_class.php";

	$article_title = $_POST['article_title'];
	$article_author = $_POST['article_author'];
	$article_image = $_FILES['banner_image'];
	$article_body = $_POST['article_body'];
	$categories = $_POST['categories'];
	$date = date("l d F, Y");
	
	if (isset($article_title, $article_image, $article_body, $article_author)) {
		function manipulate ($article_title) {
			$temp_link = explode(" ", $article_title);
			$article_link = array();
			for ($i = 0; $i < count($article_title); $i++) {
				if (strlen($temp_link[$i])>3) {
					$article_link[] = $temp_link[$i];
				}
			}
			return $perm_link = $_SERVER['DOCUMENT_ROOT'] . "/" . date('Y/m') . "/" . implode("-", $article_link) . "/";
		}
	// upload banner image
	move_uploaded_file($article_image['tmp_name'], $perm_link . "banner.jpg");

	// update db with posts info
	$blog_post_vars = array($article_title, $article_author, $article_body, $perm_link, $categories, $date);
	$update = $conn->prepare("INSERT INTO blog_posts (article_title, article_author, article_body, article_url, categories, date) VALUES(?, ?, ?, ?, ?, ?)");
	$update->execute($blog_post_vars);

	// then create unique page for post
	$p = new Member_page($article_title, manipulate ($article_title), "../posts/blog_template.php");
	}

And in the “…/posts/blog_template.php”, I call it like I called its variables in my post above:

include "../classes/member_template_class.php";
// grab all post's details
@$post_title = PAGEOWNER; // just using this line for clarification purposes so we know who we dealing with
$curr_post = Member_page::my_data($post_title);
	<main>
		<h2> <?php echo $curr_post->article_title ?> </h2>
		<div id=banner-image> <img src=banner.jpg alt=""> </div>
		<div id=info> by<span id=author> <?php echo $curr_post->article_author; ?> </span> <span id=date> <?php echo $curr_post->date; ?> </span> </div>
//and so on and so forth
</main>

I hope I haven’t missed anything but in case I have or there’s something you don’t understand, just ask. I also hope I don’t give your Xdebug a torrid time :sweat_smile:

This is the reason why people shouldn’t write their own content management systems and frameworks. This is just a complete mess. Its not funny its sad… very sad and inconsiderate to any other developer who will need to maintain this disaster. I’ve been on the end of maintaining stuff like this and it makes me sick considering all the great alternatives with thorough documentation in the ecosystem.

1 Like

I think you and I should have gone past the stage of condemning my code without pointing out what the problem with it is. If I have gone through the pain of sharing my (albeit horrible) code, the least you can do is pinpoint what you feel I’m doing wrong and not resort to such blanket statements. If I were you, and I could clearly see loopholes in @nmeri17’s templating system but I’m too lazy to point it out, I’d at least advice him to add a Big caveat at the top of all his scripts apologizing profusely to the inheriting developer and begging him for forgiveness about the horrors the bugs and code are about to unleash on him. That is at least better than pointing out nothing IMHO.

I have other obligations besides teaching someone intermediate to advanced design patterns for template systems. Besides I don’t write my own template systems… I use the wonderful ones available in the ecosystem and part of the frameworks which I use. For example, in Laravel with blade one would use a view composer to accomplish the same task with much less code and convoluted logic.

There is potential value in “re-inventing the wheel”.

As long as it is for the learning experience, and there are no time constraints.

One thing for sure, “tinkering” will help with understanding other’s work, and give an appreciation of the work done by other Teams of developers.

I’m assuming that nmeri17 's intent at this time is not to write “the next great thing” but to learn.

To that end, looking at some of oddz 's suggested alternatives and studying how they’re put together might help.

4 Likes

I am afraid you are attacking the problem from the wrong angle.

The way the problem you describe is normally solved is by a template engine. Then after the view has been created you can do a granular cache on the content the page consists of, or cache the whole page.

On new visits from the same user (or users if its not unique content tied to a user), instead or creating the page again, the cache is served.

If you want to create your own system doing this, then this is what you need to do.

  1. Create a template class.
  2. Create a cache class.
  3. For each page, take all the code that is now inside the templates, database queries, calling classes etc. and move them into their own page, class etc. The idea is to separate them from the templating code. Then you will pass along all of the required result as values to the templates as they are processed. If any of the parsed templates should be cached, this is also where you do this.
  4. Create barebone html template files (i.e. no database queries, calling classes etc. inside them).

Doing this will separate the concerns of the code, making it easier to maintain and also easier to read.