CodeIgniter MVC: multiple models per controller? - php

I was pushed into an existing CodeIgniter project and am familiarizing myself with the proper conventions for their MVC approach. One thing I'm stuck on is relating models and controllers. The CI documentation gives almost no guidance on this and I'm not sure what the correct approach is. Our project is an API which is called by external applications so I'm not concerned with views, only models and controllers.
This is an off-the-cuff example rather than a practical example, but hopefully it will help me understand: Let's say that I'm making an application that has minigames and a virtual store. The player can earn points by playing minigames. They can spend those points in the shop to buy items. They can also sell items in the shop to earn points. The application should log each transaction of points.
In this situation, my thinking is I would have a:
ShopModel - interacts with the database to load product data and to save what items the user has purchased
MiniGameModel - interacts with the database to load data about the minigames and save scores
PointsModel - interacts with the database to transfer points into or out of the player's account (and writes corresponding log entries in the "log" table)
ShopController - utilizes ShopModel and PointsModel
MiniGameController - utilizes MiniGameModel and PointsModel
So, for example, the user tells the application they want to search the shop for "weapons". The application requests weapons from the controller. The shop controller builds a query and the shop model executes the query and returns the records. The controller formats the records as JSON and sends them back to the application.
The user tells the application they want to buy the shield. The application notifies the shop controller. The shop controller queries the price from the shop model, then tells the points model to subtract the points, then tells the shop model to give the player the shield. Finally, the controller notifies the application via JSON that the shield was purchased.
Is this an acceptable structure, or should each controller only have one model? If there should only be one model per controller, how do I avoid copy-pasting code that handles the points? Am I doing this completely wrong?
Please do not get hung up on the database structure or anything like that. This is not a real example. I'm just trying to figure out how to organize classes.

It's really as simple as you're thinking. Models in Codeigniter are just supposed to passed db results to the controller, or custom class, then to the controller.
You can load as many models as you like in a controller - thats not a problem at all. Personally I try to keep my model > db table in a one to one relationship. If I have work to do on the data from the model, i'll usually add a Library (custom class) to handle that part.
That way my controller stays clean.

i would give you some suggestion :
To save your time use this API RESTSERVER for functionally like you
explain.
For common functionality make a library, then auto load it and when ever you need it just called it where you want.you can called a library every where ,in view,controller,model .
e.g for just an idea, Library which would look like.
<?php if (!defined('BASEPATH')) {
exit('No direct script access allowed');
}
class Menu {
public $ci;
public $table="tblmenu";
public $full_record = array();
function __construct() {
$this->ci = &get_instance();
$this->company_id = $this->ci->session->userdata('company_id');
}
public function get_menu($comp_id = NULL) {
$comp_id = ($comp_id) ? $comp_id : $this->company_id;
$this->ci->db->select()->from($this->table)->where('company_id', $comp_id);
$this->ci->db->where('visible', 1);
$this->ci->db->order_by('id', 'ASC');
$this->full_record = $this->ci->db->get()->result_array();
return $this->full_record;
}
}
Then when you need it :
$this->load->library('menu');//or auto load it .
$this->menu->get_menu();

Related

how display checked filter variable value in url codeigniter

