Dear folks,
Imagine a flat php site without database with hundreds of files having the same variables defined in all of them eg $read $look and $buys.
page1.php
<?
$blue= ".....";
$bell= ".....";
$beam= ".....";
?>
page2.php
<?
$blue= ".....";
$bell= ".....";
$beam= ".....";
?>
etcettera.php
Now, as soon as I invent a new variable, say $bike or $beaf then I have to go through all those template files in order to add to them $beaf = "" or else there undefined there. I miss a master template so to say... Any ideas/hints/code/suggestions are welcome. Thanks in advance.
Is there any smarter way of template management without use of database, making it easer to maintain these templates?
A templating engine like Twig might help you. Twig supports template inheritance, which allows you to define a master template that all child templates inherit from:
master.html.twig:
<html>
<head><title>{% block title %}Default Title{% endblock %}</title></head>
<body>
<h1>{% block pageHeading}{% endblock %}</h1>
{% block body}{% endblock %}
</body>
</html>
child.html.twig:
{% extends master.html.twig %}
{% block title}Child Page{% endblock %}
{% block pageHeading}Weclome!{% endblock %}
{% block body}
<p>My name is {{ name }}. Today's date is {{ today|date('n/j/Y') }}.</p>
{% endblock %}
PHP code:
$loader = new Twig_Loader_Filesystem('/path/to/templates');
$twig = new Twig_Environment($loader, array(
'cache' => '/path/to/compilation_cache',
));
$template = $twig->loadTemplate('child.html.twig');
echo $templater->render(array("name"=>"Mike", "today"=>new DateTime()));
I would suggest to create a file that has an __autoload function in it, include it at the top of your page1.php (and so on), then create some class like this:
class MyVars {
const book = "Book";
const apple = "Apple";
}
and you can use them like MyVars::book and MyVars::apple in your PHP files.
Your system with flat variables floating around is one of the thing to avoid.
Use a framework that helps you not doing such bad errors or just use Smarty
Zend
Related
TL;DR: I am currently struggling with the idea how to elegantly generate CRUDs/GRID using Twig.
Long story:
I have a Phalcon app with AngularJs, templating system is Twig.
PHP is suppose to prepare a template for CRUD that contains:
List od entities, table that contains proper headers, columns, row items, action buttons
Simple and advanced search
Mass actions block
Main buttons - Add/Import/Export etc.
AngularJs is responsible for:
Paginating results in 2 modes: Ajax Loaded entities, All entities at once
Changing number of entities per page
Displaying various forms in modals - Add/Edit/Import
Filtering entities - simple and advanced search
Everything is working right now but I am not particularly fond of how it works.
For example a simple entity with few fields needs a following template:
{% extends 'index.twig' %}
{% block containerAttr %}ng-controller="InventoryController as ctrl"{% endblock %}
{% set ctrlName = 'ctrl' %}
{% set columnWidth = 'col-xs-12' %}
{% set tableClass = 'table table-bordered table-striped table-hover' %}
{% block header %}
{% include '#crud/crud/header.twig' %}
{% endblock %}
{% block content %}
{% embed '#crud/crud/main-box.twig' %}
{% block tableHeader %}
{% autoescape false %}
{{ crud.tableHeader('Id', 'id') }}
{{ crud.tableHeader('Nazwa', 'name') }}
<th class="col-xs-1">Actions</th>
{% endautoescape %}
{% endblock %}
{% block tableRow %}
<td ng-bind="e.id"></td>
<td ng-bind="e.name"></td>
{% endblock %}
{% endembed %}
{% embed '#crud/crud/form.twig' %}
{% block modalBody %}
{% autoescape false %}
<div class="row">
{{ crud.input('ctrl.entity.name', 'Name', 12) }}
</div>
{% endautoescape %}
{% endblock %}
{% endembed %}
{% embed '#crud/crud/upload.twig' %}{% endembed %}
{% embed '#crud/crud/advancedSearch.twig' %}{% endembed %}
<script>
window.xdata = {{ xdata | json_encode | raw }};
</script>
{% endblock %}
crud in this template is responsible for generating form fields compatible with AngularJs.
Idea is: To create new CRUDs/Grids with the least amount of work required. While still giving a room for some flexibility.
Right now to make a CRUD/Grid inside my application there is a really little work required:
PHP Controller needs to contain only one line:
class SubCategoryController extends CrudBase
{
protected $entityClass = InventoryCategory::class;
}
Thanks to extending it is really easy to customize every part of it.
Model needs to have just a few fields:
class InventoryCategory extends ModelBase
{
/** #var integer */
public $id;
/** #var string */
public $name;
public function initialize()
{
$this->setSource('inventory_subcategory');
$this::setup(['castOnHydrate' => true]);
}
}
Even the AngularJs controller contains only URLs and one line:
class InventoryCategoryController extends CrudBase {
constructor($injector, $scope) {
super($injector, $scope);
this.urlSave = '/inventory/category/save';
this.urlImport = '/inventory/category/import';
this.urlExport = '/inventory/category/export';
this.urlDelete = '/inventory/category/delete';
this.init({
advancedSearch: false
});
}
}
angular.module('App').controller('InventoryCategoryController', InventoryCategoryController);
Yes I use ES6, application is not compatible with older browsers anyways and it is admin panel so I do not care about older browsers.
But now only templates remains a tedious work to copy it over and change it. Not to mention they do look pretty ugly.
So my idea was to use Annotation Reader (Phalcon has one) to read fields from Model, then transform it into a base configuration, check if there is custom configuration in json and merge it. Then based on configuration, generate this whole template on the fly.
So the grand question is:
I was wondering if I can create some class that extends Twig_Template to generate this template on the fly?
I have seen Twig cache and it should be pretty easy but then how can i use it? How can i render it? Will extend still work?
I'm wondering how I would go about using custom variables in base.html.twig in a symphony application.
I know I can use {{ app.whatever }} but how would I use {{ myvariable }} or {{ myentity.row }} if I wanted to?
Thanks
As a variable is rendered with a twig template, you can use this variable in both parent and child templates.
In other words, if you have the following base template:
// base.html.twig
<html>
<body>
{{ block body }}
{{ endblock }}
</body>
</html>
The following child template:
// child.html.twig
{% extends 'base.html.twig' %}
{% block body %}
// content
{% endblock %}
And the following controller action:
public function renderVariableAction()
{
return $this->render('child.html.twig', [
'hello' => 'Hello world',
]);
}
You can use {{ hello }} in both base.html.twig and child.html.twig.
EDIT
For a global variable:
// app/config/config.yml
# ...
twig:
# ...
globals:
your_custom_var: "your_value"
You can't define a variable that is always assigned to a specific template, the variable must be rendered with it dynamically.
Note You can define global variables dynamically like this:
$this->get('twig')->addGlobal('entity', $entity);
So you can easily inject the same variable on kernel.response using an EventListener.
See global variables in templates.
Hi I have a class following:
class allConstants {
//PREDEFINED ALL FIXED GROUPS USING IN ACCOUNT MODULE
const GROUP_BANK_ACCOUNT = 'Bank Accounts';
const GROUP_CURRENT_ASSETS = 'Current Assets';
const GROUP_LOAN_LIBILITIES = 'Loan (Liabilities)';
const GROUP_BANK_OD_ACCOUNT = 'Bank OD a/c';
const GROUP_CASH_IN_HAND
}
So I want to access these constants into twig file. So when I am using like following in twig :
constant('\Edu\AccountBundle\Constants\allConstants::GROUP_BANK_ACCOUNT');
its showing an refrence erro that "constant" not define.
Please guide how to make it work. I am using symfony 2.3.7
Thanks in advance
{% if gropu is constant('allConstants::GROUP_BANK_ACCOUNT') %}
the status attribute is exactly the same as allConstants::GROUP_BANK_ACCOUNT
{% endif %}
test constants from object instances
{% if gropu is constant('GROUP_BANK_ACCOUNT', allConstants) %}
the status attribute is exactly the same as allConstants::GROUP_BANK_ACCOUNT
{% endif %}
The code posted by Muhammad is right:
{% if group is constant('GROUP_BANK_ACCOUNT', allConstants) %}
the status attribute is exactly the same as allConstants::GROUP_BANK_ACCOUNT
{% endif %}
But you can use like this only with Twig >=1.12.1; with lower version, you can just use it from static classes, like this:
constant('allConstants::GROUP_BANK_ACCOUNT')
I want to use Twig (v1.15.0) in my project in order to replace our homemade template engine. It uses specific delimiters to replace variables, [[...]], or to manage localized strings, [% ... %].
<table>
<tr>
<td>[%myLocalizedString%]</td>
<td>[[myVarToReplace]]</td>
</tr>
</table>
I don't want to modify all existing templates to replace each delimiter, for legacy and compatibility reasons.
For variables, it is not a big deal, I just have to set the Twig lexer's options :
$twig = new Twig_Environment();
$lexer = new Twig_Lexer($twig, array(
'tag_comment' => array('{#', '#}'),
'tag_block' => array('{%', '%}'),
'tag_variable' => array('[[', ']]'), // was array('{{', '}}')
'interpolation' => array('#{', '}'),
));
$twig->setLexer($lexer);
In the case of localization delimiters is not as simple. Initialy I wanted to do something like that :
$twig = new Twig_Environment();
$lexer = new Twig_Lexer($twig);
$lexer->addDelimiter('tag_localize', array('[%', '%]'), 'functionToCall');
But it does not seems to be implemented yet.
The ultimate solution is to extend the Lexer class and use it in my twig environnement.
But I would like to avoid that.
Is there any better solution ?
I'm sure you know this already: in Twig you do translations using the I18n extension. That extension provides a "trans" tag: see i18n docs
I see no way you can convert your translation syntax [%Hello world%] into the Twig way {% trans %}Hello world{% endtrans %} by extendling the Lexer class, because {% is a block element and trans a tag defined in the I18n extension. You could build your own translation logic, but I think it is much easier to create a preprocessor that replaces [% with {% trans %] and %} with {% endtrans %}.
I imagine it could work like this (untested):
class MYTwigEnvironment extends Twig_Environment {
public function compileSource($source, $name = null) {
/*
* code to replace '[%' with '{% trans %}' in $source
* comes here ...
*/
return parent::compileSource($source, $name = null);
}
}
As far as I understand, this way the template caching should stay intact.
regards
SETUP:
Twig 1.13.1
PHP 5.4.3
PROBLEM:
I am needing help setting up a custom tag that calls a function that i have already built...
Current Code:
Template Code
{% set stories = get_latest_stories(2, sports) %}
{% for story in stories %}
{{ story.headline }} <br>
{% endfor %}
Controller
$function = new Twig_SimpleFunction('getViewStories', function (section, limit) {
return news_stories::getStories(section,limit);
});
$twig->addFunction($function);
$twig->render("storyList.html");
GOAL:
No with that said I would like to use a custom tag like
{% get_latest_stories 2 sports %}
to call the same function as above. The new way looks nicer and is easier to follow
Why not fetch your stories in the controller instead of the template? This does not seem like a job for the view layer...
So, something like this:
$twig->render("storyList.html", array(
'stories' => news_stories::getStories($section, $limit)
));
Then, you'll have a stories variable available in your template.
here is simple example how to write twig extension
Following code is taken from my unfinished project
function file_import($value){
//some code here
return $value;
}
$app['twig']->addFunction('file_import', new Twig_Function_Function('file_import'));
usage
{{ file_import('value') }}