CodeIgniter Forums

Full Version: Using libraries alongside models
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2
Hi Guys!

I'm just curious to know, as I would like to ensure that I use the best possible practices when creating applications.

So here's conundrum, I have a home controller, In this controller I would like to store the latest products from the products controller.

Now from the home controller I can't directly access the product controller. Now, I've created a templating engine as a library, now I would like to be able to say something like {% latest_blogs(9) %} in my home view. Now don't worry about the template engine too much it's just the main reason I need to ask whether my approach is acceptable. However I feel like I would have the same problem even If I wasn't calling it from the view and attempted to call it from the controller.

Anyway, as noted, I basically need access to the product controller whether the access is from my view or controller in this case. Now, Is it OKAY to create a products library with it's own model or even the model of the products controller?

If not how else can I approach this? I mean, I could load the model into the controller too but I don't know how to approach this in the best possible way.

Some advice would be fantastic,

Thanks,
Matt.
you could probably take a bunch of the code in your Product controller and refactor it into a Products model.

so then in any controller you could have something really simple like

PHP Code:
if ( ! $products $this->products->returnProductsBy($category) ){

 
    $this->showNoProductsBlogPost() ; } 

else{
$this->showBlogPostWith($products) ;  

personal preference: i'm not calling any views, they are in separate methods. this adds a few lines of code but it makes it much easier to maintain.
(03-29-2015, 04:06 PM)mdixon18 Wrote: [ -> ]So here's conundrum, I have a home controller, In this controller I would like to store the latest products from the products controller. Now from the home controller I can't directly access the product controller.
Hi, Matt, and welcome to the forum!

I'll be the first to back down if my way isn't "best practices," but I don't consider controller, models, and views to be rigidly tied to each other. That is, I don't believe that you can load only the home model and no other model into your home controller. If I need to access products from my home page, I load the products model in my home controller and call the appropriate methods in that model.

I would not put methods that retrieve or manipulate products from and in the database in other models or libraries just to ensure that my home controller only loads the home model. That would place database access methods in different places, which I think would be worse practice than keeping them all together in the same model, regardless of which controller used them.
(03-29-2015, 06:13 PM)RobertSF Wrote: [ -> ]
(03-29-2015, 04:06 PM)mdixon18 Wrote: [ -> ]So here's conundrum, I have a home controller, In this controller I would like to store the latest products from the products controller. Now from the home controller I can't directly access the product controller.
Hi, Matt, and welcome to the forum!

I'll be the first to back down if my way isn't "best practices," but I don't consider controller, models, and views to be rigidly tied to each other. That is, I don't believe that you can load only the home model and no other model into your home controller. If I need to access products from my home page, I load the products model in my home controller and call the appropriate methods in that model.

I would not put methods that retrieve or manipulate products from and in the database in other models or libraries just to ensure that my home controller only loads the home model. That would place database access methods in different places, which I think would be worse practice than keeping them all together in the same model, regardless of which controller used them.

Thanks for this, I agree this is the way I would do it in the controller and pull them all in.

But what do you guys think about calling a model from a library? Only I've created a huge template library and it'll be really nice if its good standards to assign a mod specifically to a library.

I've done it this way already and hey it works.

But is it a good way of doing things?
I would also like to note that the Template Engine I have created is called instead of loading $this->load->view(); therefore, I've had to set it up to pass data to the template to check for matches. I would just like to be able to have a kinda partial library for functionality.

Such as products, blogs, forums etc. This way I could call different things in my template like latest blog posts, latest products and latest forums; no matter what page I am or what template is being loaded.

To do this i kinda need to know what the best way is, do I use a library with direct database queries? do I load a model into the library? or do i use a helper and call the database or so on.

What do you think?

Matt.
In my opinion, it is better to load/call a model from a library than to call the database from your library.

One example I can think of in Bonfire is a Settings library which allows settings to be stored in the database but also allows settings to be retrieved from CI config files (if they do not exist in the database). So, it uses a settings model to access the database, but if the value requested is not found, it uses the config_item() helper function to retrieve the setting from a config file (and caches the result regardless of the original location so it can be retrieved later without making an additional call to the database or the file).

Then you simply determine (more or less on a case-by-case basis) whether you should only use the library to access the model, or if the model should also be directly accessed by a controller in some situations.

In the end, only a model should access the database. If a library needs access to data, it should either be provided to the library by the caller or the library should load/use a model which can give it the required data. Ultimately, if the data is provided to the library (or the model is injected) it will usually provide the best long-term maintainability and potential for reuse for that library, but this isn't always the most practical way to develop your application.
Seem's like just having a Model's folder, view folder and controller folder inside the library could be a good setup and just extend off the auto loaded classes. As long as the library is loaded this should work.
Why would you make a library?

Libraries usually contain non-CodeIgniter specific functionality. A libary can be re-used by you or others in other projects. Examples: An authentication library and a mail library. It does not contain business logic. So some kind of 'Products Library' does not make sense.

Side note: If you make a library, it might be possible that it uses a MVC-pattern underwater, but the user of the library does not need to know this. The library needs to provide an interface/API and the end user definitely (YOU) does not access a model (directly). The interface consists of one class (sometimes more than one) exposing public methods to the outside world. The MVC-pattern.framework is most of the time not really suitable for a library.

As suggested, you can access multiple models from your home controller. It is perfectly fine to access the products model from your home controller.... BUT

you will find out that a lot of times you need some data coming from one model and combine it with data coming from another model. You have to perform some kind of business logic, but where do you put this?
It definitely does not belong in the view. (You only present/output data in a view).
It does not belong in the controller. A controller should be as lean/clean/thin as possible, so no business logic there.
So it should be in a model. That means you have to retrieve data form one model and pass it to the other... You cannot call one model from another one.

This is a situation you will find yourself in a lot of times. As far as I know, the MVC-pattern/framework does not provide a solution. Neither does CodeIgniter (or almost any other MVC-framework for that matter).

The solution would be to use a service layer (also called 'business layer'). The idea is that you access a 'service class' from the model, which gives the information you need. Example: In your case you could create a BlogService with a method "GetBlogs(DatetIme fromDate, DateTime endDate)". In the BlogService class you access all the models you need.

There you go!! Business Logic nicely separated from the controller (and the models), and that is a good practice.

I have to go now, but I will come back to this. In the meantime read something about service layers.

Anyhow, do not create a library.
Quote:I have a home controller, In this controller I would like to store the latest products from the products controller.
This does not make sense. Controllers are not for storing data.
I did not finish my last reply....

So my suggestion is not to have 3 layers (Model, Controller, View), but 4: Model, Service Layer, Controller, View.

In your controller, you access a service class like this:

PHP Code:
$data['blogs'] = blogService->GetBlogs('2015-04-01''2015--04-07');
$this->load->view('blogs_view'$data); 

In your service class (named "BlogService" here) you access your models like this:

PHP Code:
function GetBlogs(DatetIme fromDateDateTime endDate)
{
 
$blogs = array();

 
$homeData $this->_homeModel->GetHomeData(); // Get some data from a model
 
$personData $this->_personModel->getPersonData(); // Get some data form another model
 
 // Do all the things you like (busines logic) with the data you retrieved from the different models...
 
return $blogs 


In your models you access your data source (probably a database)

Probably you got the picture by now. But how to create this service layer? Controllers, Models and views are supported by the Codeigniter framework, but the service layer is not... so you have to extend it.
If possible you do not want to modify the CodeIgniter core libraries (anything in the system folder). I was able to create such a layer for CodeIgniter 2.

This is what I did:

Create a class MyService and place it in folder application/core:

PHP Code:
<?php
 
if (! defined('BASEPATH'))
 
   exit('Geen directe toegang tot het script toegestaan.');
 
class 
MyService
{
 
   protected $_CI null;
 
   protected $_lang null;
 
    
    function __construct
()
 
   {
 
       // Get the CI object.       
 
       $this->_CI = &get_instance();
 
        
        $this
->load = & $this->_CI->load//& load_class ( 'Loader', 'core' );     
 
        
        $this
->_CI->lang->load('Dutch');
 
       $this->_lang = & $this->_CI->lang    
    
}
}
 
?>

You can use this base class for all your services. Example of a service (placed in folder application/services):

PHP Code:
<?php
 
if (! defined('BASEPATH'))
 
   exit('Geen directe toegang tot het script toegestaan.');
 
require_once 
APPPATH 'core/MyService.php'//Necessary. If we want CodeIgniter to know how to find this class, we have to modify/extend the core.
 
class TeamService extends MyService
{
 
   private $_teamModel;
 
    
    function __construct
()
 
   {
 
       parent::__construct ();     
        $this
->load->model('TeamModel''_teamModel');
 
       $this->_teamModel = & $this->_CI->_teamModel;
 
        
    
}
 
 
   public function GetTeamNames($competitionId$divisionId
 
   {
 
       $result $this->_teamModel->GetTeamNames($competitionId$divisionId);
 
       return $result
 
   }
}
 
?>

Things to notice:

- The loading of the language in MyService is not really necessary. It is convenient to be able to have the language you are going to use available at this level. The following 2 lines take care of that:

       $this->_CI->lang->load('Dutch');
       $this->_lang = & $this->_CI->lang;
 

- Because the class cannot find the base class MyService, simply because the framework does not look for this type of class, you have to tell where to find it. That is what the require_once is for.  

- Models you have to load by hand. That is what the $this->load->model does.

- After that you assign it to a local class variable. That is what $this->_teamModel = & $this->_CI->_teamModel does.

So now you can access this class from every controller and you can access multiple models. Two other big advantages: You can totally separate your business logic (service layer -= business logic layer) and you prevent repetitive code. In the above example I can get teams in every controller where I need teams. Isn't that sweet?

I haven't migrated my code to Codeigniter 3 yet. It shouldn't be a problem to use my service layer again.

Hopefully this answered the question of the OP.
Pages: 1 2