eftec / bladeonehtml
The standalone version Blade Template Engine from Laravel in a single php file
Installs: 8 951
Dependents: 11
Suggesters: 1
Security: 0
Stars: 10
Watchers: 2
Forks: 2
Open Issues: 0
Requires
- php: >=7.4
- ext-json: *
- eftec/bladeone: ^4.12
- eftec/messagecontainer: ^2.8
Requires (Dev)
- phpunit/phpunit: ^9.5.11
README
It is a PHP library that allows to create forms (view) easily, cleanly and without killing the performance. It uses the library BladeOne to renders the view. This library only uses a single dependency, one file and nothing more.
This library works in two ways:
- It compiles a script (our view that use our tags), in a native PHP code.
- And the next read, if the script exists, then it uses it (instead of re-compiling). And since the script is native code, then it is exactly like to work in vanilla-php, but it is way easy to write and to maintenance.
- BladeOneHtml
Usage
- This library requires eftec/bladeone. You could install via Composer in the root folder of your project as
composer require eftec/bladeonehtml
- And you should extend the class as follows (BladeOneHtml is a Trait)
include "vendor/autoload.php"; use eftec\bladeone\BladeOne; use eftec\bladeonehtml\BladeOneHtml; class myBlade extends BladeOne { use BladeOneHtml; } $blade=new myBlade(); // for our example: $myvalue=@$_REQUEST['myform']; echo $blade->run("exampleview", ['myvalue'=>$myvalue]);
- Create a folders called 📁 "\views" and 📁 "\compiles"
- Inside views, creates the next file 📄 "\views\exampleview.blade.php"
<body> @form() @input(type="text" name="myform" value=$myvalue) @button(type="submit" value="Send") @endform() </body>
$blade=new myBlade();
Template basic
This library adds a new set of tags for the template. The tags uses named arguments, so it is easily configurable.
@<tag>(argument1="value" argument2='value' argument3=value argument4=$variable argument5=function(), argument6="aaa $aaa")
This library uses the native html arguments but some arguments are special
Let's say the next example
@input(value="hello world" type="text" )
It is rendered as
<input value="hello world" type="text" />
If the tag uses a variable of function, then this view
@input(value=$hello type="text" )
Is converted into
<input value="<?php echo $this->e($hello);?>" type="text" />
The method $this->e is used to escape the method.
Note: This library allows any tag, even custom tags (but only if they don't enter in conflict with the special tags, see table)
@input(value="hello world" type="text" mycustomtag="hi" )
Is converted into
<input value="hello world" type="text" mycustomtag="hi" />
Template usage
input
It shows an input HTML.
Basic example:
@input(id="id1" value="hello world$somevar" type="text" )
hidden
It generates a hidden field
Basic example:
@hidden(name="id1" value="hello world$somevar" )
label
It shows a label html
@label(for="id1" text="hello world:")
image
It shows an image
@image(src="https://via.placeholder.com/350x150")
select
It shows a select (dropdown list) html object
Example:
@select(id="aaa" value=$selection values=$countries alias=$country)
@item(value='aaa' text='hello world')
@item(value='aaa' text='hello world')
@item(value='aaa' text='hello world')
@items( id="chkx" value=$country->id text=$country->name)
@endselect
Note 1: @items requires the arguments values in the parent (@select) and the arguments value (the selectable value) and text (the visible value) Note 2: @items requires an id, assigned in the same tag or in the parent tag (in this case, the parent is @select) Note 3: By standard, the argument id must be unique.
item
@item is a utility tag used inside other tags. This behaves depending on of their parent tag. It adds a simple line/row to the parent object.
Example:
@select()
@item(value='aaa' text='hello world')
@endselect
It renders
<select>
<option value="aaa">hello world</option>
</select>
items
@items is a utilitarian tag used inside some tags. This behaves depending on of their parent tag. It adds a multiples lines/rows to the parent object using the tag values
Note: This tag requires some arguments:
- the parent(or this tag) requires the tag values
- the parent requires the tag value It indicates the current selection (if any)
- the parent(or this tag) requires the tag alias If alias is missing then it uses the name of values + "Row", i.e. values=product -> alias= productRow
- the parent(or this tag) requires the tag id
- The rendered "id" will be generated using this id+"_"+"id of the row". i.e. id="idproduct" => idproduct_0, idproduct_1
- Why? It is because the id must be unique (html specs)
Example, if $countries is a list of objects then :
@select(id="aaa" value=$selection values=$countries alias=$country)
@items( id="chkx" value=$country->id text=$country->name)
@endselect
If $countries is a list of arrays then:
@select(id="aaa" value=$selection values=$countries alias=$country)
@items( id="chkx" value=$country['id'] text=$country['name'])
@endselect
Inside the tag items, you could use the next variables
optgroup
It starts an optional group (select)
Example:
@select(id="aaa" value=$selection values=$countries alias=$country)
@optgroup(label="group1")
@item(value='aaa' text='hello world')
@item(value='aaa' text='hello world')
@item(value='aaa' text='hello world')
@endoptgroup
@endselect
Note: this tag must be ended with the tag @endoptgroup
checkbox
It adds a single checkbox
Example:
@checkbox(id="idsimple" value="1" checked="1" post="it is a selection")
radio
It adds a single radio button
Example:
@radio(id="idsimple" value="1" checked="1" post="it is a selection")
textarea
It draws a text area.
Example:
@textarea(id="aaa" value="3333 3333 aaa3333 ")
button
It draws a button
Example:
@button(value="click me" type="submit" class="test" onclick='alert("ok")')
link
It adds a hyperlink
Example:
@link(href="https://www.google.cl" text="context")
checkboxes
It shows a list of checkboxes
@checkboxes(id="checkbox1" value=$selection alias=$country)
@item(id="aa1" value='aaa' text='hello world' post="<br>")
@item(id="aa2" value='aaa' text='hello world2' post="<br>")
@items(values=$countries value='id' text='name' post="<br>")
@endcheckboxes
radios
It shows a list of radio buttons
@radios(id="radios1" name="aaa" value=$selection alias=$country)
@item(value='aaa' text='hello world' post="<br>")
@item(value='aaa' text='hello world2' post="<br>")
@items(values=$countries value='id' text='name' post="<br>")
@endradios
file
It generates a file input value
@file(name="file" value="123.jpg" post="hello world")
Note: it also renders a hidden file with name "name"+"_file" with the original value
ul
It generates an unsorted list
@ul(id="aaa" value=$selection values=$countries alias=$country)
@item(value='aaa' text='hello world')
@item(value='aaa' text='hello world')
@item(value='aaa' text='hello world')
@items(value=$country->id text=$country->name)
@endul
ol
It generates a sorted list
@ol(id="aaa" value=$selection values=$countries alias=$country)
@item(value='aaa' text='hello world')
@item(value='aaa' text='hello world')
@item(value='aaa' text='hello world')
@items(value=$country->id text=$country->name)
@endol
pagination
It generates a pagination. It requires bootstrap3, bootstrap4 or bootstrap5.
You can find an example at examples/examplepagination.php
PHP code
$current=isset($_GET['_page']) ? $_GET['_page'] : 1; echo $blade->run("examplepagination", ['totalpages'=>count($products) ,'current'=>$current ,'pagesize'=>10 ,'products'=>$items ]);
Template
@pagination(numpages=$totalpages current=$current pagesize=$pagesize urlparam='_page')
Note: The page is base 1. Note: the argument urlparam is used to build the link (domain.dom/web.php?_page=999)
You can change the name of the buttons prev and next as follows:
$this->setTranslation(['pagination'=>['prev'=>'<<>','next'=>'>']]);
table
It renders a table
@table(class="table" values=$countries alias=$country border="1")
@tablehead
@cell(text="id")
@cell(text="cod")
@cell(text="name")
@endtablehead
@tablebody(id='hello world' )
@tablerows(style="background-color:azure")
@cell(text=$country->id style="background-color:orange")
@cell(text=$country->cod )
@cell(text=$country->name)
@endtablerows
@endtablebody
@tablefooter
@cell(text="id" colspan="3")
@endtablefooter
@endtable
tablehead
It renders the header of the table (optional). Each cell added inside it, is rendered as "th" HTML tag
tablebody
It renders the body of the table (optional). Each cell added inside the table is rendered as "td" HTML tag
tablefooter
It renders the footer of the table (optional). Each cell added inside it, is rendered as "th" HTML tag
tablerows
It generates a row inside the body
cells
It renders a cell inside the tablehead,tablebody (tablerows) or tablefooter
cssbox
It renders and css added into the box
<head> @cssbox </head>
How to add a new css into the cssbox?
Using the method addCss($css,$name)
$this->addCss('<link rel="stylesheet" href="mystyle.css">','mystyle'); $this->addCss('css/stylename.css');
$css could be a link or a link tag
$name is optional but it avoids to add duplicates. If we add a new CSS with the same name as a previous one, then it is ignored.
jsbox
It renders all JavaScript links added to the box
<body> <!-- our page --> @jsbox </body>
How to add a new JavaScript into the cssbox?
Using the method addJs($script,$name)
$this->addJs('<script src="js/jquery.js"></script>','jquery');
jscodebox
<body> <!-- our page --> @jsbox <!-- we could load jquery here --> @jscodebox(ready) </body>
This code adds the tags < script > automatically.
The argument ready indicates if we want to execute the function when the document is ready.
How to add a new JavaScript code into the jscodebox?
$blade->addJsCode('alert("hello");');
Template Customization
BladeOneHtml allows to modify the tags used and to set a default classes for each class.
You can set a default class and tags for Bootstrap 3/4/5 using the next method (pick only one).
// if true then it loads the css and js from a cdn into the css and jsbox so it requires @cssbox and @jsbox $blade->useBootstrap5(true); // if true then it loads the css and js from a cdn into the css and jsbox so it requires @cssbox and @jsbox $blade->useBootstrap4(true); // if true then it loads the css and js from a cdn into the css and jsbox so it requires @cssbox and @jsbox $blade->useBootstrap3(true);
Or you could create your own tags and classes
Set a default class
$blade->defaultClass[$tagname]='default class';
Set a custom pattern
$blade->pattern['nametag']='pattern';
Where nametag could be as follows
Pattern-Variables inside the code
Example of a normal tag:
$blade->pattern['input']='{{pre}}<input{{inner}} >{{between}}</input>{{post}}';
Note :(*) What is escaped?. For example the text "", if it escaped, it is displayed as "<hello>"
Custom attribute
It is possible to add a custom attribute that it could be used inside a pattern.
For example, let's add the custom tag called customtag
$blade->customAttr['customtag']='This attr is missing!'; $blade->pattern['alert']='{{pre}}<div {{inner}}><h1>{{customtag}}</h1>{{between}}</div>{{post}}';
And in the view
@alert(text="hi there" class="alert-danger" customtag="it is a custom tag")<br> @alert(text="hi there" class="alert-danger" )<br>
Methods
The library has a lit of methods that they could be used to initialize and configure the library. They are optionals.
useBootstrap5
It sets the patterns and classes to be compatible with bootstrap 4.
if argument is true, then it adds the CSS to the css box from the CDN
Our code
$blade->useBootstrap5(true);
Note: If we want to use the css box, then we need to add to our view the next code
<header> @cssbox </header>
useBootstrap4
It sets the patterns and classes to be compatible with bootstrap 4.
if argument is true, then it adds the CSS to the css box from the CDN
Our code
$blade->useBootstrap4(true);
Note: If we want to use the css box, then we need to add to our view the next code
<header> @cssbox </header>
useBootstrap3
It sets the patterns and classes to be compatible with bootstrap 3.
if argument is true, then it adds the CSS to the css box from the CDN
$blade->useBootstrap3(true);
addCss
It adds a CSS to the css box
$this->addCss('css/datepicker.css','datepicker');
addJS
It adds a javascript link to the js box
$this->addJs('<script src="js/jquery.js"></script>','jquery');
addJSCode
It adds a javascript code to the js box
$blade->addJsCode('alert("hello");');
Public Fields
It is the list of public fields of the class. The fields are public because for performance purpose (versus to use setter and getters)
$pattern
It stores the list of patterns used by the code
$this->pattern['sometag']='{{pre}}<tag {{inner}}>{{between}}</tag>{{post}}';
Note: see "Pattern-Variable inside the code" to see the list of pattern-variables
$defaultClass
The default CSS class added to a specific tag.
$this->defaultClass['sometag']='classred classbackgroundblue';
$customAttr
It adds a custom adds that it could be used together with $this->pattern
$this->customAttr['customtag']='XXXXX'; // So we could use the tag {{customtag}}. 'XXXXX' is the default value
The custom attribute always removes the quotes and double quotes, so if our value is "hello" -> hello
Creating a new pattern
It is possible to add a new pattern by extending the PHP class.
1- Adding a new pattern
$this->pattern['mynewtag']='<mycustomtag {{inner}}>{{between}}</mycustomtag>';
2- Creating a new method
You could create a new PHP class or trait and extend our class. Inside this new structure, you must add a new method with the next structure
Using a new class
use eftec\bladeone\BladeOne; use eftec\bladeonehtml\BladeOneHtml; class MyBlade extends BladeOne { use BladeOneHtml; } class MyClass extends MyBlade { protected function compileMyNewTag($expression) { // the method must be called "compile" + your name of tag. $args = $this->getArgs($expression); // it separates the values of the tags $result = ['', '', '', '']; // inner, between, pre, post // your custom code here return $this->render($args, 'mynewtag', $result); // we should indicate to use our pattern. } }
Using a trait (recommended, why? It is because trait are more flexible)
trait MyTrait { protected function compileMyNewTag($expression) { // the method must be called "compile" + your name of tag. $args = $this->getArgs($expression); // it separates the values of the tags $result = ['', '', '', '']; // inner, between, pre, post // your custom code here return $this->render($args, 'mynewtag', $result); // we should indicate to use our pattern. } } class MyClass extends BladeOne { use BladeOneHtml; use MyTrait; // <-- our trait }
3- Creating a new parent Method (container method)
For creating a parent method, you must push a new value inside $this->htmlItem. You can store whatever you want to.
$this->pattern['mynewtag']='<mycustomtag {{inner}}>{{between}}';
protected function compileMyNewTag($expression) { $args = $this->getArgs($expression); // it loads and separates the arguments. $this->htmlItem[] = ['type' => 'mynewtag','value' => @$args['value'] ]; $result = ['', '', '', '']; // inner, between, pre, post //unset($args['value']); // we could unset values that we don't want to be rendered. return $this->render($args, 'select', $result); }
Our objective is to render PHP code, not to evaluate a code. For example, if $args['somearg']=$variable, then our value is $variable (as text), no matter the real value of the variable.
You must also create a method to end the container, and we must also add a new pattern.
$this->pattern['mynewtag_end']='</mycustomtag>';
protected function compileEndNewTag() { $parent = @\array_pop($this->htmlItem); // remove the element from the stack if (\is_null($parent) || $parent['type']!=='newtag') { // if no element in the stack or it's a wrong one then error $this->showError("@endnewtag", "Missing @initial tag", true); } // our code return $this->pattern[$parent['type'] . '_end']; // renders the element of the stack }
Our items could know if they are inside a tag with the next operation
$parent = \end($this->htmlItem);
4- Advanced
We could create a component that requires CSS and JavaScript.
For example a date picker.
protected function compileDatePicker($expression) { $args = $this->getArgs($expression); // it loads and separates the arguments. \array_push($this->htmlItem, ['type' => 'mynewtag','value' => @$args['value']]); $result = ['', '', '', '']; // inner, between, pre, post if(!isset($args['id'])) { $this->showError("@datepicker", "Missing @id tag", true); } $this->addJs('<script src="js/jquery.js"></script>','jquery'); // our script needs jquery (if it is not loaded) $this->addCss('css/datepicker.css','datepicker'); $this->addjscode('$(.'.$args['id'].').datepicker();'); //unset($args['value']); // we could unset values that we don't want to be rendered. return $this->render($args, 'select', $result); }
Note: It's better to add the library of jQuery and date picker once in our code
Version history
- 2.4 2024-03-02
- Updating dependency to PHP 7.4. The extended support of PHP 7.2 ended 3 years ago.
- Added more type hinting in the code
- 2.3.2 2023-01-31
- a typo in pagination
- 2.3.1 2023-01-31
- fixed a problem with pagination.
- some cleanups
- update dependencies.
- 2.3 2022-02-04
- Now this library is compatible with PHP 7.2 and higher.
- Some cleanups and type hinting (return methods)
- 2.2 2021-12-11
- fixed a problem with optgroup and when the argument is an associative array.
- 2.1 2021-10-01
- Added support for Bootstrap 5.0
- Updated Bootstrap CDNs
- added tags @container, @row, @col
- 2.0 2021-09-24
- Dropped support for PHP 5.x. Updated support for BladeOne 4.0
- 1.8.1 2021/07/03
- It solves a problem when the argument is defined as id="somevalue$id"
- 1.8 2021/06/09
- @checkbox and @radio now works with variables. The element is checked only if the value is not null, empty or zero.
- 1.7.1 2021/02/06
- @item now marks the value "checked" or "selected" if the values is equals to the current value of the parent object
- Bootstrap 4 CDN now it uses the version 4.6
- for @item and @items, the field name and idname are created automatically. If id is set, then it uses it.
- 1.7 2021/01/12
- @button now considers value as the value of argument while text the visual content.
- It also uses in_array instead of isset().
- Compatible with PHP 8.x
- 1.6.1 2020/08/31
- Pagination now it has "first" and "last" buttons.
- 1.6 2020/08/30
- Added tag @pagination
- Added the method setTranslationControl() and getTranslationControl()
- 1.5 2020/06/07
- Added a new optional argument to processArgs() and render();
- Added unit test.
- 1.4 2020/05/02
- now it allows empty arguments. It requires BladeOne 3.43 or higher.
- added unit test.
- 1.3 2020/04/22
- added method useBootstrap3()
- added default class for textarea in useBootstrap4()
- 1.2 2020/04/21
- tag @@alert()
- fixed: @@items() now it keeps the selection
- tag @@cssbox, @@jsbox and @jscodebox
- method useBootstrap4($cdn=false) has a new argument
- 1.1 2020/04/21
- Method isVariablePHP() moved to BladeOne
- Update LICENSE.
- Added more documentation.
- 1.0 2020-04-20 First version