Reputation: 2494
I have a number of functions that are used by most of my models
so it makes sense to store them centrally rather than repeating code.
For example, I have a function that finds a random row from whichever table I need:
function getRandomRow() {
$rowCount = DB::connection('mydatabasename')
->table('my_table_name')
->selectRaw("FLOOR(RAND() * COUNT(*)) AS offset")
->first();
$offset = $rowCount->offset;
$randomRow = DB::connection('mydatabasename')
->table('my_table_name')
->select()
->offset($offset)
->limit(1)
->first();
return $randomRow;
}
I've looked at inheritance (extends) and traits - as well as the docs on polymorphic relations - but it's not clear which is the most efficient and how to access the table name (associated with the model being used) within the common function.
My questions:
- where do I put this function so that it can be used by all models ?
- how do I write the code so that the 'my_table_name'
uses the correct model table ?
Upvotes: 1
Views: 5939
Reputation: 2494
The simplest solution I found is to create a parent model / class - as noted in this answer to a different question - for the current example let's call it BaseModel
.
For Laravel this is stored along with the other models, directly in the App
directory
...in my case the parent model / class can be abstract
as it doesn't need to have it's own table (also meaning the BaseModel
functions can only be accessed via a child model):
namespace App;
use Illuminate\Database\Eloquent\Model;
abstract class BaseModel extends Model
{
// ...put common model functions here
}
The trick to get this working (where a BaseModel
function will need to access a child model's table) is to:
- have each child model / class extend
the BaseModel
class
- ensure that the $table
is defined in all the child models - as noted here:
class MyFunkyModel extends BaseModel
{
protected $table = 'funktown';
// ...put child specific functions here
}
which means $this->table
can be used in the BaseModel
abstract parent class to reference the designated $table
of the child model / class:
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
abstract class BaseModel extends Model
{
function getRandomRow() {
$rowCount = DB::connection('mydatabasename')
->table($this->table)
->selectRaw("FLOOR(RAND() * COUNT(*)) AS offset")
->first();
$offset = $rowCount->offset;
$profileRow = DB::connection('mydatabasename')
->table($this->table)
->select()
->offset($offset)
->limit(1)
->first();
return $profileRow;
}
}
Now from a controller you can access any functions stored in the BaseModel
simply via the child model(s):
namespace App\Http\Controllers;
use App\MyFunkyModel;
use App\MySeriousModel;
use App\MyHappyModel;
class MyController extends Controller
{
public function getRandomName($type){
switch ($type) {
case 'funky':
$modelFunky = new MyFunkyModel;
$funkyRow = $modelFunky->getRandomRow();
$randomName = $funkyRow->funky_name_column;
break;
case 'serious':
$modelSerious = new MySeriousModel;
$seriousRow = $modelSerious->getRandomRow();
$randomName = $seriousRow->serious_name_column;
break;
case 'happy':
$modelHappy = new MyHappyModel;
$happyRow = $modelHappy->getRandomRow();
$randomName = $happyRow->happy_name_column;
break;
return $randomName;
}
}
Upvotes: 4
Reputation: 3704
You can use both inheritance
and trait
for this. But highly recommend to use Eloquent
models rather than DB::table()
. The reason is if somehow the table name get changed you have to change it everywhere. With Eloquent
you only need to mention table name once in you model.
protected $table = 'new_table_name'
using inheritance
structure you BaseModel
and class
as follows.
class BaseModel extends Model {
public static function getRandomRow()
{
$rowCount = self::selectRaw("FLOOR(RAND() * COUNT(*)) AS offset")
->first();
$offset = $rowCount->offset;
$randomRow = self::select()
->offset($offset)
->limit(1)
->first();
return $randomRow;
}
}
class YourModel extends BaseModel {
// getRandomRow() available here
}
using trait
structure your trait
and class
as follows.
trait BaseTrait {
public static function getRandomRow()
{
$rowCount = self::selectRaw("FLOOR(RAND() * COUNT(*)) AS offset")
->first();
$offset = $rowCount->offset;
$randomRow = self::select()
->offset($offset)
->limit(1)
->first();
return $randomRow;
}
}
class YourClass {
use BaseTrait;
// getRandomRow() available here
}
Either way you can access your method like
class yourController {
public function youMethod()
{
$rows = YourModel::getRandomRow();
}
}
Upvotes: 4