I'm doing a php MVC project using code igniter. I have two models, a and b.
Each class contains four functions (insert, delete, update and view) and their implementations are almost the same with each other. A friend suggested to put generic versions of the four functions inside a utility class and the two models can access the function their. For example, here is the generic implementation of insert.
public function insert($tableName, $columns, $preds = null)
{
// call code igniter's insert function
}
// do the same with delete, update and view
However, having been introduced to data directed programming before and having recently found out php can have arrays of functions, I think we can make this better.
What I would like to do is: On each class, I am going to create a global array that holds the four code igniter CRUD functions specific to the class with the keys "insert", "add", "delete", "update".
Rather than create four functions for each CRUD operations, I am going to create one utility function and one general execute function for each class.
Note: I am extremely new to php, some of the php code might not work. I have not implemented this directly yet.
// in the utility class
public function execute($dataFunctions, $op, $tableName, $columns)
{
// this will not work, I am not yet familiar with putting functions inside an array
$dataFunctions['op']($tableName,$columns);
}
// on class a
public function execute($op, $columns)
{
// dataFunctions is the name of the global array
utils->execute($dataFunctions,$op,"a",$colums)
}
// same with class b
Thing is, I am not completely sure that this is a good idea. I haven't done this before. I might not be aware of any drawbacks. Should I prefer the way with the array of functions? Or should I just stick to implementing the four crud functions?
1 Answer 1
Have an abstract base class and two concrete derived classes. You didn't tell us what is different, but only said "their implementations are almost the same with each other". Let's assume the database name is the only difference:
abstract class Model_base {
public function insert($tableName, $columns, $preds = null) {
$db = $this->getDB();
// call code igniter's insert function on $db
}
// Gets the database to operate on
abstract function getDB();
}
class a extends Model_base {
function getDB() {
return $this->load->database('db_a', TRUE);
}
}
class b extends Model_base {
function getDB() {
return $this->load->database('db_b', TRUE);
}
}
See also:
https://ellislab.com/codeigniter/user-guide/database/connecting.html Connecting to Multiple Databases
https://ellislab.com/codeigniter/user-guide/database/configuration.html Database Configuration
Edit: Example usage:
You could create two instances:
$modelA = new a():
$modelB = new b():
$modelA->insert(...);
$modelB->insert(...);
Or you could have a model selector:
$model = $useA ? new a() : new b();
$model->insert(...);
Btw, if they actually only differ in selected database, you could also just pass the database name (db_a or db_b) or the Code Igniter database object to a constructor of a single class, no abstract/derived classes required. It all depends on what is different between the classes.
Edit 2: "actually the only difference is the name of the tables and the columns, they both are inside one database"
Given that only the table and column names change:
class Model_base {
private $tableName1;
private $tableName2;
private $colName1;
private $colName2;
function __construct(
$tableName1,
$tableName2,
$colName1,
$colName2
) {
$this->tableName1 = $tableName1;
$this->tableName2 = $tableName2;
$this->colName1 = $colName1;
$this->colName2 = $colName2;
}
public function insert($preds = null) {
// call code igniter's insert function using table and column names given in constructor
// ...($this->tableName1, $this->colName2, ...);
}
}
class Model_a extends Model_base {
function __construct() {
parent::__construct(
'table1_a',
'table2_a',
'col1_a',
'col2_a'
);
}
}
class Model_b extends Model_base {
function __construct() {
parent::__construct(
'table1_b',
'table2_b',
'col1_b',
'col2_b'
);
}
}
Usage is similar to before.
Edit 3: Shorter way if lots of table names, but less "compiler" help:
class Model_base {
private $tableNames;
private $colNames;
function __construct(array $tableNames, array $colNames) {
$this->tableNames = $tableNames;
$this->colNames = $colNames;
}
public function insert($preds = null) {
// call code igniter's insert function using table and column names given in constructor
// ...($this->tableNames['table_1'], $this->colNames['col_2'], ...);
}
}
class Model_a extends Model_base {
function __construct() {
parent::__construct(
array(
'table_1' => 'table_1a',
'table_2' => 'table_2a'
),
array(
'col_1' => 'col_1a',
'col_2' => 'col_2a'
)
);
}
}
class Model_b extends Model_base {
function __construct() {
parent::__construct(
array(
'table_1' => 'table_1b',
'table_2' => 'table_2b'
),
array(
'col_1' => 'col_1b',
'col_2' => 'col_2b'
)
);
}
}
Usage is similar to before.
-
Should I call the abstract insert() in the concrete classes?lightning_missile– lightning_missile2016年04月22日 05:54:13 +00:00Commented Apr 22, 2016 at 5:54
-
Yes, you'd call the method on the instance of the derived class. I have added examples to my answer under "Example usage".Dan Armstrong– Dan Armstrong2016年04月22日 06:00:54 +00:00Commented Apr 22, 2016 at 6:00
-
actually the only difference is the name of the tables and the columns, they both are inside one database.lightning_missile– lightning_missile2016年04月22日 06:11:20 +00:00Commented Apr 22, 2016 at 6:11
-
Look for "Edit 2" above. I gave an example of how the derived classes can provide the table/column names through a constructor call to the base class. Note that the base class is no longer abstract. You could use it directly by instantiating it with arguments, but Code Igniter models expect a zero-arg contructor like used in Model_a and Model_b.Dan Armstrong– Dan Armstrong2016年04月22日 06:25:23 +00:00Commented Apr 22, 2016 at 6:25
-
Fixed "Edit 2" to have no-arg contructors on derived classes. Added "Edit 3" that passes associative arrays of table names and column names. If you have lots of table names this will be shorter and more meaningful than a whole bunch of individual unnamed parameters to the base constructor.Dan Armstrong– Dan Armstrong2016年04月22日 06:47:04 +00:00Commented Apr 22, 2016 at 6:47
Explore related questions
See similar questions with these tags.
$dataFunctions[$op]($tableName,$columns);