KSmarty is a Kohana module meant to integrate Smarty with Kohana. I'm trying to migrate my current project (already using Smarty) to using Kohana.
I'm trying to get KSmarty set up, but I'm having difficulties getting the templates to work. This is the "hello world" example from KSmarty:
application/classes/Controller/Welcome.php
<?php defined('SYSPATH') or die('No direct script access.');
class Controller_Welcome extends Controller_Template
{
public $template = 'welcome';
public function action_index()
{
// Assign a value to the variable 'intro'
$this->template->intro = 'Hello world!';
// Create a nested view by loading a different template
$this->template->content = View::factory('content');
}
}
// End Welcome
application/views/welcome.tpl
<html>
<body>
<h1>{$intro}</h1>
<p>
{$content}
</p>
</body>
</html>
application/views/content.tpl
Yes, this works!
However, for me, the controller/view combo does not work as expected. Here are the variants of action_index() that I've tried:
public function action_index()
{
echo 'foo';
}
// Output: foo
public function action_index()
{
// Assign a value to the variable 'intro'
$this->template->intro = 'Hello world!';
// Create a nested view by loading a different template
$this->template->content = View::factory('content');
}
// No output
// No error in apache log, php log, or kohana log
public function action_index()
{
Ksmarty::instance()->assign(array(
'intro' => 'Hello world!',
'content' => APPPATH.'/views/content.tpl'
// Note: also changed {$content} in template to {include $content}
));
Ksmarty::instance()->display(APPPATH.'/views/welcome.tpl');
}
// Expected HTML output
I could simply use Ksmarty::instance() like this and get my website working, but this isn't how the Kohana Views system was designed, and it feels like a kludge, especially since the KSmarty example matches up with Kohana's use of Views.
I'm pulling my hair out trying to pin this one down, which is impressive considering the amount of hair-pulling Kohana gave me on the initial install. What am I doing wrong?
Oh, I have make two changes to KSmarty to reach this point:
All instances of Kohana::config('smarty') replaced with Kohana::$config->load('smarty'); as far as I can tell, this is a matter of a version change in Kohana.
Commented out $s->security = Kohana::$config->load('smarty')->security;; as far as I can tell, this is a matter of a version change in Smarty, and KSmarty is configured to FALSE anyway.
Adding echo $this->template; to the end of the view works. It's not in the Kohana nor the KSmarty documentation/examples, but it's close enough to satisfy me. If anyone else ever comes up with an answer that solves the problem without echo, I'll mark that answer as accepted, but until that time, I have a solution.
<?php defined('SYSPATH') or die('No direct script access');
class Controller_Welcome extends Controller_Template
{
public $template = 'welcome';
public function action_index()
{
// Assign a value to the variable 'intro'
$this->template->intro = 'Hello world!';
// Create a nested view by loading a different template
$this->template->content = View::factory('content');
// Output the view
echo $this->template;
}
}
// End Welcome
Related
I started working on a platform on CodeIgniter thanks to my work. The platform was started since before, so i just took the project. The thing is that i hadn't work with CI, so i just had a fast tutorial, and started developing based on how the platform was built. Now, to start, i decided to make a new page to to put a list of objects and understand a little how the PHP communicated with the HTML. The problem is that, when i go to the URL that i defined on routes.php, it gives an error "Requested resource does not exist", and i don't know what i'm doing wrong, while something similar works on other modules of the platform.
The files i'm using are:
list.php
// stuff
<?php if (has_access('agroindustrias')): ?>
<li class="<?php get_li_class('agroindustrias', $active); ?>" >
Agroindustrias
</li>
<?php endif ?>
// stuff
agroindustria.php
<?php
if (!defined('BASEPATH')) {
exit('No direct script access allowed');
}
class Agroindustria extends MY_Controller
{
public function __construct()
{
parent::__construct();
$this->load->model('agroindustria_model', 'agroindustria');
}
public function index($offset = 0)
{
$data['links'] = $this->paginate($this->agroindustria, 'agroindustrias', $offset);
$data['permisos'] = $this->getPermissions('usuario');
$data['active'] = 'usuarios';
$data['agroindustrias'] = $this->agroindustria->limit($this->limit, $offset)->get_all();
$data['submenu'] = $this->load->view('administracion/menu', $data, true);
$this->template->write_view('content', 'administracion/agroindustrias/list', $data);
$this->template->render();
}
}
routes.php(Updated with all the file, only the one before "reportes" doesn't work)
$route['administracion/agroindustria'] = 'agroindustria/index';
My URL is: http://localhost/work/administracion/agroindustria
The other controllers works with something similar, reason that i don't know what i'm doing wrong, if i still need to add something to another file, or if something that i wrote is wrong. Thanks in advance.
After the things that #Antony told me to check, i was able to find the error, it wasn't actually an error, just that the people before worked very much in the platform, that i did not undertand the mothodology to add new modules to the platform. All that i needed to do was register the new module, and the platform added the new URL as i wanted. Thanks Antony for your help!
1st of all rename agroindustria.php to Agroindustria.php if 1st letter not in upper case
if you are using method like this
public function index($offset = 0){
....
....
....
}
then you need to change routes like
$route['administracion/agroindustria/(:num)'] = 'agroindustria/index/$1';
and url
http://localhost/work/administracion/agroindustria/0
The best solution is change in your controller
//if offset not change
public function index(){
$offset = 0;
....
....
....
}
//if your offset depend upon 3rd segments of URL then
public function index(){
$offset = if($this->uri->segment(3)) ? $this->uri->segment(3) : 0;
....
....
....
}
I have an old project I'm working on using Slim version 2. I can not upgrade to 3.
I'm trying to integrate twig into slim 2 while also keeping the old default slim2 renderer.
Currently I have this.
class TwigView extends \Slim\View
{
public function rendertwig($template,$data = array()){
global $twig;
$twigResults = $twig->render($template,array('test' => '1'));
$data = array_merge($this->data->all(), $data);
return $this->render($twigResults, $data);
}
}
$view = new TwigView();
$config['view'] = $view; //#JA - This command overides the default render method.
//#JA - Intialize Slim
$app = new \Slim\Slim($config);
The idea is that I would call this saying $app->view->rendertwig('file.twig') when I need to render the twig templates and use $app->render('template.php') for all the other templates that use the default slim2 method of templating.
However, I get an error because in my rendertwig function $this->render() function requires a template name for the first parameter. Is there a way I can render directly the results from twig into the slim engine without needing a template file?
I'm aware this is bad form to have two templating engines but eventually I will switch everything to Twig but I need this as a temporary solution till I can patch everything over.
When I inspected slim's view object it has this defined as its render method which will explain the issue.
protected function render($template, $data = null)
{
$templatePathname = $this->getTemplatePathname($template);
if (!is_file($templatePathname)) {
throw new \RuntimeException("View cannot render `$template` because the template does not exist");
}
$data = array_merge($this->data->all(), (array) $data);
extract($data);
ob_start();
require $templatePathname;
return ob_get_clean();
}
I don't know if this is bad form but I did this as a temporary solution.
class TwigView extends \Slim\View
{
public function rendertwig($template,$data = array()){
global $twig;
$twigResults = $twig->render($template,array('test' => '1'));
echo $twigResults;
}
}
I saw that all the render method did was just require the template so I figured its safe to just echo the results from the twig templating engine? This seemed to work from my test.
I recently implemented the following MVC code using this tiny mvc boilerplate.
I did not want to use Zend or Symfony as I only require a small structure but i really need to expend this one slightly.
I am new to PHP so wondered if anyone has used this or knows how i go about adding another View. I have got the link version working which i use to load my layout but would like to add a Content section within this layout which is able to call other pages.
Any help with this would be great!
Gods below .. that video is horrible.
In that existing example, if you want to add another "view" (which is no really what view is), you will need another method in the controller:
class Controller
{
// -- snip --
// you need to change the constructor too
public function __construct()
{
$this->load = new Load;
$this->model = new Model;
}
// -- snip --
public function gallery()
{
$list = $this->model->get_urls();
if ( count($list) > 0 )
{
$this->load->view('gallery.php' , $list);
}
else
{
$this->load->view('error.php', array(
'source' => 'gallery',
'reason' => 'empty'
));
}
}
// -- snip --
}
And you also would need to change the tinyMvc.php file:
$c = new Controller;
$action = 'home';
if ( isset( $_GET['page']))
{
$action = $_GET['page'];
}
if ( method_exists( $c, $action) )
{
$c->{$action}();
}
else
{
echo 'no such action !';
}
Anyway. Whole that "tutorial" uses the terms of MVC, that isn't really whats made there. His "view" is actually just a simple template. Which is not completely a thing to learn how to do for a beginner, but his implementation sucked too .. If you want to learn how to make simple native php templates, you might find this article quite useful.
I have to display different views for mobile devices and I want to provide a simple JSON-API.
I wrote a little module for the Kohana Framework which loads different views depending on some circumstances, which should help me in this case: https://github.com/ClaudioAlbertin/Kohana-View-Factory
However, I'm not very happy with this solution because I can't set different assets for different device-types. Also, when I'd output JSON with a JSON-view, it's still wrapped in all the HTML-templates.
Now, I'm looking for a better solution. How do you handle different output formats or device-types in your MVC-applications?
I had an idea: just split the controller into two controllers: a data-controller and an output-controller.
The data-controller gets and sets data with help of the models, does
all the validating etc. It gets the data from the models and write it to a data-object
which is later passed to the view.
The output-controller loads the views and give them the data-object from the data-controller. There is an output-controller for each format or device-type: an output-controller for mobile-devices could load the mobile-views and add all the mobile-versions of stylesheets and scripts. A JSON-output-controller could load a view without all the html-template stuff and convert the data into JSON.
A little example:
<?php
class Controller_Data_User extends Controller_Data // Controller_Data defines a data-object $this->data
{
public function action_index()
{
$this->request->redirect('user/list');
}
public function action_list()
{
$this->data->users = ORM::factory('user')->find_all();
}
public function action_show($id)
{
$user = new Model_User((int) $id);
if (!$user->loaded()) {
throw new HTTP_Exception_404('User not found.');
}
$this->data->user = $user;
}
}
class Controller_Output_Desktop extends Controller_Output_HTML // Controller_Output_HTML loads a HTML-template
{
public function action_list($data)
{
$view = new View('user/list.desktop');
$view->set($data->as_array());
$this->template->body = $view;
}
public function action_show($data)
{
$view = new View('user/show.desktop');
$view->set($data->as_array());
$this->template->body = $view;
}
}
class Controller_Output_JSON extends Controller_Output // Controller_Output doesn't load a template
{
public function action_list($data)
{
$view = new View('user/list.json');
$view->users = json_encode($data->users->as_array());
$this->template = $view;
}
public function action_show($data)
{
$view = new View('user/show.json');
$view->user = json_encode($data->user);
$this->template = $view;
}
}
What do you think?
Hmm... From the 1st view it loooks strange, and somehow like fractal -- we are breaking on MVC one of our MVC -- C.
But why is this app returns so different results, based on point-of-entry (or device)?
The task of the controller is only to get the data and choose the view -- why do we need standalone logic for choosing something based on point-of-entry (device)?
I think these questions should be answered first. Somewhere could be some problem.
Also the cotroller should select only one view ideally, and dont' do "encode" or else with data, based on current output. I think all this should be in some kind of "layouts" or else. As data always the same and even different views should be the same -- only some aspects changes.
All,
I am studying some sample code given in my web dev class as an example of MVC (again, for the web). In this code, there's a system to navigate from the index.php page to the various controllers (which then call the Model and View modules), and then back into index.php.
I understand how the MVC works.
What I'm grappling with is the navigation mechanism. I am having difficulties understanding how all the pieces work together.
Could anyone take a look at the code below and tell me if this matches a well known method / pattern to deal with dynamic website navigation? (Maybe the Front Controller?) If it does, then my hope is that I can more easily do some more research on it.
Many thanks!
JDelage
Index.php
<?php
require_once("User.php");
session_start();
if (isset($_GET['action']))
$action= $_GET['action'];
else
$action="";
switch ($action) {
case 'login':
require_once('Login.php');
$command= new LoginControler();
break;
case 'logoff':
require_once('Logoff.php');
$command= new LogoffControler();
break;
// Several other cases
default:
require_once('Unknown.php');
$command= new UnknownControle();
}
$command->execute();
require_once('EntryMenu.php'); // Those are objects that represent both the
// menu label and the links.
$menu= array(
new EntryMenu("Login", "index.php", array("action" => "logon")),
new EntryMenu("Logoff", "index.php", array("action" => "logoff")),
new EntryMenu("Write", "index.php", array("action" => "write")),
new EntryMenu("Read", "index.php", array("action" => "read"))
);
if ($command->redirect) {
header('Location: ' . $command->redirect);
} else if ($command->page) {
include("ui/header.php");
include("ui/menu.php");
echo "<div class='content'>";
include("ui/". $command->page);
echo "</div>";
include("ui/footer.php");
}
?>
Controler.php
<?php
class Controler {
public $page= "problem.php";
function execute() {}
}
?>
LogoffControler.php
<?php
require_once('Controler.php');
class LogoffControler extends Controler {
function execute() {
$this->redirect= "index.php";
unset($_SESSION['user']);
}
}
?>
LoginControler.php
<?php
require_once('LoginModel.php'); // This manages the exchanges with the user db
require_once('Controler.php');
class ConnexionControle extends Controler {
public $page= "LoginForm.php";
function execute() {
// More code to deal with incorrectly filled login forms
$login = new LoginModel();
$login->loginUser($_POST['login'], $_POST['password']);
if ($login->userLogedIn()) {
$_SESSION['user']= $login->user;
$this->redirect= "index.php";
}
// More code to deal with invalid logins
}
}
?>
I am assuming you understand the controller part, and is asking about the switch..case statements. I haven't come across an official name for that yet,but most MVC frameworks for PHP (Kohana, CakePHP, CodeIgniter, Fat Free and etc.) calls that 'routing'. It's mapping of a URL to a controller.
Using a switch..case sets of statement is one of the easier ways. More sophisticated solutions use RegEx to match pre-defined URL patterns to resolve what controller to invoke, and what are its parameters (usually bundled as a 'request')
Other methods include using URL rewriting to come up with pretty urls, such as /articles/month/nov/article-id/3
which in 'ugly url form' is :
action=articles&month=nov&article-id=3
If you would like an easy-to-dissect verion of a MVC system you could try the 1kb PHP MVC which handles everything you are attempting in a much cleaner fashion. Though you might have to break up the code if you really want to read it as it is in compressed form.
With this system you simply place a controller in /classes/controller/ named somthing.php and you can then access it from the URL like http://site.com/something.
Loading Models is also easy and doesn't require any include or require calls.
class Controller_Something
{
public function index()
{
$model = new Model_User();
}
}