Using CodeIgniter Model as an object manager/factory - php

I'm currently designing a game that utilises CodeIgniter, but I don't think the singleton approach to models is the way I want to handle the game-related objects in the DB.
I want to use a CodeIgniter Model class to handle the basic CRUD operations of the objects, but have the objects as PHP Classes.
Example:
$this->load->model('playermodel');
$player = $this->playermodel->get($player_id); // Returns a Player object
// Call modifying operations on the player (equip item, take damage etc.)
$this->playermodel->save($player); // Commits updated Player back to DB
$player2 = $this->playermodel->create(); // Basically calls new Player()
I'm fairly new to CodeIgniter, would something like this be going against any kind of CodeIgniter or MVC design rules? And if so, could anyone recommend me another approach to my problem?

The best approach would be for you to get as far as you can from Codeigniter, if you want to build proper MVC. Codeigniter is framework written for PHP4, and it didn't get any updates for quite some time now, I'm talking about framework design, not some library updates.
If you look at Codeigniter source code and look what base model do, it just takes request from model and pass it back to the controller using magic _set and _get methods. So Codeigniter doesn't really know a difference between your models or controllers. And how every you write this, everything is processed in some mega super ultra global object.
From outside it might look like you are using MVC but you are not really.
Take a look at Zend2, Symfony2... where you can really build your Models.

What you currently have is a strange interpretation of data mapper pattern (do not confused with CI's ORM with same name, which instead implements active record pattern).
The idea would be to separate the domain logic from the interaction with storage abstraction. For simplified code example, you can read this post.
Only major problem, that i sea with your implement, is that your mapper also contains logic for creation of instance. Thus, it has acquired also the characteristics of a factory (or maybe, builder .. depends on your particular use-case). This would violate single responsibility principle.
But non of this is against CI's design rules. Because it has none.

Related

implementing my first PHP model

I've written a small RESTful PHP backend using the Slim framework (http://www.slimframework.com/) that interfaces with a MySQL database, and right now I just have one class doing all the DB interactions and it's getting kinda big. So it's time to organize it a little more cleanly.
So based on what I understand from MVC, a better way to do this might be to implement a model layer like so:
each logical entity in the system will be implemented with a data class. I.E. user accounts: a class called "Account" with getId(), getName(), getEmail(), etc etc
and corresponding factory objects, i.e. AccountFactory which owns the DB connection and creates an Account class to manipulate elsewhere in the business logic layer.
The business logic layer would still be pretty simple, maybe a class called MyApplication that instantiates factories and uses them to respond to the RESTful API calls.
Business logic might be, for example, matching two accounts together based on geographical location. So in this case, I would just be testing on the data in two separate Account objects instead of the raw data loaded from the database.
But that seems like a lot of refactoring time spent to do basically the same thing. Why wouldn't I want to just use the plain array data I load from the database? It's not DB-independent, sure, but I don't really plan on switching away from MySQL at the moment anyway.
Am I approaching this in the correct way?
Well, partly.
The first point describes a model - the M in MVC. Abstracting your "business logic" from this model makes sense in many ways. One use case could be a website that interacts with the same data as the REST API. You could reuse the model and only need to build new controllers.
The "business logic"/"layer" would probably the controller - the C in MVC. However I would not give the factory objects ownership of the DB connection, as some use cases may want to use multiple factory objects but should use the same database connection...
I suggest you read more about the structure and pro's and con's of the MVC approach.
when you start from scratch the best is to :
have a ORM (which mean that you must have relations in your MySQL database with foreign keys etc.). Thats very quick way to manage database management in your program.
Create your home-made class for each entitiy = 1 class.
The best pratices are generally to have an ORM but it can be a bit heavy (it depends on your architecture and application).
In your case put an ORM seems to be a lot too much cause you developped a lot.
It depends of the future of your application : will it grow again ? will a lot of developper will develop on it ?
For a small/medium size you can easily refactor a bit your class by big theme, ex : 1 class for your 3 biggest entity in which you have the more requests. That will tidy a bit the mess and organize things, and then you can migrate your new classes for eqch new entity. For the old ones you can migrate step by stepm or not
Another good practice is to have getters and setters $this->getter_id(); $this->setter_id( $in_nId ); That will help you a lot if you need to change some db fields

Where to put sql queries in Yii (or any framework with ORM support)?

This is a more of a coding style question for projects using MVC architecture.
I'm working on a project using Yii framework. Each database table has it's own model class and lets me take advantage of Yii's Active Record stuff. Cool.
But now I need to do an SQL query with a complex logic and a lot of tables being joined.
The best and quickest way to do this is to write a raw SQL and put it in somegetSomeComplexLogicData method.
The question is, where do I put this method? Is it a good practice to leave it in a controller where I'm calling it (it's highly unlikely that it will be re-used anywhere else), or should I put it in some Model class that it best corresponds with?
It is not mandatory for Yii's "models" to extend CActiveRecord.
You can create a simple domain object, which contains the business logic for some structure in your code an have separate mapper for that structure, which contains the complicated SQL queries.
You should try to avoid lumping all in a single class because you end up with SRP violations, which is one of main reason why active record pattern is usually considered to be harmful (there, of course, are some exceptions). It dents to combine bot domain logic and storage logic on single class, thus making it hard to test and maintain.
If you were using a proper MVC or MVC-inspired design pattern, there would be no "models". Model is supposed to be a layer. Not a class or object. And you should no have any domain business logic exposed to controller.
1) You can put this method into components/Controller.php so that this method available for you into each your application controller.
2) Best way is to make a your own component. You can call your compoment from controller, model, views.
Yii::app()->yourcomponentname->methodname
Link to learn how to make component: http://www.yiiframework.com/wiki/187/how-to-write-a-simple-application-component/

