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