Today at work someone tried to convince me that:
{$obj->getTableInfo()}
is fine for smarty/mvc/templating because it is using an objects method. I argued that because it makes a call to the database it has no place being there and it should be in the controller (we don't actually use MVC). Am I right in my understanding of the logical separations that are used in MVC and generally in templating? Or is there something that I am missing?
You're right. He's wrong.
Database calls, no matter in what form, should live in the controller if you want to do MVC right.
Obviously people piss all over what it should be and do stuff like that, but it's not the correct way.
Well, there are no "official" rules or anything, but I think something like that belongs in the controller. I don't do anything in my view code except display variables, nothing more complex than an if or a foreach-type loop is allowed. Certainly not calling functions that access the database. That should all be loaded by the controller, the view should only decide whether it needs to display it or not.
Depends on its context and scope really.
Is $obj the controller or the model layer? That should answer whether or not it is valid in my opinion.
In response to reading the other answers.
The functions name in itself pertains it to being a simple getter method. It may make a call to the db through a controller layer. Which I would say is ok. Especially if it used some form of caching in memory. (ie the getter is the setter as you only want to cache it when it is used once.)
Related
First question on StackOverflow (I don't know if I'm doing this right, so sorry if I mess it up)
Background:
My controller has a method that list all actions in my app and plugins called getActions().
And I need to use getActions() in a Helper that overrides HtmlHelper->link() method, because the purpose of this method is return null if the link is forbidden by Acl, thus not rendering any link that would lead to a forbidden action.
Question
How to share this method? I'm doing this wrong?
Lib is the right way to go?
This doesn't seem right: In CakePHP, how do I call an AppController method from a helper?
Don't share the method, share its output. as mentioned in the link to the other question.
I assume that this data is static, meaning: if it will be called from any part in the application, it will return the same value.
Call the method in the controller, store its output in a view-variable or in the session, and write a helper that will access this information and do the acl logic.
It won't break the MVC and will avoid DRY.
The right place for the method is Lib, because its a general purpose method that is going to be used in differents places with differents objectives.
CakePHP's core has many examples of this approach like: CakeTime, CakeNumber and others.
Others examples could be seen in some of CakeDC plugins too.
IMHO #yossi was right about "assuming the data as static", but his approach of storing the data in Session just would make my code more confusing.
In my particular case I'm taking the Lib way. Thanks for the help.
I am working with Codeignitor 2.x and I was originally using controllers as modules (though not completely HMVC), in that I had a Top Level controller that would call other lower level controllers. My thinking was that because these lower level controllers were still interacting with the view, that they should remain controllers rather than models or drivers.
What I found, however, is that each instance of a controller also spawns a new instance of CI. So I would have 3 or 4 instances of CI running for each request. Ton of overhead, and also caused session issues.
I have since moved these lower level controllers into the library as drivers. They now capture the CI instance in the construct method, and make modifications to it. This makes it VERY nice to work with, and doesn't require the HMVC extension. The drivers are not externally callable either, so it allows me to funnel all requests through specific entry points.
My question is whether this is structurally correct. I have always held the notion that drivers should only modify the data they are provided through their method calls, but many of these drivers will pull information directly from GET and POST, and while they will not directly append to the View, they are often accessing view files, and passing the processed view to the CI instance for output.
[EDIT] A little more context:
One of the drivers I have created is essentially a user login driver called 'Access'. It makes calls to the 'User' model for create/login/logout methods. The driver uses the POST data to check the User model, then loads the correct view with errors and whatever is needed. The idea, being, with 2 lines, I can include this driver in any controller throughout the project, so there is a significant decrease in code redundancy. Again, I know that the drivers should be confined to their scope, however the driver does not modify anything outside it's scope, but simply returns the view it has created.
Is there another method to for doing this that is more inline with straight MVC?
I can't say whether it is right or wrong. But if I were you, I wouldn't do that. I'd probably refactor some of the code. I'd make sure that they don't grab and manipulate data directly from the $_GET or $_POST superglobals. Instead, pass in some data as arguments to a function call. This would make testing easier, since you don't have to simulate a GET or a POST request. While technically, you could just set the value for the superglobals manually from the code, but I'd not recommend doing that. Supplying data as arguments would be much better, especially if you want to write test cases that are to be executed subsequently. Plus, having the libraries interacting with the scopes beyond its own might introduce some hidden gotchas.
In my opinion, libraries are meant to be something like modules, where you can just drag and drop, and then use them without any hassle. If your code really needs to grab or manipulate values from $_GET or $_POST, maybe they are meant to be models instead. Also, you might want to think whether your code is actually a library or not. Ask yourself, will this code be useful outside this application? Or is it highly dependent and can only be useful for this particular app? If you say yes to the latter, then it's probably should be a model instead of a library. Last thing, you should leave the views to the controller. Just return the data you need from the library/model method then pass it to the view from the controller.
When trying to adhere to established best practices like avoiding singletons, registry, static properties and base controllers, how I can populate my layout(and partials used by the layout) with data that is only used by the layout and common across all actions?
The typical scenario is menu which is built on variable data, like an database. Keeping separation of concerns in mind, the views/layout should never talk to an backend directly, but rather be told what to contain.
Using a front controller plugin is simply not possible without using the singleton "feature" in Zend_Layout. The plugin only knows the request and response object, neither has access to controllers, views or the layout.
Zend's action helpers have init/preDispatch/postDispatch methods. One can add action helpers to the HelperBroker (ex. using the bootstrap) and these will be executed in the normal application flow.
Using the init-method to inject data into the view is not possible since it's trigged before the controller/view is ready. preDispatch/postDispatch is possible, but not perfect, since these methods are always triggered when executing a controller action.
That means that all uses of the Zend_Controller_Action::_forward() will also execute the preDispatch/postDispatch in all action helpers. This doesn't have any big implications for the code except speed, I really do not want to be setting a view (or an view helper) variable several times. One can code around this issue using some sort of $firstRun variable, but I really don't want to track this in my own code.
Another method is doing this in the bootstrap, but in my opinion it really does not belong there.
So, how can I populate my layout/view helper with data from the database, doing it only once and still keep a good separation of concerns?
I've followed the ActionHelper approach, setting the view variables on the preDispatch method. It was the most logical place, in my opinion. In addition, my projects weren't using Zend_Controller_Action::_forward(), so I didn't have any speed concerns about multiple triggering of the helper.
Hope that helps,
You could go with Action Helpers as stated in this answer (take a look at the question too, its pretty much similar to yours)
I'd use action helpers too. Just fill the view variables and display them using plain PHP/partials/render/viewHelper (depending on complexity).
Your problem with multiple runs using preDispatch could be solved using
if (!($this->view->myVar)) { // or array_key_exist or isset - depending on your use case
$this->view->myVar = $someModel->getSomeData();
}
Which is just fine IMO.
I've been working on creating my own MVC app in PHP and I've seen a lot of differing opinions online about how exactly this should be set up. Sure, I understand there seems to be a general "It's MVC, it is what you make of it" approach, but I'm running into 2 seemingly conflicting viewpoints.
A little background on my app: I'm using smarty as my presenter and an object-oriented approach. Seems simple enough, but I'm trying to figure out the ubiquitous "what is a model" question.
If I take a look at some tutorials and frameworks, they seem to view the model as strictly a class that inherits DAL methods from an abstract class, with a little bit extra defined in the class itself as your data needs differ from object to object. For example, I might see something like $productModel->get(5) that returns an array of 5 products from the database. So what if I need to query multiple models? Do I store all of the data in the controller or an array and pass that to the view? Then if I'm dynamically calling my controller, how can I persist the data unique to the controller necessary to render the view? This seems bad, especially because I then have to pass in things like "controllerName", "controllerData", and my View::render() method gets hugely bloated with parameters, unless I pass in the controller itself. Maybe I'm missing something here.
Let's say I want to make a login that queries a users table. Login is a model or a controller, depending on certain implementations I've seen online. Some implementations (I'll call this method 1) make a LoginController with method login() that might do a comparison of $_POST and what's returned from the user model instance $user->get(1) to see if a user is validated. Or maybe login() might be a method in a default controller. On the flipside, an implementation (implementation method 2) that resembles more of a Joomla approach would make a Login model and declare all of the actions inside of that. Then any data that needs to get assigned to the view would get returned from those methods. So login->login() would actually check post, see if there's a match, etc. Also the User model would probably be instantiated inside that model method.
My feelings about 1: The controller is fat. Additionally the controller is storing data pulled from models or passing in ten thousand variables. It doesn't seem to jibe with the idea that the model should be passing data to the view that the controller should be blind to. Also, let's say I want to wrap everything that is in a specific model handled by a specific controller in an outer template. I'd have to copy this template-setting code all across my controller functions that interface with this model. It seems grossly inefficient.
My feelings about 2: It doesn't make for having actions that aren't model methods. If I want to go to my site root, I have to make an index model or something that seems like overkill in order to have a model that passes data to the view. Also, this doesn't seem to be a very popular approach. However, I do like it more because I can just do View::render(mymodel->func()) and ensure that the data is going to be passed back just the way I like it without having to crap up my controller with code merging a thousand query results together.
I've waded through far too many religious arguments about this and want to know what you guys think.
I've built my own framework in the past too so I know what you're going through. I've heard the saying "build fat models" and I agree with that -- as long as the main goal is to return data. I considered the controller to be "The Overlord" as it manipulated data and directed where it should go.
For a login controller i might create something it like...
Post URI: http://example.com/login/authenticate
LoginController extends ParentController {
public function authenticate() {
$credential_model = $this->getModel('credentials');
// Obviously you should sanitize the $_POST values.
$is_valid = $credential_model->isValid($_POST['user'], $_POST['email']);
$view = $is_valid ? 'login_fail.php' : 'login_success.php';
$data = array();
$data['a'] = $a;
// .. more vars
$this->view->render($view, $data);
}
}
In my opinion data should always flow from the model -> controller -> view as it makes the most sense (data, manipulation, output). The View should only have access to what it has been given by the controller.
As for this...
Then if I'm dynamically calling my controller, how can I persist the data unique to the controller necessary to render the view?
Well I would imagine you're building a 'base' or 'parent' controller that gets extended off of by your dynamically called controllers. Those child controllers can have properties that are needed for for the view to render -- honestly I'd need an example to go further.
Hopefully this helps a bit. If you ask more specific questions I might be able to give a better thought out opinion.
If you're writing your own app, I think the best solution is to do it yourself and find out.
Ultimately, whatever makes the most sense to you, and whatever makes it easier for you to conceptualize your app and quickly add to or change it, is going to be your best option.
If one way is "wrong", then you'll find out through experience, rather than someone else telling you. And you'll know the entire situation that much better, and know EXACTLY why one way is better.
What helped me when I was writing my own framework in PHP was, strangely enough, CherryPy. It made the concept of an object-oriented web app so simple and obvious, and I enjoyed using it so much, that I modeled the basic structure of my PHP framework to imitate CherryPy.
I don't mean to imply you should learn CherryPy. I mean that simplicity, clarity, and enjoying developing with your own web app go a LONG way.
If I were to give one piece of specific advice, I'd say try to avoid retyping code; write your code to be reusable in as many situations as possible. This will not only be good for your app, but for future apps you may write or work on.
You might check out Eric S. Raymond's Rules for Unix Programming. I think they're definitely applicable here.
Dang-I know this is a subjective question so will probably get booted off/locked, but I'll try anyway, because I don't know where else to ask (feel free to point me to a better place to ask this!)
I'm just wrapping my head around oop with PHP, but I'm still not using frameworks or anything.
I'd like to create several small simple objects that I could use in my own websites to better get a feel for them.
Can anyone recommend a list or a resource that could point me to say 10 day-to-day objects that people would use in basic websites?
The reason I'm asking is because I'm confusing myself a bit. For example, I was thinking of a "database connection" object, but then I'm just thinking that is just a function, and not really an "object"??
So the question is:
What are some examples of objects used in basic PHP websites (not including "shopping cart" type websites)
Thanks!
Here's a few basic reusable objects you might have:
Session (identified by a cookie, stored server side)
User (username, password, etc.)
DBConnection (yes, this can be an object)
Comment (allow users to comment on things)
It sounds like you want to start to build your own web framework, which is a decent way to learn. Don't reinvent the wheel though. For a production site, you're probably better off using an existing framework.
Since you said you don't want to glue HTML and CSS again, you don't try this:
Create a WebForm class. This class is a container of form elements. It has methods to add and remove form elements. It has a getHTML() method that writes the form so that the user can input data. The same object is when a POST is made. It has a method to validate the input of the user; it delegates the validation to every form element and then does some kind of global validation. It has a process method that processes the form. It is final and checks whether validation has passed. If it passed it calls an abstract protected method that actually does the form-specific processing (e.g. insert rows into the DB). The form may be stored in the stored in session, or it may be re-built everytime (if it is stored in the session, it's easier to make multi-page forms).
Create a BaseFormElement and then several child classes like EmailElement, PhoneElement etc. These have also a getHTML() method that is called by WebForm::getHTML() and that prints the specific element. They have a validate() method that is called by WebForm::validate() and a getData() method that returns the properly validated and processed data of that element.
These are just some ideas. Some things may not make sense :p
I'd say database access would be the first most likely object - encapsulate your most common SQL requests into one class. If you make them abstract enough, you can use them for a wide variety of data access situations.
The way to think about class design/usage is to think of the class responsibility. You should be able to describe the class purpose in a short sentence (shorter than this...) i.e for database access object, you might say:
"provides API for common data access tasks"
If any of the methods in your data access class do something other than that, then you know they belong somewhere else.