Zend Framework Data Access Layer (DAL)

Looking through several tutorials and books regarding data access in Zend Framework, it seems as if most people do data access within their models (Active Record Pattern) or even controllers. I strongly disagree with that. Therefore I want to have a Data Access Layer (DAL) so that my domain layer remains portable by not having any "ZF stuff" in it. I have searched around but have not really found exactly what I wanted. Heads up: I am new to ZF.
DAL structure
So, the first problem is where to place the Data Access Layer. While it could certainly be placed within the library folder and adding a namespace to the autoloader, that does not seem logical as it is specific to my application (so the applications folder is suitable). I am using a modular structure. I am thinking of using the below structure:
/application/modules/default/dal/
However, I am not sure how include this folder so that I can access the classes within the controllers (without using includes/requires). If anyone knows how to accomplish this, that would be super! Any other ideas are of course also welcome.
The idea is to have my controllers interact with the Data Access Objects (DAO). Then the DAOs use models that can then be returned to the controllers. By doing this, I can leave my models intact.
Implementation
In other languages, I have previously implemented DAOs per model, e.g. DAL_User. This resulted in an awful lot of DAO classes. Is there a smarter way to do this (using a single class does not seem easy with foreign keys)?
I would also appreciate suggestions on how to implement my DAO classes in ZF. I have not spent an awful lot of time reading about all of the components available for database interaction, so any ideas are very welcome. I suspect that there is something smarter than standard PDO available (which probably uses PDO internally, though). Name drops would be sufficient.
Sorry for the many questions. I just need a push in the right direction.
Well, the first thing you have to take into account when dealing with the Data Access Layer, is that this layer also have sub-layers, it's unusual to find folders called "dal" in modern frameworks (I'm taking as basis both Zend Framework and Symfony).
Second, about ActiveRecord, you must be aware that by default Zend Frameworks doesn't implement it. Most of the tutorials take the easiest path to teach new concepts. With simple examples, the amount of business logic is minimal, so instead of adding another layer of complexity (mapping between database and model's objects) they compose the domain layer (model) with two basic patterns: Table Data Gateway and Row Data Gateway. Which is enough information for a beginner to start.
After analyzing it, you will see some similarity between ActiveRecord
and Row Data Gateway patterns. The main difference is that
ActiveRecord objects (persistable entities) carries business logic and
Row Data Gateway only represents a row in the database. If you add
business logic on a object representing a database row, then it will
become an ActiveRecord object.
Additionally, following the Zend Framework Quick Start, on the domain model section, you will realize that there's a third component, which uses the Data Mapper Pattern.
So, if the main purpose of your DAL is to map data between business objects (model) and your storage, the responsibility of this task is delegated to the Data Mappers as follows:
class Application_Model_GuestbookMapper
{
public function save(Application_Model_Guestbook $guestbook);
public function find($id);
public function fetchAll();
}
Those methods will interact with the Database Abstraction Layer and populate the domain objects with the data. Something along this lines:
public function find($id, Application_Model_Guestbook $guestbook)
{
$result = $this->getDbTable()->find($id);
if (0 == count($result)) {
return;
}
$row = $result->current();
$guestbook->setId($row->id)
->setEmail($row->email)
->setComment($row->comment)
->setCreated($row->created);
}
As you can see, the Data Mappers interacts with a Zend_Db_Table instance, which uses the Table Data Gateway Pattern. On the other hand, the $this->getDbTable->find() returns instances of the Zend_Db_Table_Row, which implements the Row Data Gateway Pattern (it's an object representing a database row).
Tip: The domain object itself, the guestbook
entity, was not created by the find() method on the DataMapper,
instead, the idea is that object creation is a task of factories
and you must inject the dependency in order to achieve the so called
Dependency Inversion Principle (DIP) (part of the SOLID principles). But that's
another subject, out of the scope of the question. I suggest you
to access the following link http://youtu.be/RlfLCWKxHJ0
The mapping stuff begins here:
$guestbook->setId($row->id)
->setEmail($row->email)
->setComment($row->comment)
->setCreated($row->created);
So far, I think I have answered your main question, your structure will be as following:
application/models/DbTable/Guestbook.php
application/models/Guestbook.php
application/models/GuestbookMapper.php
So, as in the ZF Quick Start:
class GuestbookController extends Zend_Controller_Action
{
public function indexAction()
{
$guestbook = new Application_Model_GuestbookMapper();
$this->view->entries = $guestbook->fetchAll();
}
}
Maybe you want to have a separated folder for the data mappers. Just change:
application/models/GuestbookMapper.php
to
application/models/DataMapper/GuestbookMapper.php
The class name will be
class Application_Model_DataMapper_GuestbookMapper
I've seen that you want to separate your domain model objects into modules. It's possible too, all you need is to follow the ZF's directory and namespace guidelines for modules.
Final tip: I've spent a lot of time coding my own data mappers for
finally realize that it's nightmare to maintain the object mapping when
your application grows with a lot of correlated entities. (i.e Account
objects that contain references to users objects, users that contain
roles, and so on) It's not so easy to write the mapping stuff at this
point. So I strongly recommend you, if you really want a true
object-relational mapper, to first study how legacy frameworks perform
such tasks and perhaps use it.
So, take some spare time with Doctrine 2, which is the
one of the best so far (IMO) using the DataMapper pattern.
That's it. You still can use your /dal directory for storing the DataMappers, just register the namespace, so that the auto loader can find it.
In my opinion you should have a gateway abstraction (not just Database access) per model. A DAO is not enough. What if you need to get the data from the cloud at some point? This is quickly coming a reality. If you abstract your gateway logic into something generic and then implement it using a database you can have the best of both worlds.
The implementation of a specific gateway interface could use a generic data mapper if you so chose. I work for a small company and have always just created my implementation using PDO. This lets me be close enough to the database to deal with any interesting bits of SQL I might need but am able to support a very abstracted interface.
I have not used the Zend Framework at all. I do not know if they have data-mapper tools that could help you implement the gateway interfaces.

php oop MVC design - proper architecture for an application to edit data

Now that I have read an awfull lot of posts, articles, questions and answers on OOP, MVC and design patterns, I still have questions on what is the best way to build what i want to build.
My little framework is build in an MVC fashion. It uses smarty as the viewer and I have a class set up as the controller that is called from the url.
Now where I think I get lost is in the model part. I might be mixing models and classes/objects to much (or to little).
Anyway an example. When the aim is to get a list of users that reside in my database:
the application is called by e.g. "users/list" The controller then runs the function list, that opens an instance of a class "user" and requests that class to retrieve a list from the table. once returned to the controller, the controller pushes it to the viewer by assigning the result set (an array) to the template and setting the template.
The user would then click on a line in the table that would tell the controler to start "user/edit" for example - which would in return create a form and fill that with the user data for me to edit.
so far so good.
right now i have all of that combined in one user class - so that class would have a function create, getMeAListOfUsers, update etc and properties like hairType and noseSize.
But proper oop design would want me to seperate "user" (with properties like, login name, big nose, curly hair) from "getme a list of users" what would feel more like a "user manager class".
If I would implement a user manager class, how should that look like then? should it be an object (can't really compare it to a real world thing) or should it be an class with just public functions so that it more or less looks like a set of functions.
Should it return an array of found records (like: array([0]=>array("firstname"=>"dirk", "lastname"=>"diggler")) or should it return an array of objects.
All of that is still a bit confusing to me, and I wonder if anyone can give me a little insight on how to do approach this the best way.
The level of abstraction you need for your processing and data (Business Logic) depends on your needs. For example for an application with Transaction Scripts (which probably is the case with your design), the class you describe that fetches and updates the data from the database sounds valid to me.
You can generalize things a bit more by using a Table Data Gateway, Row Data Gateway or Active Record even.
If you get the feeling that you then duplicate a lot of code in your transaction scripts, you might want to create your own Domain Model with a Data Mapper. However, I would not just blindly do this from the beginning because this needs much more code to get started. Also it's not wise to write a Data Mapper on your own but to use an existing component for that. Doctrine is such a component in PHP.
Another existing ORM (Object Relational Mapper) component is Propel which provides Active Records.
If you're just looking for a quick way to query your database, you might find NotORM inspiring.
You can find the Patterns listed in italics in
http://martinfowler.com/eaaCatalog/index.html
which lists all patterns in the book Patterns of Enterprise Application Architecture.
I'm not an expert at this but have recently done pretty much exactly the same thing. The way I set it up is that I have one class for several rows (Users) and one class for one row (User). The "several rows class" is basically just a collection of (static) functions and they are used to retrieve row(s) from a table, like so:
$fiveLatestUsers = Users::getByDate(5);
And that returns an array of User objects. Each User object then has methods for retrieving the fields in the table (like $user->getUsername() or $user->getEmail() etc). I used to just return an associative array but then you run into occasions where you want to modify the data before it is returned and that's where having a class with methods for each field makes a lot of sense.
Edit: The User object also have methods for updating and deleting the current row;
$user->setUsername('Gandalf');
$user->save();
$user->delete();
Another alternative to Doctrine and Propel is PHP Activerecords.
Doctrine and Propel are really mighty beasts. If you are doing a smaller project, I think you are better off with something lighter.
Also, when talking about third-party solutions there are a lot of MVC frameworks for PHP like: Kohana, Codeigniter, CakePHP, Zend (of course)...
All of them have their own ORM implementations, usually lighter alternatives.
For Kohana framework there is also Auto modeler which is supposedly very lightweight.
Personally I'm using Doctrine, but its a huge project. If I was doing something smaller I'd sooner go with a lighter alternative.

Using ORM classes directly from the controller in MVC, bad practice?

I've recently delved into using an ORM in my CodeIgniter application and one i've gone for is Propel. Now this gives me the power to basically use Propels classes as the 'Model' but is this bad practive?
So my controller code would be as follows:
<?php
class Page extends Controller {
function __construct() {
parent::__construct();
}
function index() {
$foo = FooQuery::create()->limit(10)->find();
$data['content'] = array('foo'=>$foo);
$this->load->view('home', $foo);
}
}
?>
I want to solve this issue before I carry on developing my application. An example of how I should do this would be very helpful if you do consider this to be bad practice please.
Thanks in advance
Yes, it's bad practice.
The model should contain all of your data logic and abstract it all away from the rest of the program. To the rest of the application, the models should look like black boxes out of which it gets its data. If you use an ORM as your model, you're leaking the abstraction and tightly coupling your controller to your data layer.
Instead, create your models, and deal with the ORM in there. That way if you ever need to adjust your data model, you can just change it in one place (the model layer) and know that the abstraction will hold.
With the Query classes Propel now uses, I think the difference with a more "formal" Model becomes smaller and smaller. If this will become a library that you release into the world it would be an advantage to have an abstraction layer so you can have different backends, but if it is an in-house application I would just use the Query classes as your Model.
But remember that the Query classes are created to feel like an actual object, and that they hide the relational part as much as they can. You can use this to your advantage. Check out this article about rewriting your SQL queries with Query methods, especially the third answer: move more and more into your Query class, so your Controller doesn't feel like it uses a database.
// Instead of this code in your controller,
// tightly coupled to your database logic
$books = BookQuery::create()
->filterByTitle('%war%')
->filterByPrice(array('max' => 10)
->filterByPublishedAt(array('max' => time()))
->leftJoin('Book.Author')
->where('Author.Name > ?', $fameTreshold);
// You would use this code in your controller
// and create small methods with the business logic in the BookQuery class
$books = BookQuery::create()
->titleContainsWord('war')
->cheap()
->published()
->writtenByFamousAuthors();
I've found this to be an occasional necessary evil when your ORM is following the Active Row pattern.
The problem I always run into is that a model only represents a single instance of the data structure. It makes no sense to add collection retrieval methods into the model.
This is where I have historically used a service layer to handle pulling in collections of models. Although to be honest lately I've simply wrote a controller helper object that just abstracts my table object.
It depends a lot on what you are doing and why. in this example you are putting a limit clause in the query - is that business or display logic? From my perspective, it's hard to argue that it's business logic - that I get back 10 elements is irrelevant to the model - that's just how many I think makes sense to using in one page. If you want that rule to be consistent across controllers, you could set some config value to enforce consistency. But putting it in the model just makes the model needless large (there's a difference between fat models and obese models)
I would say that limits, orders and offsets are often not business logic. Even a simple where might or might not be depending on the case. If there's a join there, it's a sign that something is wrong.
The example from Jan Fabry is mostly pretty good. filterByTitle looks about the same to me as titleContainsWord. filterByPublishedAt(array('max' => time())) is much worse than ->published(). In general, the less you controllers need to know about the inner data structure, the better.

Categories