So far, I create one controller for a site section with a method for each page - most are static pages, not requiring much logic or a model.
But where some of those pages are complex in functionality and need their own model, do I need to break them off into their own controllers? or is there a way to keep them in the one controller and load the model per method... probably the wrong thing to do
Totally agree with jondavidjohn's answer. I suggest just doing what works for you for now, and don't worry too much about overhead or doing the "correct" thing. You'll shortly realize what you need to do and how to be organized, and as far as overhead - Codeigniter is pretty lean, don't worry about optimization at this point - just get everything to work the way you want.
Take your first Codeigniter project and make it the best you can, but just consider it a throw-away app. Each time you work with it you'll learn more about how to use it, and especially if you keep reading and asking questions.
To answer your literal question: No, there's nothing wrong with loading the model per method. In fact, it can be "better" than loading in the __construct of your Controller, because it ensures you only load exactly what you need. So don't worry about it.
So far, I create one controller for a site section with a method for each page - most are static pages
There's nothing wrong with this, but to make things easier, you can use the same method for each of your static pages, and keep your urls the same. Something like this:
class Pages extends CI_Controller {
public function __construct()
{
parent::__construct();
}
function index($page)
{
$this->load->view("pages/$page");
}
}
// config/routes.php
$route['page/(:any)'] = 'pages/index/$1';
This would map the url /page/my_first_page to the Page controller and call index() with the argument my_first_page. Then you can use this for all your static pages without dynamic data. You can take this a lot further, but it's an example of one option you can choose to avoid writing a new method for every static page.
Because Codeigniter is so convention-less, it does lead to questions of opinion like this.
In general though I would always advise that more modularity is better than less modularity, and you can never over-organize.
Just because something isn't "wrong" doen't make it best.
Only you can decide in the end, because you will be the one to maintain it.
You can load the model per method. It's not bad practice to do that.
$this->load->model('your_model');
Models typically aren't too intensive to load. You shouldn't worry too much about loading models unless you are trying to save ever single bite.
its good to use specific controller for each page , so that the application becomes light weight, and also need to create its on model. So the application expand its functionality it becomes easy to develop :
class Location extends CI_Controller {
public function __construct()
{
parent::__construct();
$this->load->library('session');
}
public function index()
{
$data['title'] = "Hello world";
$this->load->view('locale_view', $data);
}
}
Related
I have a guitar lessons site using Laravel 5.3. It has lessons that are then broken down into exercises.
I decided today to add in the backend the ability to mark lessons or exercises as published. I simply added a 'published' column in the respective tables which contains 0 or 1.
There are many places in my site where exercises or lessons are accessed in some shape or form, including a lesson view, exercise view, lessons partial view (a tabular listing), exercises partial view (also a tabular listing), search/query views. There are also routes that perform functions such as incrementing hit count for a lesson or exercise, adding a lesson or exercise to one's favorites.
Given above, I am not sure how to prevent access to unpublished lessons or exercises using minimal code edits. I started looking at the controller files but then realized the controller might not be a catch all, such as on query result pages. Also controller files contain multiple methods and I don't want to edit them separately. I suspect there is a "laravel way" to do what I need globally, without me having to modify a bunch of queries in multiple files. Maybe it amounts to middleware or something?
In any case, I am new to laravel and if there is a tried and true way to control routes for content that is marked as unpublished, I would be very interested to know about it.
thanks
Take a look at global scopes, laravelest way to do this
As an aside, I prefer to use timestamps for things like published states on models. It means I can set a future timestamp for that content to become available, i.e. if I’m going on holiday.
In terms of your actual problem, a query scope would be the way to go:
class Lesson extends Model
{
public function scopePublished($query)
{
return $query->wherePublished(true);
}
}
Alternatively, if you did use a timestamp instead, you could do:
class Lesson extends Model
{
public function scopePublished($query)
{
return $query->where('published', '<=', $this->freshTimestamp());
}
}
You will then need to update your front-end code to use this scope:
public function LessonController extends Controller
{
public function index()
{
$lessons = Lesson::published()->latest()->paginate();
return view('lesson.index', compact('lessons'));
}
}
How to load more than one controller in another controller in CodeIgniter. The below code is i'm using. But it doesn't working. Only the controller which specified at first was work the second one is not working.
class A extends CI_Controller{
function __construct(){
parent::__construct();
$this->load->controller('B');
$this->load->controller('C');
}
}
You shouldn't be loading other controllers. Each request should be handled by a single controller. If you require common behaviour you have the following options:
/application/core/MY_Controller.php and extend that class
Move the behaviour to a model
Move the behaviour to a library or helper
If you are unfamiliar with the MVC pattern, this forum post might help you. It's from an old thread, but the principles still apply.
There are various methods to do that.
One of them: you can try this.
//Load the controller you want
$this->load->library('../controllers/controller_name');
//and can call functions of that controller
$this->controller_name->function_name();
I hope this is helpful!
When you are using code igniter you load a library or model like so
$this->load->library('mylibrary');
$this->load->model('mymodel');
So, in a real world example, lets say you have a controller called user.
So, to login a user you send them to http://example.com/user/login
Now the login function loads a form that submits to http://example.com/user/login_do
You do some simple checks, and then send it over to your model to do the database check for you.
So you call
$this->load->model('user');
if($this->user->validate($email, $pass)){...}
UH OH!
Fatal error: Cannot redeclare class
User in
/var/www/unity/src/application/models/User_Model.php
on line ...
So what happened? Well, Code igniter does not segregate the classes, so your model now conflicts with your controller,
sure you can use
$this->load->model('user_model', '', 'user_m');
if($this->user_m->validate($email, $pass)){...}
So, Onto my question.
Why does code igniter not segregate the classes,
e.g. so you would call
$this->load->model('user');
if($this->model->user->validate($email, $pass)){...}
Sure it's slightly longer, but hell it would make things heaps nicer to user.
is it possible to extend code igniter so it works in this way?
It's not exactly the solution you're asking for (or a great idea), but there's nothing stopping you from doing this:
class Users extends CI_Controller {
private $model;
private $m;
public function __construct()
{
parent::__construct();
$this->load->model('user_model');
$this->model->users = $this->user_model;
$this->m = $this->user_model;
}
function index()
{
// Here's that syntax you wanted
$this->model->users->get_many();
// Even shorter
$this->m->get_many();
}
}
You can really just assign anything to any property of the controller you want, as long as it's not the name of a loaded class or property (session, router, etc.). It can save you some typing if your model names are really long, but otherwise it's pointless and may conflict with things in the future.
Here's what I do if I'm not using *_model for model names:
Controller name: Users (plural)
Model name: User (singular)
No conflict, short syntax, sensible naming, it just doesn't work for some names like "news".
As I mentioned, it would be nice to see controller names using something like Controller_User or User_Controller to clear up the namespace issues a bit for the classes that we actually do have to call frequently, like models and libraries, but keep our urls as normal. I'm sure it can be done, something for a rainy day...
You missing the main point, PHP doesn't allow two classes with the same name, basically that's what Cannot redeclare class User says.
The Zend Framework is mainly meant for MVC use. One of the very usefull components is Zend_Form.
I have a bit trouble finding the place of Zend_Form. Is it part of the view, model, or controller and which responsibilities should I give it.
The thing is, Zend_Form does two things: decorate and render the form and validate it. The first is a real view task, the second a real model task.
Now the most common use seems to be to have the forms interact with the controller only, effectively putting both tasks (rendering and validating) to the view/controller.
Another option given by Matthew Weier O'Phinney is to attach the form to your model, and adding the later view options in the controller.
So, I'm doubting. Where in the MVC pattern should I place Zend_Form and how should I use it?
Edit Good answers so far, thanks! I will be awarding the bounty an hour or two before it expires, so please give an answer if you have some more thoughts!
Zend_Form can be viewed at different points. It can't be considered at all as part of just one layer of MVC pattern.
First of all Zend_Form use decorators and view helpers to render the form, at this point it is part of view layer.
Then, Zend_Form does part of the model job filtering and validating the content.
We know that Controller layer render input from the view and pass it to the model. Actually, the controller layer decide which resource to load from model layer and then perform the corrects calls.
When you call Zend_Form from controller layer, you can consider that you are calling one model resource to perform valitations and filtering actions and decide whether or not this is a valid input. For example:
public function newAction()
{
$form = $this->getForm();
if($this->getRequest()->isPost())
{
$formData = $this->_request->getPost();
if($form->isValid($formData))
{
$Model = $this->getModel();
$id = $Model->insert($form->getValues());
}
}
$this->view->form = $form;
}
Tie Forms to the model can be considered a good pratice because when you are performing filtering and validation actions you are on model layer. So, as Matthew proposed:
class Model_DbTable_Users extends Zend_Db_Table
{
protected $_name = 'users';
protected $_form;
public function getForm()
{
if(!$this->_form)
$this->_form = new Form_User();
return $this->_form;
}
public function add($data)
{
$form = $this->getForm();
if(!$form->isValid($data)) return false;
if($form->getValue('id'))
{
$id = (int) $form->getValue('id');
$this->update($form->getValues(), 'id =' . $id);
}
else
{
$id = $this->insert($form->getValues());
}
return $id;
}
}
From the standard directory structure we can see that Forms aren't in the model folder nor in the view folder because Zend_Form is a specific class that tie many resources and layers together. If you check the Matthews post you will realize that this is exactly what is being said when the action url is set on the view script and the form is tied to the model.
Finally, you can analyze your context and pick up one of these two approachs.
Currently, my choice is to tie forms to models. Looks nice! And make a lot of sense to me.
IMO, Zend_Form is designed to wear multiple hats. It is, in fact, a bridge between the view and model with a giant support beam from the controller.
Instead of assigning a Form to a Model, consider assigning Model(s) to a form.
In the Model layer, you can have a a getFormInputs method that could return the Elements needed to input data. The model doesn't care what form is going to use it, it just makes it available to any from that wants them.
Now in your form layer, make a setupInputs method that will loop thru an array of models to grab all the inputs. If there was only one model, add the inputs to the form. If there was more then one model, make sub forms.
Your controller will initiate the form and pass the values back to model (see Keyne's newAction method)
Zend_Form does often feel like the odd man out. I think everyone's mileage varies.
Lately, most of my administrative interfaces have been very drag + drop AJAX-y, and they require a good deal of html and javascript - actual form elements are sparse. So I chose to eschew a lot of the features of Zend_Form and use it as a fancy view helper with filtering. All my validation is done on a separate layer in the model.
I think O'Phinney's idea makes a lot of sense as well. Here, he's choosing to think of the form almost as a component of the domain object - where he can add business logic. This sounds just fine, as long as you're careful to keep all the view logic for the form separated. As he notes, it's about making semantic sense. There isn't necessarily a hard and fast rule.
I am having difficulties testing Controllers in Codeigniter:
I use Toast but when I invoke my Home Controller class I get an exception that "db" is not defined. Has anybody an idea how to test this 1-1?
Thanks
class Home_tests extends Toast {
function __construct() {
parent::__construct(__FILE__);
// Load any models, libraries etc. you need here
}
function test_select_user() {
$controller = new Home();
$controller->getDbUser('foo#gmail.com','password');
assert($query->num_rows() == 0 );
}
}
As others have mentioned, CI doesn't let you call a controller from another controller. The short reason is that controllers always create response headers (even when you don't load any views or call the output class), and you aren't allowed to send two sets of HTTP headers to the browser.
While coding Toast, I tried to hack CI to allow this, but it takes some very hairy hacking of the Loader, and I came to the conclusion that you really shouldn't put any heavy logic in your controllers anyway. IMO, for proper MVC modularity, that stuff belongs in your models, libraries and helpers (which can all be unit tested with Toast).
You might need to edit your database connectivity settings in ../system/application/config/database.php