Codeigniter 3 Model best practices - LiMingzhe - 07-19-2019
It's a very first post here so...Hi guys My name's Jakub (James for friends), I'm using CI from half and past a year, but I need to know some best approach especialy in Model.
Well I'm trying to achieve an OOP principes in Codeigniter, something like ORM but in simpler way. Usually I'm using a simple spl loader in MY_Loader, with my own classess, where properties look like in tables. But the problem are .... relations - espiecially many to many.
For example - I have Database with User($email, $password, $id), Item($name $id) and relation table ($idUser, $idItem).
And now I want to get items what are related to User by item->name. Database makes results by custom_results_object.
Usually I'm just making a several queries to database, table by table, and operate results by standard php methods, to return an array of needed object.
How it's yours idea? I think it's not a good solution to make a several queries, while I can use for example join method. But how to convert it to objects ?
RE: Codeigniter 3 Model best practices - InsiteFX - 07-20-2019
You can convert the arrays to object like this:
PHP Code: $object = (object)$array;
RE: Codeigniter 3 Model best practices - Wouter60 - 07-20-2019
The database library in CI will return query results as objects by default:
PHP Code: $this->db ->select('name,email') ->from('users') ->where('deleted_at', 0) ->order_by('name', 'ASC'); $query = $this->db->get(); return $query->result();
Now your model returns the records as an array of objects.
If you prefer an array of arrays, then do this:
PHP Code: return $query->result_array();
RE: Codeigniter 3 Model best practices - sintakonte - 07-23-2019
this isn't trivial at all, and i'm unsure about your level but i'll try ...
First of all - i strongly suggest the use of objects (respective classes) in any circumstance - because of its flexibility
any kind of array which holds a set of data (multiple rows) - should be an object (one of the better approaches would be the use of ArrayObjects)
lets take an example based on author and books (one author has many books)
That said your structure should be:
PHP Code: class Collection extends ArrayObject {} class AuthorCollection extends Collection {} class BookCollection extends Collection {}
class Author {} class Book {}
$col = new AuthorCollection();
$objAuthorSK = new Author(); $objAuthorSK->firstame = 'Stephen'; $objAuthorSK->lastname = 'King'; $objAuthorSK->books = new BookCollection();
$col->append($objAuthorSK);
$objBook = new Book(); $objBook->title = 'Carrie'; $objAuthorSK->books->append($objBook);
print_r($col);
You'll see how structured your data are right now
The main problem now is - how to integrate such a simple looking example into Codeigniter - to be honest i just can deliver some abstract basics, because i'm really busy right now
The first thing i would recommend is to deal with the problem how and where to define your relations
For this matter i strongly suggest one model for each corresponding table
the second thing is - you should think about your type of relations (maybe take a look @laravels eloquent)
But for now there are 2 relations important:
(optional for a later use - ManyByIntermediate and OneByIntermediate)
How would this look in our model ?
A possible approach would be (since namespaces and CI are a special topic - i'll stick with the common practice to suffix the names of the respectivce classes.
PHP Code: class Author_model extends ORM_Model { protected $strTable = 'author'; protected $strTableObject = 'Author_Object'; protected $strResultCollection = 'Author_Collection'; public function __construct() { $this->addConnections([ 'book' => Relations_Factory::Many( 'Book_model', [ 'id' => 'author_id' ] ), ]); } }
class Book_model extends ORM_Model { protected $strTable = 'book'; protected $strTableObject = 'Book_Object'; protected $strResultCollection = 'Book_Collection'; public function __construct() { $this->addConnections([ 'author' => Relations_Factory::One( 'Author_model', [ 'author_id' => 'id' ] ), ]); } }
The next thing would be to think about - whats the job of your ORM Model and which functions and processes should be there ...
I for myself would integrate the query builder and use it for your own purpose
it could look like (keep in mind this is just an abstract shot, in order to understand how to achieve a structured query building process)
PHP Code: abstract class ORM_model { protected $strTable = ''; protected $strTableObject = 'OrmTable_Object'; protected $objRelationManager; protected $strIdKey = 'id'; protected $arrConnections = array(); protected $objDb; protected $blnEscapeStrings = true;
private static $arrBufferJoinedAliases = array();
public function __construct(?CI_DB_query_builder $objDb = null, ?Relation_Manager $objRelationManager = null) { $this->objRelationManager = (!is_null($objRelationManager)) ? $objRelationManager : new ORMRelation_Manager($this); $this->objDb = ($objDb) ? $objDb : $this->db; } public function select($mixedSelect, $process = true) { $this->objDb->select($mixedSelect, $this->blnEscapeStrings); return $this; } public function where($strFieldName, $mixedValue, $process = true) { $this->objDb->where($strFieldName, $mixedValue, $this->blnEscapeStrings return $this; } //where_in, or_where, like, or_like, group_start, and so on (the supported Query Builder functions) public function getTableAlias() { return $this->strTableAlias; } private function processFieldNameForQuery($strFieldName) { //in case of a connection if(strpos($strFieldName, ':')) { $arrConnections = explode(':', $strFieldName); $strFieldNameForTargetTable = $this->joinConnectionAndGetFieldNameForTargetTable($arrConnections); } else { $strFieldNameForTargetTable = $this->getTableAlias() . '.' . $strFieldName; } return $strFieldNameForTargetTable;
} private function joinConnectionAndGetFieldNameForTargetTable($arrConnections) { $strCurrentConnection = array_shift($arrConnections); if(array_key_exists($strCurrentConnection, $this->arrConnections)) { $objCurrentConnection = $this->arrConnections[$strCurrentConnection]; if(!in_array($objCurrentConnection->getTargetTableAlias(), CrudDb_Model::$arrBufferJoinedAliases)) { CrudDb_Model::$arrBufferJoinedAliases[] = $objCurrentConnection->getTargetTableAlias(); $objCurrentConnection->performJoinsForQuery($this, $this->objDb); foreach($objCurrentConnection->getTargetModel()->getStandardWhere() as $strFieldName => $strFieldValue) { $this->where($objCurrentConnection->getTargetTableAlias().'.'.$strFieldName, $strFieldValue); } } if(count($arrConnections) == 1) { $strFieldName = array_shift($arrConnections);
if(!strpos($strFieldName, '.')) { $strFieldName = $objCurrentConnection->getTargetModel()->processFieldNameForQuery($strFieldName);
return $strFieldName; } else { return $strFieldName; } } else { return $objCurrentConnection->getTargetModel()->joinConnectionAndGetFieldNameForTargetTable($arrConnections); }
//.... and so on } else { throw new InvalidArgumentException('Provided connection '.$strCurrentConnection.' does not exist in '.get_class($this)); } } }
the Relation builder is still missing -
PHP Code: class Relations_Factory { public static function One($strFieldName, $strTargetModel, $arrObjectToTargetKeys, $arrTargetOptions = array()) { return new One_Relation($strFieldName, $strTargetModel, $arrObjectToTargetKeys, $arrTargetOptions); }
public static function Many($strFieldName, $strTargetModel, $arrObjectToTargetKeys, $arrTargetOptions = array()) { return new Many_Relation($strFieldName, $strTargetModel, $arrObjectToTargetKeys, $arrTargetOptions); } }
Now you have to think about your relation Structure and thats it.
The end goal would be something like:
PHP Code: $colAuthor = $this->Author_model->where('lasname', 'King')->read();
$objAuthor = $colAuthor[0];
//lazy loading principle by calling the corresponding collection - which adds all books to your Authors Objects. $colBooks = $objAuthor->get('book');
There is a topic in the CI4 Forum - for additional infos https://forum.codeigniter.com/thread-71733-page-2.html
|