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.
Related
I'm new to CodeIgniter but want to perform best practices from the start. I have a simple authorization call that needs to be able to be called from several controllers. Hence I'm thinking it should be placed in either a library or a helper function. The call would take the user's id and a required authorization "level", grab their information from the DB, make sure they have that level of access, and return true or false.
Let's say:
auth($user,5)
My first instinct is to make this a library, but it seems odd to place it directly in a library because there are DB calls, which I would think should go in a model. It appears that only the Session library contains calls directly to the DB (for when database session storing is turned on).
So, I could access the DB directly within the library, or try to link to an external Model. Looking it up on the web, I'm only finding people who have trouble with both routes. Before I dive too deeply into getting one of them to work, I'd appreciate any opinions out there on how to go about this.
Thanks,
Jeremy
It seems like that is a model function. At least put it there until later in development.
If you later find there is a need for multiple models which would require duplicating the function, then would be a good time to move it to a helper or library.
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.
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.
Im used to java and creating UML.. and i was wondering how can PHP be OOP, the objects live only until you make a request.. then they destroy, so if im using a database is useless to create a class and add the members (variables) to the class, they will be useless.. i cant pass the main system object from one page to another, or similar so how can PHP be compare to jave? you never do OOP .. i mean REAL OOP.. not creating classes , in fact your index will be a procedural file with some object instance and then ? how about if i make a html form and i want to submit the data.. i have to call a file which is not a class is a php procedural file were i grab the submited data with POST, from that file you will instance a class and do some logic there.. but for me thats not pure OOP.. can somebody point me to the right way of OOP using a form submit example ?
Thanks!
You're labouring under a misapprehension that object oriented programming by definition includes a persistent environment with objects that exist independantly of page requests. I'm afraid it doesn't.
PHP does do "real" object-oriented programming. But PHP's execution environment is like executing a CGI program: upon a page request, the program starts and it ends when the page is finished. Within that paradigm, objects can exist only as long as the page is producing content. Therefore, the first thing the page must do is to load the framework to define and instantiate the required objects, such as a database handler and object mappers that must load and save their data within a page request cycle. Some frameworks will also create objects with the page-request data that your code and objects can then access, sometimes from within objects.
But PHP does not provide this natively because it does not enforce a framework. It is by nature procedural so a framework must be added so as to define and create the desired objects if you don't want to work that way.
There is an advantage to doing things this way. It means a page's code need only concern itself with a single page request. Almost all issues to do with data-sharing and multiply-threaded execution is pushed out to things that can handle it invisibly, like the database and the web server.
Check out any of the latest php framework and how they handle forms. (like ZF or Yii).
b.t.w the "problem" you refer too is client-server architecture and not a minus of PHP.
Each request is a new process with a new MAIN or new Class with static main function which are practically the same.
"so if im using a database is useless
to create a class and add the members
(variables) to the class, they will be
useless"
It sounds like you want an object-relational mapper. There are several popular ones for PHP, as discussed at this previous question.
I'm thinking about using CodeIgniter for a new project. I was reading the user-guide for CI and I noticed a few things. In all their examples, they seem to put all the logic in the Controller and just use the model to get and set data. I like to put all my logic in my Model.
Are all of their functions universal to all 3 parts (model, view, and controller) or will there be problems if trying to do logic in the model as opposed to the controller.
Also, are all variables accessible to all 3 parts (model, view, and controller). If I wanted to know if a user was logged in within the view, would I have to pass that information to the view from the controller or is it already accessible within the view?
Also, I noticed that session data is stored within cookies, even though they are encrypted. Is the encryption safe enough to use, beause im more used to using sessions. Also, how long are these cookies stored by default? I was a little confused about that part, if anybody can clear that up.
If you have any other tips to help my learning this new framework, I would appreciate it.
Thanks
EDIT: I like to use Fat Models and skinny controllers, so that I can use the same functions in more than one place.
Just read about Kohana, I think I'll look more into that
You have made a lot of assumptions from some basic examples which are not entirely correct.
Controllers should contain interaction logic.
That means that your Controllers should just be saying what models, views, libraries, etc should be used based on what the user is doing.
Models contain data logic.
This can be your business logic, tax calculations, all sorts of data related work. The examples in the userguide suggest just using Models as a "dump wrapper for the database" but you can do anything with them. The model simple represents your data and the rest of your application should not care where it came from.
My models contain a mixture of XML file parsing, REST method calls and of course, some ActiveRecord queries.
Views just show stuff, therefore has no idea about login/logout state. You would of course need to tell it this from your controller (or from global code such as MY_Controller, which IMHO almost every decent sized application needs).
Sessions stored as encrypted cookies are perfectly safe. They would only be able to decode them if they knew your application encryption key, but that is very unlikely unless you have not set one; in which case you only have yourself to blame.
If storing sessions in cookies is not your cup of tea, you can store session values in the database to keep them even more secure, or grab a different session library to work with.
The thing to remember with CodeIgniter is that it only suggests ways to work, if you don't like it, extend, override or replace.
they seem to put all the logic in the Controller and just use the model to get and set data.
CodeIgniter expects very little logic in its models, and instead gives you a very dumb SQL wrapper for returning simple arrays of POD types to represent your data. It even puts a lot of validation code into the controllers, which (in my opinion) is incorrect and repetitive. I've rolled my own solution for Rails-style in-model validation and dynamic find method, allowing things like
// inside model:
// username must be 8 to 25 chars long
$this->validates_length_of('username', 8, 25);
// dynamically handled via __call()
$this->User->find_first_by_username('john'); // Return object or null
$this->User->find(); // select *
$this->User->find_by_group('admin'); // return 0 or more records
but AFAIK there isn't any built-in way of doing similar things with CodeIgniter.
Also, are all variables accessible to all 3 parts
No; you have to manually pass your variables from your controller to your view, and there is no sharing of variables with models/controllers or models/views.
I believe the method suggested by CodeIgniter:
<?php
function users() {
$data['users'] = $this->User->find();
// must use $data['users'] for controller logic; verbose and annoying
$this->load->view('users/index', $data); // $users defined for view
}
?>
can be improved by using PHP's compact keyword:
<?php
function users() {
$users = $this->User->find();
// now we can use $users more easily
$this->load->view('users/index', compact('users'));
}
?>
I noticed that session data is stored within cookies
CodeIgniter can store session data in a database; see $config['sess_use_database'] in config/config.php. There are other config settings in there that pertain to the lifetime of the session cookie.
I'm inclined to say that the only thing CodeIgniter does well is their documentation, read more about session configuration and their implemntation of active record (really a language-independant SQL wrapper which has nothing to do with the Active Record pattern)
CodeIgniter is based on the Model-View-Controller development pattern. The model represents your data structures and should be used just for that.
I would follow that convention, especially if you want to learn the new framework.
AFAIK, the session id is encrypted and stored in cookies, but session data is stored in local database.
The main idea of MVC is such division. But models are not restricted to just direct access to data, they can perform various data manipulation. The idea is to represent objects(and sets of objects) stored in database as php objects, so if it seems logical to have some function in you object - it's as much logical to have it in your model.
I think the misunderstanding here is that so many web applications have hardly any logic outside some simple data processing, that developers are getting used to it.