Laravel Eloquent: Accessing properties and Dynamic Table Names
I assume you know how to navigate the Laravel API / codebase since you will need it to fully understand this answer...
Disclaimer: Even though I tested some cases I can't guarantee It always works. If you run into a problem, let me know and I'll try my best to help you.
I see you have multiple cases where you need this kind of dynamic table name, so we will start off by creating a BaseModel
so we don't have to repeat ourselves.
class BaseModel extends Eloquent {}
class Team extends BaseModel {}
Nothing exciting so far. Next, we take a look at one of the static functions in Illuminate\Database\Eloquent\Model
and write our own static function, let's call it year
.
(Put this in the BaseModel
)
public static function year($year){
$instance = new static;
return $instance->newQuery();
}
This function now does nothing but create a new instance of the current model and then initialize the query builder on it. In a similar fashion to the way Laravel does it in the Model class.
The next step will be to create a function that actually sets the table on an instantiated model. Let's call this one setYear
. And we'll also add an instance variable to store the year separately from the actual table name.
protected $year = null;
public function setYear($year){
$this->year = $year;
if($year != null){
$this->table = 'gamedata_'.$year.'_'.$this->getTable(); // you could use the logic from your example as well, but getTable looks nicer
}
}
Now we have to change the year
to actually call setYear
public static function year($year){
$instance = new static;
$instance->setYear($year);
return $instance->newQuery();
}
And last but not least, we have to override newInstance()
. This method is used my Laravel when using find()
for example.
public function newInstance($attributes = array(), $exists = false)
{
$model = parent::newInstance($attributes, $exists);
$model->setYear($this->year);
return $model;
}
That's the basics. Here's how to use it:
$team = Team::year(2015)->find(1);
$newTeam = new Team();
$newTeam->setTable(2015);
$newTeam->property = 'value';
$newTeam->save();
The next step are relationships. And that's were it gets real tricky.
The methods for relations (like: hasMany('Player')
) don't support passing in objects. They take a class and then create an instance from it. The simplest solution I could found, is by creating the relationship object manually. (in Team
)
public function players(){
$instance = new Player();
$instance->setYear($this->year);
$foreignKey = $instance->getTable.'.'.$this->getForeignKey();
$localKey = $this->getKeyName();
return new HasMany($instance->newQuery(), $this, $foreignKey, $localKey);
}
Note: the foreign key will still be called team_id
(without the year) I suppose that is what you want.
Unfortunately, you will have to do this for every relationship you define. For other relationship types look at the code in Illuminate\Database\Eloquent\Model
. You can basically copy paste it and make a few changes. If you use a lot of relationships on your year-dependent models you could also override the relationship methods in your BaseModel
.
View the full BaseModel
on Pastebin
How to dynamically set table name in Eloquent Model
The following trait allows for passing on the table name during hydration.
trait BindsDynamically
{
protected $connection = null;
protected $table = null;
public function bind(string $connection, string $table)
{
$this->setConnection($connection);
$this->setTable($table);
}
public function newInstance($attributes = [], $exists = false)
{
// Overridden in order to allow for late table binding.
$model = parent::newInstance($attributes, $exists);
$model->setTable($this->table);
return $model;
}
}
Here is how to use it:
class ProductLog extends Model
{
use BindsDynamically;
}
Call the method on instance like this:
public function index()
{
$productLog = new ProductLog;
$productLog->setTable('anotherTableName');
$productLog->get(); // select * from anotherTableName
$productLog->myTestProp = 'test';
$productLog->save(); // now saves into anotherTableName
}
Laravel query builder - dynamic table name
What do you mean with "dynamic query"?
$users = DB::table($tableName)->where('name', $name)->get();
In this case you can change dynamically $tablename and also the variable $name, so you can catch everything you need. Also you can use a variable in the first parameter of the method where().
So if you want to dynamically change the table name you can do something like this:
$names = ['users', 'posts', 'comments'];
foreach($name as $names){
$res= DB::table($tableName)->where('active', 1)->get();
// do something with the result
}
I don't know if I answered your question.
How to return database table name in Laravel
There is a public getTable() method defined in Eloquent\Model so you should be able to use $model->getTable()
.
Related Topics
Utf8 Filenames in PHP and Different Unicode Encodings
How to Set an Absolute Include Path in PHP
How to Pass a Parameter Like Title, Summary and Image in a Facebook Sharer Url
Detect "Overall Average" Color of the Picture
List of Us Time Zones for PHP to Use
Minifying Final HTML Output Using Regular Expressions with Codeigniter
How to Convert the Time from Am/Pm to 24 Hour Format in PHP
Getting MySQL_Insert_Id() While Using on Duplicate Key Update with PHP
Best Practice for Working with Currency Values in PHP
Cannot Call Function SQLsrv_Connect()
A Script to Change All Tables and Fields to the Utf-8-Bin Collation in MySQL
How to Remove a Key and Its Value from an Associative Array
Send Email from Localhost with Gmail(Windows)
How Is Annotation Useful in PHP
Read in Text File Line by Line PHP - Newline Not Being Detected