I am a basic user of code igniter and PHP.I have some products page with filters. How to created a URL link like this:
http://somepage.pl/products?color=red
I know I can do above url when I will change the config line:
$config['enable_query_strings'] = FALSE; on TRUE.
But I want to use this option only one controller and one function.
Your best bet is to rely on codeigniter's native URI rewriting.
By default, (I'm not getting into custom routes here, but you might if you understand them) URLs served by Codeigniter will look like this:
BASE URL/Controller/method/params
Base url will be what you define in the config and more often than not, it'll be the base domain of your site, like example.com.
Since CI is built based on MVC architecture, all your functionality must "live" on different methods within one or many controllers. So, for example, you might have a controller named products and within that controller you may have a method (for simplicity's sake: function) called lookupProductById that will take one parameter ($product_id). It'll look like this:
class Products extends CI_Controller {
public function lookupProductById($product_id = null)
{
// whatever you need to do (like querying the database to fetch info for the product with a certain product ID) goes here
// for instance, start by checking that the product ID was passed in the URI
if ($product_id == null)
{
// handle exception
}
else
{
// query the database and fetch info for the product whose ID is $product_id
}
}
}
so, when accessing example.com/products/lookupProductById/8 you'll be able to fetch the info related to product ID 8
You may want to read the CI documentation (the introductory chapters and tutorials will guide you through a (very) basic understanding of how MVC frameworks operate, how controllers, models and views interact to produce a result, etc.) to better understand what you're getting into :)

CodeIgniter with multiple subdomains

I have a problem and hopefully we will solve it.
The problem is, I am creating an application this application has an “Admin Panel (Backend)” and Frontend.
The URL structure of the admin panel is like this
https://www.app-name.com/admin
For frontend I have a different URL structure which is based on country for example.
https://usa.app-name.com
https://ca.app-name.com
https://uk.app-name.com
https://uae.app-name.com
https://in.app-name.com
It means in frontend I have multiple sub-domains. And the all these sub-domains are sharing a single database. As well as, backend is also sharing the same database.
Now my problem is how can I handle front-end like this.
Possible one solution in my mind is to copy app to all the sub-domains and connect with single database. And for admin panel copy it at the main domain.
But in this case, if I have a single modification to application I have to update all the copies. I want to use only single copy of app to handle all sub-domains.
Anyone have some solution for this problem. Thanks
I'd suggest executing some code in a important model for the app that gets auto-loaded through the entire app. Maybe call it Site_model.php.
Firstly, lets autoload the model. Open up config/autoload.php and add the model into the list of models to be autoloaded:
$autoload['model'] = array('Site_model');
Now, create the new model calls Site_model. In the construct of the model, add some code along these lines (this is a simply basic example of how to fetch and assign the value of a subdomain. I imagine there are better ways, but for this example, it will do):
class Site_model extends CI_Model {
var $subDomain = '';
function __construct() {
$this->subDomain = array_shift((explode('.', $_SERVER['HTTP_HOST'])));
// further code which uses the value of subDomain to fetch the correct record from the database.
}
Now, anytime you want to reference the subdomain in your code, you can simply get it like this:
echo $this->Site_model->subDomain;
This should also work for the admin backend. Oh, and ensure that the model is the first to be auto-loaded, in case any of the other models that are auto-loaded initialise code that is dependent on the site model's values.

How to be more Laravel in a CRUD app?

This is a question about how to create a better application with awesome Laravel. I want to create a CRUD application with multiple forms with user's permissions.
Details:
View. I have 3 forms, for example lets call it cat, turtle and dog. The most important is that they have different number of fields.
Here are forms
Controller. After user filled in the form and pressed save button the controller in the game. All of us know that the thinner controller is the better it is. But I use construction like this:
switch($type)
{
case '1':
//form validation -> move to model
//if all have passed that insert into database
//Show user a message
break;
case '2':
//form validation -> move to model
//if all have passed that insert into database
//Show user a message
break;
//.....
default:
//show message
break;
}
Where variable type equals form's type which has been filled in by a user. But as you can see now the controller is pretty big, and I don't like it. What the best way to do this?
Model.
I have 4 table, dogs_data, turtle_data, cat_data where I store all data from forms and pets_data where I store different metadata about pets above. How does it work? After validation passed insert data into one of these tables and get ID of this insertion. Then create the record in pets_data and insert the ID as pet_id and also insert table_type which will be required to get information from database. I think that it is very weird way to work with database. Here is table's visualisation.
Another problem is - show data. For example user has no permissions to edit data or delete records, but admin can remove, updated and see a lot of data from database. Should I create another controller like AdminController and write there another method which display information only for admin?
My application now:
WebSiteController - display website
AdminController - admin page, there is a method which generate special page to view pets.
UserController - users control panel, there is also method which generate page to view pets, but special for user.
And I think to create something like this
AuthController - special for login\registration\activation\etc
PetsController - create\delete\update\etc and also view in two variation: for user and admin. And idea is to create a method getShowPets($pet_id) (important it is only id from pets_data, not the pets_id) then get permission of the user and generate page.
And so on, I want to re-write my application use DRY rule
So I will very happy if you can give me some good tips about this project.
It looks like you are setting up a polymorphic relation, in which case, I would make everything separate meaning you'd have a model for Cat, Dog, Turtle, and PetData. You'd have controllers for CatController, DogController, and TurtleController. And you'd have a Cat form, a Dog form and a Turtle form, each that also contain inputs for the data you require for your pet_info table.
To create the polymorphic relation, your pet_data table will require some changes. Just change the table column to pet_type. Laravel expects a certain name for this column and for its contents to be the name of a model rather than the name of your table.
Setting up the models for these is very easy, I'll do the PetData and the Dog one to get started.
class Dog extends Eloquent
{
protected $table = 'dogs_data';
protected $timestamps = false;
public function petData()
{
return $this->morphMany('PetData', 'pet');
}
}
class PetData extends Eloquent
{
protected $timestamps = false;
public function pet()
{
return $this->morphTo();
}
}
Can read more about this here... http://laravel.com/docs/eloquent#polymorphic-relations
The idea of having separate models/controllers for everything might seem like a lot of work, but it goes a long way when trying to maintain or add additional animals to your app because you should rarely have to modify production code, taking away the possibility of introducing more bugs when trying to add enhancements to your website.
Now it becomes very easy to save a pet and related pet data without having to worry about the pet_id and pet_type in the pet_data table, Laravel will take care of that for you. The function on your dog controller might look like this...
class DogController extends BaseController
{
public function save()
{
$dog = new Dog;
$dog->name = Input::get('name');
$dog->age = Input::get('age');
$dog->save();
$pet_data = new PetData;
$pet_data->color = Input::get('color');
$dog->petData()->save($pet_data);
}
}
As far as creating another controller for admins, I would say yes, do that. It never hurts to keep parts of your website that you consider different in different files. It not only helps with organization, but again, with separation of concerns, which you should probably read more about.
There are also some fantastic 3rd party options for managing roles. I've used zizaco/entrust before and found it very easy to manage. It might make your life a lot easier when trying to manage who can do what on your web app.

One view called by two different controllers (A form contained with in a view calls another controller)

Dear Friends: It seems like more of a Conceptual problem than a programming problem. Am new to MVC and have problems in understanding what can call what. THE FLOW OF PROGRAM CONTROL.
The Problem: Controller A --Calls-->Model A--calls-->View A. Now once the View A is loaded it also contains a form for inserting comment with a sumbitt button.
Once the comments are inserted (and submitted) it calls Controller B--calls-->Mocel B. which insert data into comments table -- further it has NO View to call.
QUESTION 1: how to call the Controller A from Model B (since model B does not have a view). it is possible to load ViewA from ModelB but that will require to re-write the code that exists in Controller a already. FURTHER more i want the comment form to be inserted into many pages so will i have to reload all those pages (Views) manually.
Question2: it is possible to make comments form (Controller B and Model B) part of Controller A and Model A BUT then comment form will cease to be a re-usable module and will need to be inserted into every page that i like it to be used in.
Question3: Is there some conceptual error i an making. it is the way MCV works?
Summary:: There is a form managed by Controller B and Modal B (it has no view and it displayed as part of a page managed by Controller A, Model A and View A) Model Bafter doing its job it needs to call Controller A (so that it can refresh the page) HOW?
THANKS TO YOU BRAVE SOULS IN ADVANCE
I think your strategy is a little off starting with
Controller A --Calls-->Model A--calls-->View A
Your models really shouldn't be calling your view. The controller is usually in charge of this. Requests are made to the controller and the controller gets all the data from the model then formats/templates it using a view and outputs it to a user. Controllers should be at the center of every request.
QUESTION 1 how to call the Controller A from Model B?
Model B really shouldn't be calling a controller. MVC really isn't desinger for this. If you need data from model B get it from the controller. If you need functionality that exists in controller A refactor it into a utilty function that can be used anywhere in your app.
Question2: it is possible to make comments form (Controller B and
Model B) part of Controller A?
Yes once again this comes from a good app design. I'd imagine that one of your models is able to retrieve comments. Perhaps per user perhaps per time frame. From controller A you can call that model function. By loading the model $this->load->model('Post')
and retireving your posts $this->Post->most_recent_posts().
Question3: Is there some conceptual error i an making. it is the way
MCV works?
Yes the functions of your site are too tightly bound to their controllers and models. They hve to be more loose/general so functionality can be used in any controller.
I'd like to answer you last/main point but it would really really help to see some code.

Data from multiple models in one view (web page)

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');
}

Categories