I just stuck at a point.
To render Forms in Smarty Template.
Well, smarty is well configured in my silex project.
here is the Code in my controller class.
$loginForm = $app['form.factory']
->createBuilder(new Form\UserLogin())
->getForm();
$app['smarty']->assign('loginForm', $loginForm->createView());
return $app['smarty']->render('login.tpl');
Here is the code in my tpl file
{block name="headline"}
<h1>User Login</h1>
{/block}
{block name="content"}
<div>
{form_widget(loginForm)}
</div>
{/block}
And i am getting this exception.
SmartyCompilerException:
Syntax Error in template "/home/Symfony/demo/App/View/login.tpl" on line 8
"{form_widget(loginForm)}" unknown function "form_widget"
Edit:
Ok i found the issue but not getting the solution.
Following is SmartyServiceProvider Class.
<?php
namespace App\ServiceProvider;
use Silex\Application;
use \Symfony\Component\HttpFoundation\Request;
use Silex\ServiceProviderInterface;
use App\Classes\Smarty;
use NoiseLabs\Bundle\SmartyBundle\Form\SmartyRendererInterface;
use \NoiseLabs\Bundle\SmartyBundle\Extension\AbstractExtension;
use \NoiseLabs\Bundle\SmartyBundle\Extension\FormExtension;
use \NoiseLabs\Bundle\SmartyBundle\Form;
class SmartyServiceProvider implements ServiceProviderInterface
{
public function register(Application $app)
{
$app['smarty.auto-render'] = true;
$app['smarty.extension'] = $app->protect(
function (AbstractExtension $extension, Smarty $smarty = null) use ($app) {
if ($smarty == null) {
$smarty = $app['smarty'];
}
/** #var $plugin \NoiseLabs\Bundle\SmartyBundle\Extension\Plugin\AbstractPlugin */
/** #var $filter \NoiseLabs\Bundle\SmartyBundle\Extension\Filter\AbstractFilter */
foreach ($extension->getPlugins() as $plugin) {
//print $plugin->getName() . " | " . $plugin->getType() . "<br>";
$smarty->registerPlugin($plugin->getType(), $plugin->getName(), $plugin->getCallback());
}
foreach ($extension->getFilters() as $filter) {
$smarty->registerFilter($filter->getType(), $filter->getCallback());
}
}
);
$app['smarty.extensions'] = $app->protect(
function (array $extensions, Smarty $smarty = null) use ($app) {
foreach ($extensions as $extension) {
$app['smarty.extension']($extension, $smarty);
}
}
);
$app['smarty'] = $app->share(
function () use ($app) {
$app['directory.smarty.plugins'] = $app['directory.root.app'] . '/Classes/Smarty/Plugins';
$smarty = isset($app['smarty.instance']) ? $app['smarty.instance'] : new Smarty(
$app,
isset($app['smarty.primary.template.dir'])
? $app['smarty.primary.template.dir']
: $app['directory.root.view'],
false
);
if (isset($app["smarty.options"]) && is_array($app["smarty.options"])) {
foreach ($app["smarty.options"] as $smartyOptionName => $smartyOptionValue) {
$smarty->$smartyOptionName = $smartyOptionValue;
}
}
$smarty->assign("app", $app);
if (isset($app['smarty.configure'])) {
$app['smarty.configure']($smarty);
}
$extensions = [];
//$extensions[] = new \NoiseLabs\Bundle\SmartyBundle\Extension\FormExtension();
$extensions[] = new \NoiseLabs\Bundle\SmartyBundle\Extension\RoutingExtension($app['url_generator']);
$extensions[] = new \App\Classes\Smarty\HookExtension();
$app['smarty.extensions']($extensions, $smarty);
return $smarty;
}
);
}
public function boot(Application $app)
{
}
}
Here in that class i have loaded extensions of SmartyBundle here.
Here I'll have to load FormExtensions.
$extensions = [];
$extensions[] = new \NoiseLabs\Bundle\SmartyBundle\Extension\FormExtension('Don't know how to get SmartyRendererInterface instance here');
$extensions[] = new \NoiseLabs\Bundle\SmartyBundle\Extension\RoutingExtension($app['url_generator']);
$extensions[] = new \App\Classes\Smarty\HookExtension();
$app['smarty.extensions']($extensions, $smarty);
The correct syntax for the Form Widget is:
{form_widget form=$loginForm}
From your example it's not clear the out from $loginForm->createView() and you're lacking the form tags ( ie )that normally surround the Form widget. If the createView includes these you make be not need the form widget and just need to output the entire form HTML as:
{$loginForm}
Related
I'm making a website using a custom made router. With the current code, I can add a pretty url for example '/contact' to the website. I'm now this far that I need to add a product page. Normally you would have a url like product?product_id=$product_id. But I don't know how I can implement this idea with the current code. The Route class is where is where it adds new urls.
class Route
{
private $_uri = array();
private $_method = array();
/*
* Builds a collection of internal URL's to look for
* #param type $uri
*/
public function add($uri, $method = null)
{
$this->_uri[] = '/' . trim($uri, '/');
if($method != null){
$this->_method[] = $method;
}
}
public function submit()
{
$uriGetParam = isset($_GET['uri']) ? '/' . $_GET['uri'] : '/';
$routeFound = false;
foreach($this->_uri as $key => $value){
if(preg_match("#^$value$#",$uriGetParam)){
if(is_string($this->_method[$key])){
$routeFound = true;
$useMethod = $this->_method[$key];
new $useMethod();
}
else{
$routeFound = true;
call_user_func($this->_method[$key]);
}
}
}
if(!$routeFound){
http_response_code(404);
require_once 'pages/404.php';
}
}
And in the index file i actually add routes to the project
<?php
require_once 'classes/route.php';
require_once 'classes/config.php';
require_once 'classes/model.php';
require_once 'functions.php';
require_once 'classes/validator.php';
$route = new Route();
$db = new Db();
$model = new Model();
$route->add('/', function(){
require_once 'pages/home.php';
});
$route->add('/product', function(){
require_once 'pages/product.php';
});
$route->add('/contact', function(){
require_once 'pages/contact.php';
});
$route->add('/admin', function(){
require_once 'pages/admin.php';
});
$route->add('/login', function(){
require_once 'pages/test.php';
});
$route->submit();
Which framework are you using?
I’m learning CodeIgniter now, what I do there is something like:
the URL for product would be:
application_path/controller/method/id
For product:
application_path/product/insert/1
(Using “1” as an ID example)
I’d have to add a route, in the route file, to specify that after my /method I’ll have an ID. (I believe the way you do it depends on the framework you’re using)
In my controller, my method would receive a parameter. Just like:
Public function insert($id){
//code...
}
i have problem with rendering template in ZF2, where template is in string in variable. There is simple example:
$template = "<div>easy</div>";
$view = new \Zend\View\Model\ViewModel();
$view->setTemplate($template);
$renderer = new \Zend\View\Renderer\PhpRenderer();
$html = $renderer->render($view);
This code fail on rendering, the renderer think that the template is a path to file. And iam reallz not sure how to tell rendere its a string.
Thx for your time and respond.
You have to extend the PhpRenderer class and override the render method, in such a way that will use the string in the $template as the actual template:
class MyPhpRenderer extends PhpRenderer {
public function render($nameOrModel, $values = null)
{
if ($nameOrModel instanceof Model) {
$model = $nameOrModel;
$nameOrModel = $model->getTemplate();
if (empty($nameOrModel)) {
throw new Exception\DomainException(sprintf(
'%s: received View Model argument, but template is empty',
__METHOD__
));
}
$options = $model->getOptions();
foreach ($options as $setting => $value) {
$method = 'set' . $setting;
if (method_exists($this, $method)) {
$this->$method($value);
}
unset($method, $setting, $value);
}
unset($options);
// Give view model awareness via ViewModel helper
$helper = $this->plugin('view_model');
$helper->setCurrent($model);
$values = $model->getVariables();
unset($model);
}
// find the script file name using the parent private method
$this->addTemplate($nameOrModel);
unset($nameOrModel); // remove $name from local scope
$this->__varsCache[] = $this->vars();
if (null !== $values) {
$this->setVars($values);
}
unset($values);
// extract all assigned vars (pre-escaped), but not 'this'.
// assigns to a double-underscored variable, to prevent naming collisions
$__vars = $this->vars()->getArrayCopy();
if (array_key_exists('this', $__vars)) {
unset($__vars['this']);
}
extract($__vars);
unset($__vars); // remove $__vars from local scope
while ($this->__template = array_pop($this->__templates)) {
$this->__file = $this->resolver($this->__template);
try {
if (!$this->__file) {
$this->__content = $this->__template; // this line does what you need
}else{
ob_start();
$includeReturn = include $this->__file;
$this->__content = ob_get_clean();
}
} catch (\Exception $ex) {
ob_end_clean();
throw $ex;
}
if ($includeReturn === false && empty($this->__content)) {
throw new Exception\UnexpectedValueException(sprintf(
'%s: Unable to render template "%s"; file include failed',
__METHOD__,
$this->__file
));
}
}
$this->setVars(array_pop($this->__varsCache));
if ($this->__filterChain instanceof FilterChain) {
return $this->__filterChain->filter($this->__content); // filter output
}
return $this->__content;
}
}
and then you code should look like:
$template = "<div>easy</div>";
$view = new \Zend\View\Model\ViewModel();
$view->setTemplate($template);
$renderer = new MyPhpRenderer();
$html = $renderer->render($view);
Try by replacing '\' with _ underscore as Zend_View_Renderer_PhpRenderer
I'm trying to follow the instructions on this docs page, but I seem to be missing something:
https://docs.joomla.org/Supporting_SEF_URLs_in_your_component
The URI that needs to be corrected is: index.php?com_component&view=legal&page=customermasteragreement
It seems like the routing function should be simple, but the page is just displaying default instead of the sub-view.
Here's my current code:
function ComponentBuildRoute(&$query)
{
$segments = array();
if (isset($query['view'])) {
$segments[] = $query['view'];
unset($query['view']);
}
if (isset($query['page'])) {
$segments[] = $query['page'];
unset($query['page']);
}
return $segments;
}
function ComponentParseRoute($segments)
{
$vars = array();
switch($segments[0])
{
case 'legal':
$vars['view'] = 'legal';
break;
case 'customermasteragreement':
$vars['page'] = 'customermasteragreement';
break;
}
return $vars;
}
Update
This code works to display the subpage, but it gives me a URI like: legal-agreements/legal?page=customermasteragreement
class ComponentRouter extends JComponentRouterBase {
public function build(&$query) {
$segments = array();
$view = null;
if (isset($query['view'])) {
$segments[] = $query['view'];
$view = $query['view'];
unset($query['view']);
}
if (isset($query['id'])) {
if ($view !== null) {
$segments[] = $query['id'];
} else {
$segments[] = $query['id'];
}
unset($query['id']);
}
return $segments;
}
public function parse(&$segments) {
$vars = array();
// View is always the first element of the array
$vars['view'] = array_shift($segments);
return $vars;
}
}
EDIT 2
If it helps, here's my model and views
models/legal.php
// import Joomla modelitem library
jimport('joomla.application.component.modelitem');
class ComponentModelLegal extends JModelItem {
public function __construct($config = array())
{
JLoader::register('ComponentHelper', JPATH_COMPONENT_ADMINISTRATOR . '/helpers/component.php');
parent::__construct($config);
}
/**
*
* #return string
*/
public function getLegal() {
$app = JFactory::getApplication();
$page = $app->input->get('page', '', 'STRING');
if ($page) {
ComponentHelper::add('type', $page); //This is an API request to an external service, returning JSON formatted data
$legal = ComponentHelper::getData('commons/legal-agreements.json', TRUE);
if (isset($legal[0]['status'])) {
JError::raiseError(400, $legal[0]['ERROR']);
return false;
} else {
if (!isset($this->legal)) {
$this->legal = $legal;
}
return $this->legal;
}
}
}
}
views/legal/view.html.php
class ComponentViewLegal extends JViewLegacy {
function display($tpl = null) {
// Assign data to the view
$this->legal = $this->get('legal');
// Check for errors.
if (count($errors = $this->get('Errors'))) {
JLog::add(implode('<br />', $errors), JLog::WARNING, 'jerror');
return false;
}
// Display the view
parent::display($tpl);
}
}
views/legal/tmpl/default.php
$page = JRequest::getVar('page');
$pages = array(
'resellermasteragreement',
'customermasteragreement',
'resellerdomainagreement',
'customerdomainagreement',
'resellerwebserviceagreement',
'customerwebserviceagreement',
'resellerdigicertagreement',
'customerdigicertagreement',
'registraragreement',
'customerhostingproductagreement',
'resellerhostingproductagreement'
);
?>
<div class="col-lg-12">
<?php
echo in_array($page, $pages) ? $this->loadTemplate('legal') : $this->loadTemplate('home');
?>
</div>
views/legal/tmpl/default_legal.php
$page = JRequest::getVar('page');
echo nl2br(htmlspecialchars($this->legal[$page]['defaultagreement'], ENT_NOQUOTES, "UTF-8"));
?>
<a type="button" class="btn btn-primary" href="<?php echo JROUTE::_("index.php?option=com_component&view=legal"); ?>">Back</a>
EDIT 3
This works because I wasn't navigating directly to the page from a menu item. There's a top level menu, then a page a links to the agreements. I have a hidden menu to each item, but that wasn't the link I followed.
$app = JFactory::getApplication()->getMenu();
$customermaster = $app->getItems( 'link', 'index.php?option=com_component&view=legal&page=customermasteragreement', true );
JRoute::_('index.php?Itemid='.$customermaster->id);
You have one view but you're not actually set the page argument correctly when you catch a view argument, but you treat page as some king of another view. Can you please try this and check if it works:
function [componentname]ParseRoute($segments)
{
$vars = array();
switch($segments[0])
{
case 'legal':
$vars['view'] = 'legal';
$vars['page'] = $segments[1];
break;
}
return $vars;
}
Also the functions ComponentBuildRoute, ComponentParseRoute must have your components name instead of Component at the beginning.
EDIT
[componentname]BuildRoute and [componentname]ParseRoute are deprecated, you should stick the the class that extends JComponentRouterBase as you have it in your updated second example. Try this one here and see if it works:
class ComponentRouter extends JComponentRouterBase {
public function build(&$query) {
$segments = array();
$view = null;
if (isset($query['view'])) {
$segments[] = $query['view'];
$view = $query['view'];
unset($query['view']);
}
if (isset($query['page'])) {
$segments[] = $query['page'];
unset($query['page']);
}
return $segments;
}
public function parse(&$segments) {
$vars = array();
// View is always the first element of the array
$vars['view'] = array_shift($segments);
if(count($segments) > 0)
$vars['page'] = array_shift($segments);
return $vars;
}
}
EDIT 2
I have a test Joomla 3 site with a simple component named Ola.
Non SEO component URL: http://j3.dev.lytrax.net/index.php?option=com_ola&page=test_page&view=ola
URL generated by JRoute before Router class added to router.php: http://j3.dev.lytrax.net/index.php/component/ola/?page=test_page&view=ola
SEO URL returned by JRoute::_('index.php?option=com_ola&page=test_page&view=ola'); after creating router.php and used the Router class above: http://j3.dev.lytrax.net/index.php/component/ola/ola/test_page
If you visit the links, you'll see that all are working and you can even see the page, view and JRoute results of the calling component Ola.
Unless I've completely misunderstood Joomla (I've been developing with it for four five years now), there is no "sub-view" concept implemented. Trying to use the idea is what's getting you into trouble I think.
I'm astounded that the idea of using a visual debugger is so unpopular.
Get yourself something like Netbeans (there are others too), set up a local web and database server, and watch the code run. Very (well, relatively very) quickly you'll start to understand how the structure hangs together.
You may put code in your view that picks up the extra params you've set and displays or hides things accordingly, but there is no "sub-view".
I need 3 different templates for my Codeigniter application. I had read about Themes' library. But still I didn't get any idea about how to add a template to Codeignier ..
I got about how to involke template in Controller .
Please help
I'm using this template library, is really simple and works well for me.
application/libraries/Template.php
<?php
class Template {
var $template_data = array();
var $use_template = '';
/**
* Set variable for using in the template
*/
function set($name, $value)
{
$this->template_data[$name] = $value;
}
/**
* Set template name
*/
function set_template($name)
{
$this->use_template = $name;
}
/**
* Load view
*/
function load($view = '' , $view_data = array(), $template = '', $return = FALSE)
{
$this->CI =& get_instance();
if (empty($template)) {
$template = $this->CI->config->item('template_master');
}
if (!empty($this->use_template)) {
$template = $this->use_template;
}
$this->set($this->CI->config->item('data_container'), $this->CI->load->view($view, array_merge($view_data, array ('template' => $this->template_data)), true));
return $this->CI->load->view($this->CI->config->item('template_folder') . '/' . $template, $this->template_data, $return);
}
}
application/config/template.php
<?php
$config['template_master'] = 'main';
$config['template_folder'] = 'templates';
$config['data_container'] = 'content';
application/views/templates/main.php
Header<br />
<?php echo $content; ?></br>
Footer
application/controllers/welcome.php
<?php
class Welcome extends CI_Controller
{
public function index()
{
$this->load->config('template');
$this->load->library('template');
$this->template->load('welcome', array('view' => 'data'));
}
}
I usually put the config/library files on autoload, and you can use anytime $this->template->set_template('other_template'); to use another one :)
Hope it helps.
I've used the following setup in a CodeIgniter project:
The different templates along with stylesheets and images are in the following folder:
/templates/1/header.php
/templates/1/footer.php
/templates/1/images/*
/templates/1/style/*
/templates/2/header.php
/templates/2/footer.php
/templates/2/images/*
/templates/2/style/*
In your Controllers determine which template you want to load and pass the path to that template as a variable ( templatepath in this case ) to your View files. Inside the view files you do the following:
<?php include($templatepath.'/header.php'); ?>
at the top and
<?php include($templatepath.'/footer.php'); ?>
at the bottom.
Let's say I have a class...
class A {
private $action;
private $includes;
public function __construct($action, $file) {
//assign fields
}
public function includeFile()
include_once($this->file);
}
$a = new A('foo.process.php', 'somefile.php');
$a->includeFile();
As you can see, includeFile() calls the include from within the function, therefore once the external file is included, it should technically be inside of the function from my understanding.
After I've done that, let's look at the file included, which is somefile.php, which calls the field like so.
<form action=<?=$this->action;?> method="post" name="someForm">
<!--moar markup here-->
</form>
When I try to do this, I receive an error. Yet, in a CMS like Joomla I see this accomplished all the time. How is this possible?
Update
Here's the error I get.
Fatal error: Using $this when not in object context in /var/www/form/form.process.php on line 8
Update 2
Here's my code:
class EditForm implements ISave{
private $formName;
private $adData;
private $photoData;
private $urlData;
private $includes;
public function __construct(AdData $adData, PhotoData $photoData, UrlData $urlData, $includes) {
$this->formName = 'pageOne';
$this->adData = $adData;
$this->photoData = $photoData;
$this->urlData = $urlData;
$this->includes = $includes;
}
public function saveData() {
$this->adData->saveData();
$this->photoData->saveData();
}
public function includeFiles() {
if (is_array($this->includes)) {
foreach($this->includes as $file) {
include_once($file);
}
} else {
include_once($this->includes);
}
}
public function populateCategories($parent) {
$categories = $this->getCategories($parent);
$this->printCategories($categories);
}
public function populateCountries() {
$countries = $this->getCountries();
$this->printCountries($countries);
}
public function populateSubCategories() {
//TODO
}
private function getCategories($parent) {
$db = patentionConnect();
$query =
"SELECT * FROM `jos_adsmanager_categories`
WHERE `parent` = :parent";
$result = $db->fetchAll(
$query,
array(
new PQO(':parent', $parent)
)
);
return $result;
}
private function getCountries() {
$db = patentionConnect();
$query =
"SELECT `fieldtitle` FROM `jos_adsmanager_field_values`
WHERE fieldid = :id";
$result = $db->fetchAll(
$query,
array(
new PQO(':id', 29)
)
);
return $result;
}
private function printCountries(array $countries) {
foreach($countries as $row) {
?>
<option value=<?=$row['fieldtitle'];?> >
<?=$row['fieldtitle'];?>
</option>
<?php
}
}
private function printCategories(array $categories) {
foreach($categories as $key => $row){
?>
<option value=<?=$row['id'];?>>
<?=$row['name'];?>
</option>
<?php
}
}
}
And the include call (which exists in the same file):
$template = new EditForm(
new AdData(),
new PhotoData(),
new UrlData($Itemid),
array(
'form.php',
'form.process.php'
)
);
$template->includeFiles();
And the main file which is included...
if ($this->formName == "pageOne") {
$this->adData->addData('category', $_POST['category']);
$this->adData->addData('subcategory', $_POST['subcategory']);
} else if ($this->formName == "pageTwo") {
$this->adData->addData('ad_Website', $_POST['ad_Website']);
$this->adData->addData('ad_Patent', $_POST['ad_Patent']);
$this->adData->addData('ad_Address', $_POST['ad_Address']);
$this->adData->addData('email', $_POST['email']);
$this->adData->addData('hide_email', $_POST['hide_email']);
$this->adData->addData('ad_phone', $_POST['ad_phone']);
$this->adData->addData('ad_Protection', $_POST['ad_Protection']);
$this->adData->addData('ad_Number', $_POST['ad_Number']);
$this->adData->addData('ad_Country', $_POST['ad_Country']);
$this->adData->addData('ad_issuedate', $_POST['issuedate'] . '/' . $_POST['issuemonth'] . '/' . $_POST['issueyear']);
} else if ($this->formName == "pageThree") {
$this->adData->addData('name', $_POST['name']);
$this->adData->addData('ad_Background', $_POST['ad_Background']);
$this->adData->addData('ad_opeartion', $_POST['ad_operation']);
$this->adData->addData('ad_advlimit', $_POST['ad_advlimit']);
$this->adData->addData('ad_status', $_POST['ad_status']);
$this->adData->addData('ad_addinfo', $_POST['ad_addinfo']);
$this->adData->addData('ad_description', $_POST['ad_description']);
$this->adData->addData('tags', $_POST['tags']);
$this->adData->addData('videolink', $_POST['videolink']);
} else if ($this->formName == "pageFour") {
foreach($_POST['jos_photos'] as $photo) {
$this->photoData->addData(
array(
'title' => $photo['title'],
'url' => $photo['url'],
'ad_id' => $this->photoData->__get('ad_id'),
'userid' => $this->photoData->__get('userid')
)
);
}
}
Update
Strange: while the error itself hadn't been quite related to what the problem was, I found that it was simply an undefined field which I hadn't implemented.
Consider this thread solved. To those who replied, I certainly appreciate it regardless.
This should work. Are you sure you're doing the include from a non-static method that's part of the class (class A in your example)? Can you post the exact code you're using?
Edit: As general advice for problems like this, see if you can trim down the code so the problem is reproducible in a short, simple example that anyone could easily copy/paste to reproduce the exact error. The majority of the time, you'll figure out the answer yourself in the process of trying to simplify. And if you don't, it will make it much easier for others to help you debug.