I'm new to the MVC pattern but have been trying to grasp it, for example by reading the documentation for the CakePHP framework that I want to try out. However, now I have stumbled upon a scenario that I'm not really sure how to handle.
The web site I'm working on consists of nine fixed pages, that is, there will never exist any other page than those. Each page contains something specific, like the Guest book page holds guest book notes. However, in addition, every page holds a small news box and a short fact box that an admin should be able to edit. From my point of view, those should be considered as models, e.g. NewsPost and ShortFact with belonging controls NewsPostController and ShortFactController. Notice that they are completely unrelated to each other.
Now, my question is, how do I create a single view (web page) containing the guest book notes as well as the news post box and the short fact? Do I:
Set up a unique controller GuestBookController (with an index() action) for the guest book, so that visiting www.domain.com/guest_book lets the index action fetch the latest news post and a random short fact?
Put static pages in /pages/ and in let the PagesController do the fetching?
< Please fill in the proper way here. >
Thanks in advance!
It sounds like you need to look into elements, or else you may be able to embed this into the layout - but its neater to use an element if you ask me, keep the things separate.
http://book.cakephp.org/2.0/en/views.html#elements
These allow you to have create small views that you are able to embed into other views.
You may also need to put some logic into the AppController (remember all other controllers extend the app controller) to load the data required for these views. The beforeRender function should be useful for this - its one of the hook functions cakephp provides, so if you define it on a controller, its always called after the action is finished before the view is rendered.
Something like this in your AppController should help:
function beforeRender() {
$this->dostuff();
}
function doStuff() {
// do what you need to do here - eg: load some data.
$shortfacts = $this->ShortFact->findAll();
$news = $this->NewsPost->findAll();
// news and shortfacts will be available within the $shortfacts and $news variables in the view.
$this->set('shortfacts', $shortfacts);
$this->set('news', $news);
}
If there are models you need in the app controller for use within this doStuff method, then you need to define them within uses at the top of the AppController
class AppController {
var $uses = array('NewsPost', 'ShortFact');
}
Related
I have code that I want to run on every page load, such as looking up menu items, looking up the users details etc. These will be displayed on partial views that make up the main view.
Where do I place this code so that it can fill my partial views with each page load? I know I can just add the code to the top of the partial view itself, but this doesn't really follow the MVC pattern.
Is there a function that is always called that I can hook into in my base controller?
You can create a base viewmodel for the repeated code and make other viewmodels inherit from it.
...such as looking up menu items, looking up the users details etc
You're a bit unclear about the type of information you want to load: in case the info is a view-component then indeed you should create a base-view and inherit from it or include it (composition) in any other view.
But, in case it is "user-information" - the data should live in a model-component that again, may live as "base-model" object that is included in other model components.
The following code is in my FrontController. The run method should call a controller action which belongs to a given url. For example http://localhost/admin/index should point to AdminController and indexAction.
This works already, but what's the best way to call additional controller actions, for example a action for building a navigation of my site or a aside box (is not in the main section of the site) with some information. A navigation is needed at every request, so this would be no problem to implement, but when I have to call some actions which depends on the main action, how to structure this?
My first approach was to call other controller actions in two methods like runBeforeMainController or runAfterMainController. A global config holds the info for main controllers which sub controller (actions) needs to be called before or after the main controllers call.
My second approach was to think about a hook / event system. But I didn't come to good theoretical solutions. Do you have some tips or suggestions for this approach?
// in FrontController
public function run() {
$strController = static::getControllerNameFromUrl();
$strAction = static::getActionNameFromUrl();
// call actions before main controller
$this->template->main = $this->callMainControllerAction($strController, $strAction);
// call actions after main controller
}
I think HMVC is what you're looking for. The H stands for hierarchical. Basically you are using multiple mvc-constructs. Your site gets more modular and one request may result in different actions.
Afaik there are already some PHP frameworks using this approach.
I'm new to Zend and PHP and I'm getting ready to start work on a portal type application that will house multiple internal applications. I've already setup Zend_Auth and can now login via Active Directory.
We've been discussing using Zend_Acl to setup resources, one for each application within the portal. On the surface Zend_Acl seems like it would handle what we need for authorization and hierarchical access to resources.
After some research I've found that it's common to combine Zend_Acl with Zend_Navigation but there are sometimes issues with this.
What has been requested is that apart from* utilizing a front controller plugin to check resource access/privileges on each request, that we instead control the elements shown in the view (HTML) to the user. For example if user 'Bob' doesn't have access to the blog application, we don't want Bob to see that on his nav menu.
To me, introducing all this logic and if checks in the views is wrong; I think they should remain as stupid as possible. Is there a better way of handling this? Conditionally showing or hiding elements based on user role in your view code feels wrong to me.
If you want to remove the logic from the view, I would suggest using view helpers. That way you can abstract the ACL logic away from the view.
In your controler you would need to pass the ACL object to the view for use:-
$this->view->acl = $acl;//instance of Zend_Acl
Then you have a view helper for rendering some element:-
class Zend_View_Helper_SomeElement extends Zend_View_Helper_Abstract
{
public function someElement()
{
$html = '';
if($this->view->acl->isAllowed('guest', null, 'view'){
$html .= "<div>Top secret content</div>\n";
}
return $html;
}
}
Then your view is as simple as:-
echo $this->someElement();
That keeps your view simple and easy to read, while your logic is nicely hidden. Not ideal, but in your situation, I think this is the route I would take.
Your view helper can, of course, be made a bit more general purpose than this by passing in parameters.
I've just started reading up on CakePHP and everything is going pretty good so far, though I have a query on the best way to do the following:
I have a "User" model and a "UsersController" controller.
I currently have a "home" page which is controlled by the home_controller.php (obviously). The home page contains a registration for for a user.
The Question
When the form is posted from the home page, I need to access the User model (from the home controller).
What is the best practice for this task?
If I understand the situation correctly, I would post the form to some function in users controller. Then this function would save the data, or log in, or whatever. Finally make redirect back to home for example.
you can easily share one model across many controllers
var $uses = array('ModelName');
I do that with User Model and
Account Controller (Login, Register, ...)
Members Controller (Search, Listing, Profile, ...)
Overview Controller (Start Page, Home, ...)
for example. they all share the User Model.
I currently have a "home" page which is controlled by the home_controller.php (obviously) What other methods do you have in home_controller, other than index? And in Cake convention, the controller is plural, so: users, categories... Most likely, you are not aware of pages_controller and routing in Cake.
Anyway, yes, you can make a post to any controller (or even to another domain) from any page, just like any regular HTML page. echo $this->Form->create('User', array('controller'=>'users','action' => 'register')); You can read more here: http://book.cakephp.org/view/1384/Creating-Forms
In Zend Framework, I have a common use case where I need to propagate the same information in the top section of a view across a particular controller.
For example, if I have a "Book" controller, I want to display the summary book information at the top of the page, and have a tabbed interface below the book to display comments, detailed info, etc. Each tab is an action in the books controller. What is the recommended way to propagate the summary information across the views in the controller such that:
I am not continually fetching the summary book information in each action.
I am not repeating information in my views.
I though of using a Zend View Helper, a placeholder, or the action helper ($this->action...) from within the view.
Any suggestions?
Sounds like you'd want to fetch the book information in an init() method on the controller:
class MyController extends Zend_Controller_Action
{
protected $_book;
public function init()
{
// get the book data/model, etc
$book = $this->_getBook();
// if necessary, store the book for use in the actions
$this->_book = $book;
// store the book in the view
$this->view->book = $book;
}
}
If an action only renders the book info, then you can probably get away with empty action methods, letting the view scripts do their thing.
The only downside to this is that it gets the book data on every action. So if there are some actions that do not require the book data, then you'd be eating the overhead of fetching it.
I would load the tabs' contents dynamically (should be easy to integrate with your current solution via the action helper AjaxContent. Just load the action's response into your tab container.
If you decide to stick with a non-ajax solution, the code is forced to be repetitive since you need the same piece information on more than one page. A partial should be better suited for your needs since a view helper performs some kind of logic (or proxies for logic) while you only need it for presentation & markup.
The information fetched should not be that hard on your system, assuming you are using some smart cache method (perhaps one cache entry for each section/tab).