zend : use same index for different controllers? - php

I'm just learning Zend here:
I have different controllers for different departments to display similar but different information.
Can I use the same index file? The data that is different is determined inside the controller, so otherwise I'm just going to be copying and pasting the same html file...

class BazBatController extends AbstractActionController
{
public function doSomethingCrazyAction()
{
$view = new ViewModel(array(
'message' => 'Hello world',
));
$view->setTemplate('foo/baz-bat/do-something-crazy');
return $view;
}
}
This sets a “message” variable in the View Model, and sets the template name “foo/baz-bat/do-something-crazy”. The View Model is then returned.

Yes, you can reuse templates. Your templates can be structured however you like, so create a generic index.phtml somewhere that makes sense to you, and then in your controller actions just tell the view model to use that template instead of what it does by default:
class ShoesController extends AbstractActionController
{
public function indexAction()
{
$view = new ViewModel();
$view->setTemplate('some/shared/index.phtml');
return $view;
}
}
and do the same in your PantsController.

Related

Routing independant controllers and models in fat free framework

I am trying to create Main site navigation, Sidebar Navigation and Footer navigation in Fat Free environment. I am just starting to work with frameworks especially with MVC type.
My problem, since my navigation will be almost on every page of the website, I was thinking about creating separate controller and model to handle all this staff, but not sure how it would work without making routing?
Also, I am not sure how to handle join in the model, I could not find any information about this online at all.
Here is my current Category Controller
class Categories extends DB\SQL\Mapper
{
public function __construct(DB\SQL $db)
{
parent::__construct($db, 'categories');
}
public function all()
{
$this->load();
return $this->query;
}
public function getByID($id)
{
$this->load(array('id=?', $id));
return $this->query;
}
public function getBySlug($category_slug)
{
$this->load(array('category_slug=?', $category_slug));
return $this->query;
}
public function add()
{
$this->copyfrom('POST');
$this->save();
}
public function edit($id)
{
$this->load(array('id=?', $id));
$this->copyfrom('POST');
$this->update();
}
public function delete($id)
{
$this->load(array('id=?', $id));
$this->erase();
}
}
any ideas or pointers will help me to go a long way.
Thanks in advance
I don't know if understood what your issue is, but if you want to make the categories available for all methods in a Controller, you could use the beforeRoute() method:
class TestController extends MainController {
// runs before routing
// if another controller extends TestController and also has a
// beforeRoute, this will be overriden
function beforeRoute() {
// Load Categories
$categories = new Categories($this->db);
// Assiging ->all() to variable makes the method return an array of all results
$categoriesArray = $categories->all();
// Set an array in the hive for template use
$this->f3->set('categories', $categoriesArray );
// Clear the instance
$categories->reset();
}
function renderPage() {
// the 'categories' hive variable is available because beforeRoute has been run
// Set the page title from the dictionary file
$this->f3->set('pageTitle', $this->f3->get('DICT_'.'page_whatever') );
// Render the View
$this->f3->set('view','page.whatever.htm');
$template=\Template::instance();
echo $template->render('layout.sidebar.htm');
}
// End of Controller
}
And of course, in the template:
<repeat group="#categories" value="#category">
<li>
{{ #category.label }}
</li>
</repeat>
ps: You might be using $f3 instead of $this->f3 (and the same for $db)

Pass Database Values to Layout

In my Zend application there is a layout file used in multiple modules. Now i need to retrieve data from database (table gateway) and display on layout. Then it should appear across all the modules.
How do i achieve that ?
Ex -
<?php echo $user_name; ?>
Value for $user_name should be taken from database and pass to layout file.
you dont have to set it in every controller. You could just attach it to a layout variable in your module.php.
public function onBootstrap(MvcEvent $e)
{
$sm = $e->getApplication()->getServiceManager();
$tableWhatever = $sm->get('tableWhatever');
$viewModel = $e->getApplication()->getMvcEvent()->getViewModel();
$viewModel->userName = $tableWhatever->getUserName();
}
Depending on the zf2 version you may have to access the variable in your layout like so:
$this->layout()->userName;
You also have the possibility to extend the AbstractActionController and add the layout variables trough that. I usually just go with the quick onBootstrap method though.
I believe, in Zend, your controller(s) will want:
$this->view->assign('variableName', 'variableValue');
And in your view(s), you will want:
$this->variableName;
You could use Zend Plugin to achieve something like that, like:
class MyPlugin extends Zend_Controller_Plugin_Abstract {
public function preDispatch(Zend_Controller_Request_Abstract $request) {
// Get instance
$layout = Zend_Layout::getMvcInstance();
$view = $layout->getView();
$view->user_name = 'your_username';
}
}
and register your plugin in frontController:
Zend_Controller_Front::getInstance()->registerPlugin(new MyPlugin());
then in layout , you could do:
<?php echo $this->user_name; ?>

Laravel 4.1 - Controller throw error when I try to load view with layout

I'm trying to load a blade view with layout, but I get this error:
"Attempt to assign property of non-object"
The structure is the following:
Route:
Route::pattern('controller', '\w+');
Route::get('{controller}', function($controller) {
$controllerClass = $controller.'Controller';
App::make($controllerClass)->index();
});
Controller:
class PricesController extends BaseController {
protected $layout = 'layouts.master';
public function index()
{
$this->layout->content = View::make('prices.index');
}
}
The debug says the issue is at line $this->layout->content = View::make('prices.index');
The views are fine... I have layouts folder with master.blade.php and I also have prices folder with index.blade.php.
The content section is exists as well with #stop and the #yield is there in the layout.
In the BaseController there is the setupLayout method:
protected function setupLayout()
{
if ( ! is_null($this->layout))
{
$this->layout = View::make($this->layout);
}
}
What is the problem? Why I get that exception?
Thank you!
I know I helped you in the #laravel irc channel but there are 3 things here for any others with this problem.
This is not a good use of route files. Controller implicit routing is hard to maintain if your app gets larger. Consider using Route::resource instead if you're just trying to save a few lines of code. But I'll give you the benefit of the doubt.
You'll want to use the nest method for your layout, i.e. $this->layout->nest('content', 'prices.index');
The setupLayout() function is not being called because you are calling index() directly on the object. This is not how Laravel normally processes controllers.
I'm not going to walk through the entire routing process but if you look at vendors/laravel/framework/src/Illuminate/Routing/ControllerDisplatcher.php on line 89 you will see:
protected function call($instance, $route, $method)
{
$parameters = $route->parametersWithoutNulls();
return $instance->callAction($method, $parameters);
}
Let's look at vendors/laravel/framework/src/Illuminate/Routing/Controller.php on line 227 and you will see:
public function callAction($method, $parameters)
{
$this->setupLayout();
$response = call_user_func_array(array($this, $method), $parameters);
... irrelevant stuff omitted ...
}
These reason I show these things is show the magic Laravel is doing behind the scenes.
Basically you are skipping that magic and just calling PricesController->index() directly instead of going through the router. This is why setupLayout is never being called and you will get an exception because there is no $this->layout object yet created.

GET and POST functions in PHP / CodeIgniter

I like MVC (a lot), and I am trying to teach myself a framework of MVC architecture in all the major web languages of today.
I am currently on CodeIgniter and PHP. I searched online for a way to make the same function behave different for a POST and GET but couldn't find anything. Does CodeIgniter have this feature?
If you've used Ruby On Rails or ASP.NET MVC you'll know what I'm talking about, in them frameworks we can do this:
[GET]
public ActionResult Edit(int Id)
{
// logic here for GET
}
[POST]
public ActionResult Edit(EntityX EX)
{
// logic here for POST
}
I am so used to this, that I am finding it hard wrapping my head around how to get the same smooth functionality without that useful ability.
Am I missing something? How can I achieve the same thing in CodeIgniter?
Thanks
Am I missing something? How can I achieve the same thing in
CodeIgniter?
if you want to learn how to truly approach MVC in PHP, you can learn it from Tom Butler articles
CodeIgniter implements Model-View-Presenter pattern, not MVC (even if it says so). If you want to implement a truly MVC-like application, you're on the wrong track.
In MVP:
View can be a class or a html template. View should never be aware of a Model.
View should never contain business logic
A Presenter is just a glue between a View and the Model. Its also responsible for generating output.
Note: A model should never be singular class. Its a number of classes. I'll call it as "Model" just for demonstration.
So it looks like as:
class Presenter
{
public function __construct(Model $model, View $view)
{
$this->model = $model;
$this->view = $view;
}
public function indexAction()
{
$data = $this->model->fetchSomeData();
$this->view->setSomeData($data);
echo $this->view->render();
}
}
In MVC:
Views are not HTML templates, but classes which are responsible for presentation logic
A View has direct access to a Model
A Controller should not generate a response, but change model variables (i.e assign vars from $_GET or $_POST
A controller should not be aware of a view
For example,
class View
{
public function __construct(Model $model)
{
$this->model = $model;
}
public function render()
{
ob_start();
$vars = $this->model->fetchSomeStuff();
extract($vars);
require('/template.phtml');
return ob_get_clean();
}
}
class Controller
{
public function __construct(Model $model)
{
$this->model = $model;
}
public function indexAction()
{
$this->model->setVars($_POST); // or something like that
}
}
$model = new Model();
$view = new View($model);
$controller = new Controller($model);
$controller->indexAction();
echo $view->render();
The parameters only allow you to retrieve GET variables. If you want to get the POST variables, you need to use the Input library which is automatically loaded by CodeIgniter:
$this->input->post('data');
So, in your case, it would be:
public function edit($id = -1)
{
if($id >= 0 && is_numeric($id))
{
// logic here for GET using $id
}
else if($id === -1 && $this->input->post('id') !== false)
{
// logic here for POST using $this->input->post('id')
}
}
Note that you can also use this library to obtain GET, COOKIE and SERVER variables:
$this->input->get('data');
$this->input->server('data');
$this->input->cookie('data');

Help getting Model into my Controllers, with MVC

I have been working on my own library/framework for the learning experience for a while. MVC is one of those things that took me a while to really understand but I do finally "Get it".
Below is some sample code for a basic MVC setup in PHP. I think I am in the right direction so far, where I need a little help is down in the "Example controller" near the bottom, you will see where I can create a view, I just need to figure out how to best get my data from a model file into that controller class. Please help with example code if you can, hopefully I am making sense.
Also I am welcome to any comments/suggestions on any of the code
Abstract Controller class...
/**
* MVC Example Project
*/
/**
* Extend this class with your Controllers
* Reference to the model wrapper / loader functions via $this->model
* Reference to the view functions via $this->view
*/
abstract class Core_Controller {
protected $view;
protected $model;
function __construct($dependencyContainer){
$this->view = new Core_View();
//$this->view = $dependencyContainer->get(view);
}
}
Abstract Model class...
/**
* Extend this class with your models and reference to the database object via $this->$db
*/
abstract class Core_Model {
protected $db;
protected $session;
function __construct($dependencyContainer) {
$this->db = $dependencyContainer->get(database);
$this->session = $dependencyContainer->get(session);
}
}
View class, might make it abstract as well...
class Core_View {
protected $data;
# Load a view file (views/$view.php);
# $param data this gets extracted and be thus be used inside the view
# When loading another view from inside the view file the data is 'cached' so you
# don't have to pass them again
public function load($view,$data = null) {
if($data) {
$this->data = $data;
extract($data);
} elseif($this->data != null) {
extract($this->data);
}
require(APP_PATH . "Views/$view.php");
}
public function set($data = null) {
if($data) {
$this->data = $data;
extract($data);
} elseif($this->data != null) {
extract($this->data);
}
}
}
Example putting it together...
/**
* Example Controller
*/
class User_Controller extends Core_Controller {
public function profile()
{
$profileData = array();
$profileData = //GET from Model
$this->view->load('userProfile', $profileData);
}
}
?>
My suggestion is not to tie view and model to the controller at all. Let them be instantiable from controller code, just like any other classes. You can then get the model data (and pass it to the view) in standard object oriented way.
Will you use a Data access layer (DAL) / Object-relational mapping (ORM)? Take a look at Zend_Db, Doctrine or Propel
I'd say that you're missing the part of the application that manipulate your models. It could be your controller, but isn't a good practice. So we need a model mapper.
The best way to get model data from your controller is simply calling it. But generally we use a kind of "pointer" which knows how to populate your object model. This pointer is called "Mappers" (Data Mapper Pattern):
$MyModelMapper = new MyModelMapper();
$Profile = $MyModelMapper->getProfileById($id); // return Core_Model.
This function will perform a database query and will populate one specific model with the data. You could also get an array of objects for a "list" action for example.
Then you'll pass this model to your view.
I think you should take a look at the Zend Framewok quick start. It will give you some ideas.
See this question too: What's the difference between DAO and Data Mapper

Categories