Vanilla 1 is no longer supported or maintained. If you need a copy, you can get it here.
HackerOne users: Testing against this community violates our program's Terms of Service and will result in your bounty being denied.
Garden and Vanilla Idea 1: Views clean and lean
x00
MVP
I have enjoyed messing around with vanilla so far. It is a great little app and not half bad for development. I am looking forward to Garden and Vanilla 2 which should be easier. I have been following its development keenly, and interested to know how various things are going to be done.
One of the areas the vanilla 1 is not so good on is the themes/templates. They are just messy, loads of code, and echoes all over the place, or appending variables, etc. In accordance to good MCV practice views should have minimal amount of code. You should avoid putting too much logic in views as this is not the place for it. However sometimes it is unavoidable, but it should always be done thoughtfully if it is necessary.
PHP is considered an "embedded" language. However it can be both an eye sore and practically difficult to mange XHTML with a bunch of PHP throughout.
One of my ideas is a simpler notation, that is unobtrusive an intuitive. I have just come up with this quick and dirty example. I have been using a more basic version of this for mini aps and extensions for a while now. Here is a Template class:
The notation is parses (as well as php) is influenced by embedded ruby and ruby string parsing, but it is not even as complicated.
here is an example of a template:
You can create a new Template like so:
which gives you:
It doesn't worry too much about types. It is not a real language or even a domain specific, micro or macro language. It only has two pseudo types. Things you can output directly like strings and numbers, and things that you can iterate or access its properties or index like arrays. It just uses the simple dot notation. It matches this to whatever you put in you params array.
If it can't find what you want, or doesn't know what to do, at the moment it just hops over. It could equally rub itself out, or raise an error.
Currently it only has one method 'each', which has a corresponding control word 'end'. This can be used can be used to iterate or if the object is not the iteration type it just creates a block so you can tidy things up a bit.
The simple notation does not itself have logic, However if were to rub out block when properties that don't exist then it could work like if true situation.
Sometimes you want php so you can insert that true. By default it will evaluate php if it detects php in the template file, or to can force it to or not.
I don't think I will be making it a great deal more complicated than that otherwise you need more syntax rules which is unnecessary. It is very literal, so if there is a space in your property it will look for the property including the space. There are no escape rules besides \#{...}, but with good conventions this shouldn’t be a problem.
Two more methods/control words that could be useful are 'fire', which will fire an event in an event handler that is passed tot he constructor, and also 'fragment', which could use a caching hander for fragment caching. Anther thing that could be useful is 'yield'. Instead of having say header and footer, etc you just have the main container page, view and partial views.
Anyway that is just a suggestion that may be useful in the framework and would also be available for extensions to use as well.
One of the areas the vanilla 1 is not so good on is the themes/templates. They are just messy, loads of code, and echoes all over the place, or appending variables, etc. In accordance to good MCV practice views should have minimal amount of code. You should avoid putting too much logic in views as this is not the place for it. However sometimes it is unavoidable, but it should always be done thoughtfully if it is necessary.
PHP is considered an "embedded" language. However it can be both an eye sore and practically difficult to mange XHTML with a bunch of PHP throughout.
One of my ideas is a simpler notation, that is unobtrusive an intuitive. I have just come up with this quick and dirty example. I have been using a more basic version of this for mini aps and extensions for a while now. Here is a Template class:
class Template {
var $evalMode;
//the chained together parts exploded
function properties($string){
$a=0;$b=0;$seperator='.';$exploded = array();
while(($a=strpos($string,$seperator,$a))!==false){
$exploded[]=substr($string,$b,$a-$b);
$a+=1;
$b=$a;
}
$exploded[]=substr($string,$b);
return $exploded;
}
//get the required parameter
function getParameter($txt,$params){
$properties = $this->properties($txt);
foreach($properties As $property){
$type = gettype($params);
if(in_array($type,array('array','object'))){
if($type == 'object'){
$params = get_object_vars($params);
}
if(array_key_exists($property,$params)){
$params = $params[$property];
}else{
return false;
}
}else{
return false;
}
}
return $params;
}
//get the file contents
//php eval modes: 0=don't evaluate, 1=force evaluate, 2=auto evaluate as required
function getTemplFile($templFile,$params){
extract($params);
$templ = file_get_contents($templFile);
if($this->evalMode==1 || ($this->evalMode==2 && strpos($templ,'<?php')!==false)){
ob_start();
eval('?>'.$templ);
return ob_get_clean();
}
return $templ;
}
//Simple parser for a simple notation
//one method 'each' with a corresponding control word 'end'
//for iteration and static blocks
function parse($templ,$params){
$a=0;
while(($a=strpos($templ,"#{",$a))!==false && ($b=strpos($templ,"}",$a))!==false && ($a==0 || substr($templ,$a-1,1)!='\\')){
$p = substr($templ,$a+2,$b-$a-2);
if(($d=strrpos($p,'.'))!==false){
$t ='';
$f=strlen($p)-1;
if(substr($p,$d+1,5)=='each|' && substr($p,$f)=='|' && ($g=strpos($templ,'#{end}',$b))!==false){
if(!($c=$this->getParameter(substr($templ,$a+2,$d),$params))){$a=$g+6;continue;}
$blocklabel = substr($p,$d+6,$f-$d-6);
$block = substr($templ,$b+1,$g-$b-1);
$type = gettype($c);
if(!in_array($type,array('array','object'))){
$c = array($c);
}
foreach($c As $v){
$params[$blocklabel] = $v;
$t .= $this->parse($block,$params);
unset($params[$blocklabel]);
}
}
if($t){
$d=substr($templ,0,$a).$t;
$e=substr($templ,$g+6);
$a=strlen($d);
$templ=$d.$e;
continue;
}
}
if(!($c=$this->getParameter(substr($templ,$a+2,$b-$a-2),$params))){$a=$b;continue;}
$type = gettype($c);
if(in_array($type,array('array','object','resource'))){$a=$b;continue;}
$d=substr($templ,0,$a).$c;
$e=substr($templ,$b+1);
$a=strlen($d);
$templ=$d.$e;
}
return $templ;
}
//load a template
function Template($templFile,$params=array(),$evalMode=2){
$this->evalMode=$evalMode;
$templ = $this->getTemplFile($templFile,$params);
echo $this->parse($templ,$params);
}
}
The notation is parses (as well as php) is influenced by embedded ruby and ruby string parsing, but it is not even as complicated.
here is an example of a template:
<?php
if(true){
echo "<p>hi</p>";
}
?>
<p>#{test.one}</p>
<input type="text" value="#{test.0}"/>
#{test.each|x|}
<p>This is a value: #{x}</p>
#{end}
#{test.one.each|y|}
<p>This is just a static block: #{y} #{test.one}</p>
#{end}
<p>#{other.bla.special}</p>
#{other.bla.each|item|}
<p>#{item}</p>
#{end}
You can create a new Template like so:
$params = array('test'=> array('one'=>'one','two'=>'two','three'=>'three','four'),
'other'=>array('bla'=>array('special'=>'whooo!','duckling')));
new Template('test.php',$params);
which gives you:
hi
one
This is a value: one
This is a value: two
This is a value: three
This is a value: four
This is just just a static block: one one
whooo!
whooo!
duckling
It doesn't worry too much about types. It is not a real language or even a domain specific, micro or macro language. It only has two pseudo types. Things you can output directly like strings and numbers, and things that you can iterate or access its properties or index like arrays. It just uses the simple dot notation. It matches this to whatever you put in you params array.
If it can't find what you want, or doesn't know what to do, at the moment it just hops over. It could equally rub itself out, or raise an error.
Currently it only has one method 'each', which has a corresponding control word 'end'. This can be used can be used to iterate or if the object is not the iteration type it just creates a block so you can tidy things up a bit.
The simple notation does not itself have logic, However if were to rub out block when properties that don't exist then it could work like if true situation.
Sometimes you want php so you can insert that true. By default it will evaluate php if it detects php in the template file, or to can force it to or not.
I don't think I will be making it a great deal more complicated than that otherwise you need more syntax rules which is unnecessary. It is very literal, so if there is a space in your property it will look for the property including the space. There are no escape rules besides \#{...}, but with good conventions this shouldn’t be a problem.
Two more methods/control words that could be useful are 'fire', which will fire an event in an event handler that is passed tot he constructor, and also 'fragment', which could use a caching hander for fragment caching. Anther thing that could be useful is 'yield'. Instead of having say header and footer, etc you just have the main container page, view and partial views.
Anyway that is just a suggestion that may be useful in the framework and would also be available for extensions to use as well.
grep is your friend.
0
Comments
Ok am ok with not having proper ORM as that is not strictly necessary so long and the query builder works nicely.
I have mixed feeling about JQuery being included in as standard. I do think we need certain functionality to be standardised for conflict reasons if nothing else like domready, etc. But I am not sure I want JQuery all the time, especially as I managed to write concise scripts (I haven’t bothered to minify yet) without a framework so far. As amazing as JQuery is, sometimes it simply isn’t needed. I mean JavaScript is not that bad, or else you wouldn’t have frameworks like JQuery. Even though you can load individual modules, those modules are nowhere near as small as you want them if you are only doing something very simple. JavaScript frameworks are not created to on save space. In order to get that benefit you would have to write something very big. JQuery, etc are created for people who hate JavaScript. Also it is myth that frameworks help you with quirks and compatibility completely. Framework teams have to make decisions with the direction the framework is going. If you don’t know about that it may be the opposite of what you want. While they do come up with innovative methods that can be efficient some times, they are also may include extra functionality, which you don’t need and that can negate the benefit.
grep is your friend.
grep is your friend.
foreach ()
can do faster, natively, and with more functionality. What I can agree with though is that programming is art, and when it comes to art, I am a minimalist107 lines of code isn't for foreach. If you are talking about 'each' that is basically dealt with in 17 line of code.
The length is actually down to speed I could do make shorter say using regular expressions call back, but that would be slower
grep is your friend.
function insert_params($txt,$params){ $a=0; while(($a=strpos($txt,"#{",$a))!==false && ($b=strpos($txt,"}",$a))!==false && ($a==0 || substr($txt,$a-1,1)!='\\')){ if(!($c=$params[substr($txt,$a+2,$b-$a-2)])){$a=$b;continue;} $d=substr($txt,0,$a).$c; $e=substr($txt,$b+1); $a=strlen($d); $txt=$d.$e; } return $txt; }
The previous example just give you a bit more flexibility that is all.
grep is your friend.
class Template { var $evalMode; var $templStr; var $yeild; //the chained together parts exploded function properties($string){ $a=0;$b=0;$seperator='.';$exploded = array(); while(($a=strpos($string,$seperator,$a))!==false){ $exploded[]=substr($string,$b,$a-$b); $a+=1; $b=$a; } $exploded[]=substr($string,$b); return $exploded; } //get the required parameter function getParameter($txt,$params){ $properties = $this->properties($txt); foreach($properties As $property){ $type = gettype($params); if(in_array($type,array('array','object'))){ if($type == 'object'){ $params = get_object_vars($params); } if(array_key_exists($property,$params)){ $params = $params[$property]; }else{ return false; } }else{ return false; } } return $params; } //get the file contents //php eval modes: 0=don't evaluate, 1=force evaluate, 2=auto evaluate as required function getTemplFile($templFile,$params){ extract($params); $templ = file_get_contents($templFile); if($this->evalMode==1 || ($this->evalMode==2 && strpos($templ,'<?php')!==false)){ ob_start(); eval('?>'.$templ); $templ = ob_get_clean(); } $this->insertOnYeild($this->parse($templ,$params)); } //insert into parent on yeild function insertOnYeild($txt){ if(!$this->templStr){ $this->templStr=$txt; return; } if($this->yeild){ $a=0; $l=strlen($this->yeild); while(($a=strpos($this->templStr,'#{yeild|'.$this->yeild.'|}',$a))!==false && ($a==0 || substr($this->templStr,$a-1,1)!='\\')){ $d=substr($this->templStr,0,$a).$txt; $e=substr($this->templStr,$a+10+$l); $a=strlen($d); $this->templStr=$d.$e; } }else{ $this->templStr=$this->templStr.$txt; } } //Simple parser for a simple notation //one method 'each' with a corresponding control word 'end' //for iteration and static blocks function parse($templ,$params){ $a=0; while(($a=strpos($templ,"#{",$a))!==false && ($b=strpos($templ,"}",$a))!==false && ($a==0 || substr($templ,$a-1,1)!='\\')){ $p = substr($templ,$a+2,$b-$a-2); $f=strlen($p)-1; if(($d=strrpos($p,'.'))!==false){ $t =''; $h = substr($p,$d+6,$f-$d-6); if(substr($p,$d+1,5)=='each|' && substr($p,$f)=='|' && ($g=strpos($templ,'#{end|'.$h.'|}',$b))!==false){ if(!($c=$this->getParameter(substr($templ,$a+2,$d),$params))){$a=$g+6;continue;} $blocklabel = $h; $block = substr($templ,$b+1,$g-$b-1); $type = gettype($c); if(!in_array($type,array('array','object'))){ $c = array($c); } foreach($c As $v){ $params[$blocklabel] = $v; $t .= $this->parse($block,$params); unset($params[$blocklabel]); } } if($t){ $d=substr($templ,0,$a).$t; $e=substr($templ,$g+8+strlen($h)); $a=strlen($d); $templ=$d.$e; continue; } } if(!($c=$this->getParameter(substr($templ,$a+2,$b-$a-2),$params))){$a=$b;continue;} $type = gettype($c); if(in_array($type,array('array','object','resource'))){$a=$b;continue;} $d=substr($templ,0,$a).$c; $e=substr($templ,$b+1); $a=strlen($d); $templ=$d.$e; } return $templ; } //print Template function tPrint(){ echo $this->templStr; } //load a template function tAdd($templFile,$params=array(),$yeild=null,$evalMode=2){ $params = is_array($params) ? $params:array(); $this->evalMode=$evalMode; $this->yeild=$yeild; $this->getTemplFile($templFile,$params); return $this; } //constructor function Template(){ $this->evalMode=null; $this->templStr=null; $this->yeild=null; } }
Say you have the following template files:
<?php echo "hi"; ?> #{yeild|bla|} #{yeild|bla|} #{yeild|bla|} #{test.each|x|} This is a value: #{x} #{end|x|} #{test.one.each|y|} This is just a static block: #{y} #{test.one} #{end|y|} Nested blocks: #{other.each|item|} #{item.each|z|} #{z} #{end|z|} #{end|item|}
#{test.one} #{yeild|sillybar|}
Some other content!
You do this:
$params = array('test'=> array('one'=>'one','two'=>'two','three'=>'three','four'), 'other'=>array('bla'=>array('special'=>'whooo!','duckling'))); $tmpl = new Template; $tmpl->tAdd('test.php',$params)->tAdd('test1.php',$params,'bla')->tAdd('test2.php',null,'sillybar')->tPrint();
...and you will get this:
one
one
one
This is a value: one
This is a value: two
This is a value: three
This is a value: four
This is just a static block: one one
Nested blocks:
whooo!
duckling
All this is this just a very simple, lean, template engine example. You could also use more comprehensive template engine like ->smarty-<
Regardless of whether you use one or not clean views are a must.
grep is your friend.
grep is your friend.
grep is your friend.
If you have
code here <- invalid <tr> code here <- possibly still invalid and still not universally supported </td>
grep is your friend.
So don't. Just because you can make a DB call inside of a view doesn't mean that you must. Shove all of your data into a bunch of nested arrays and restrict your templates to only use echo, if, select and foreach statements. Any template system is just another way of forcing you to do this. But it's like training wheels on a bicycle, what's the point of using it for the rest of your life when it's pretty easy to just learn how use the real thing correctly?
I don't get why you're so down on XML, it offers some major advantages. You're worried about overhead? With XML+XSLT you don't have to process the template on the server side at all. Just send the XML and XSL files to the browser and let the client handle it. And because the goal of XSLT is the ability to arbitrarily translate any kind of XML into any other kind of XML, it also gives you a solution for RSS or SOAP or any other XML-based trick you want to pull.
I scratch my head when you say, "W3C didn't some how anticipate how template would be used, or didn't care enough." I would say that Smarty and HAML and most other template engines are the ones that don't anticipate enough. They all seem to focus narrowly on the task of putting data into HTML. But really, how much does that help? It seems to me that most of the work in coding a web theme is making sure that your HTML and CSS work correctly across a million different browsers, not getting at the data.
Most of the mess is to do with trying to work around the mark-up design issues. It is pretty obvious people would want to put data in their pages (shock horror who have thought it). The web is hardly the first example where you are pulling raw data and outputting it in the desired format. You can't exactly blame template engines for providing a stop gap for a niche market (which is not that small).
The main point is XML, without a definition, is pointless and a waste of time to parse. You are better off with a decent serialisation language like YAML, yet people persist with this out of ignorance. Even when it has a definition, it quite often used in a situation that des not really require. Of course can't have data cluttering up the pages.
grep is your friend.
x00, you're not backing up any of your statements. If we're going to have a discussion, start referencing reasons. Do some research.
As for XSLT. I've not found a better CMS for it than with Symphony. If anyone finds something better, let me know
grep is your friend.
More code = more bugs, period. If you want to introduce more code then you should have a compelling reason for it. I haven't yet heard a compelling argument in favor of template engines like Smarty. Any argument that it reduces bugs tends to ignore the extra bugs introduced by the template engine itself. I guess it could make the HTML easier to write if your HTML editor doesn't understand PHP snippets, but is that really still a problem in 2009? You're talking about serializing data to pass it between two modules of an application. I'm saying there's no need to do that at all. As long as you build your data structures correctly you can keep the application logic quite well separated from the display logic without having to treat the view like it's the application's retarded little brother.
But back to XML, you still didn't address the big advantage of XML+XSLT over other template systems. With your code or Smarty or HAML or anything else, your code must generate the content all over again whenever you apply a new template. With XML+XSLT, you're always generating the same XML (so it's easier to cache) and each XSL template is a static file. The work of applying the template is done by the client. That does mean the client must have an XML parser built-in, but that shouldn't be a problem since every modern web browser already has that. Define irony: An unstructured, stream-of-consciousness rant about how XML sucks because it's too wordy and too hard to parse.