Welcome Guest, Not a member yet? Register   Sign In
Codeigniter 3 Model best practices
#4

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:

  • One
  • Many
(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
Reply


Messages In This Thread
Codeigniter 3 Model best practices - by LiMingzhe - 07-19-2019, 03:30 PM
RE: Codeigniter 3 Model best practices - by sintakonte - 07-23-2019, 08:20 AM



Theme © iAndrew 2016 - Forum software by © MyBB