Can Laravel 4 relations use different databases - laravel-4

At work we use Nagios for our monitoring platform and we have an in house written configuration generator.
I am planning on re-writing this using Laravel 4. Our setup is that we support multiple clients who all will have their own configuration. For security reason we have each clients configuration stored in a separate database and the database credentials are supplied to the front end using environment variables in the Apache configuration (each client is using a different TCP port).
The problem is that for each client there are database tables that are common to every client i.e. Time Periods, Contacts, etc. At present if we want to change a common item we have to do this on all databases manually (although I have scripted this from the cli)
I wish to separate out the common elements into one database and and have the client specific items in their own database.
I know that Laravel is capable of easily having more than one database connection but my question is is it possible to create Eloquent relationships between tables in two different databases.
An example would be a Service in the client database has a timeperiod_id column which is a foreign key to the primary key in the timeperiod table in shared database.
I want to be able to seamlessly do something like below in the controller (with the approriate relations in the model.
$services = Service::all();
and in the blade template view
#foreach ($services as $service)
{{ $service->name }}
{{ $service->timeperiod->name }}
#endforeach
The Laravel documentation and google dont seem to shed any light on whether this is possible.
Any help greatly appreciated

I am currently doing this in one of my laravel projects.
you can specify a foreign key to match on and also a different primary key if you want.
class TimePeriod extends Eloquent {
protected $connection = 'some_Db';
protected $table = 'time_period';
protected $primaryKey = 'id';//can set this to anything, will default to auto incr id(optional)
public function Services() {
return $this->hasone('Services', 'time_period_id');//specify the foreign key as second param
}
}
class Services extends Eloquent {
protected $connection = 'client';
protected $table = 'services';
public function TimePeriod() {
return $this->belongsto('TimePeriod', 'id');//specify the foreign key as second param
}
}

Related

Implementing Composite Keys in CodeIgniter Models

Is there any way you could implement composite primary keys using Models in CodeIgniter 4?
Like this?
class SomeModel extends Model{
protected $table = 'table';
protected $primaryKey1 = 'primary_composite_id1';
protected $primaryKey2 = 'primary_composite_id2';
protected $primaryKey3 = 'primary_composite_id3';
// numbers in the identifiers were only added for clarity
...
}
I think you can define the table structure using the Forge class. Here is a snippet of how I defined the table in Migrations.
in SomeMigration.php
class SomeClass extends Migration{
/* added fields here */
...
// Set them as foreign keys
$this->$forge->addForeignKey('item_id', 'item', 'item_id', 'CASCADE', 'CASCADE');
$this->$forge->addForeignKey('poster_uid', 'user', 'user_id', 'CASCADE', 'CASCADE');
$this->$forge->addForeignKey('customer_uid', 'user', 'user_id', 'CASCADE', 'CASCADE');
// Set them as primary keys
$this->$forge->addPrimaryKey('item_id');
$this->$forge->addPrimaryKey('poster_uid');
$this->$forge->addPrimaryKey('customer_uid');
...
}
Also, if setting composite primary keys in Models are not possible, should I
Create a new primary key column for that table instead?
Leave out the $primarykey value as empty and use just use queries (e.g. using WHERE)?
Use any one of the columns(set as PK) in the table as the value for $primarykey?
questions were created based on this post Codeigniter MY_Model composite primary key, since the answer did not directly answer the question
I am currently using the framework for our school project. There was none mentioned in the documentation, so I got stuck. Any kind of alternative solution is very much appreciated. Thanks! Cheers!
I have run into the same problem these days.
It seems that Codeigniter doesn't support this functionality for the model's primary key.
I searched in documentation and in Model's source code and I saw that it handles the primary key like one value.
e.g. at models find method I can see this code:
$row = $builder->whereIn($this->table . '.' . $this->primaryKey, $id)
In my case I will add an extra ID column and use this as a primary key. If I find a better alternative in the future I will update here.
Best Regards

laravel/elequent - models and relations

I trying to learn laravel and to do some tests/demo apps. I've struggling now with laravel/eloquent tables relations. And I need advice.
I have 3 models [Application, Term, AppState] and their tables applications[id, terms_id, appStates_id, and other cols ], terms[id, startDate, endDate, ...], app_states[id, caption]
Application.php
public function term()
{
return $this->belongsTo('App\Term');
}
public function appState()
{
return $this->belongsTo('App\AppState');
}
in Term.php and AppState.php i have:
public function applications()
{
return $this->hasMany('App\Application');
}
How I can get let's say "caption"/"startDay"+"endDate" in blade for each application? I can get their ids $app->terms_id/$app->appStates_id in foreach loop, but i want get caption value from app_states table.
Has to be this relations also specified in migrations? In some tuts is mentioned, that is not needed in case i want to handle it only in laravel.
Thanks for advice
You can access a model's relationship values by calling the relationship method like a property.
$application = Application::find(1);
$application->term->startDate;
$application->term->endDate;
$application->appState->caption;
Also your relationship with AppState is wrong, since your foreign key doesn't follow a snake_case typing, you'll need to provide the appropriate key for it
public function appState()
{
return $this->belongsTo('App\AppState', 'appStates_id');
}
You might also want to check terms_id as well since the model name (Term) is singular but the foreign key is plural.
Has to be this relations also specified in migrations? In some tuts is mentioned, that is not needed in case i want to handle it only in laravel.
Well, yes, you don't need to if Laravel will only be the one accessing that database. But if any cases in the near future you decide to migrate to a different framework or use the same database in another application, it's better to include these relationships in the migration. Also a database administrator would probably cringe if you don't.
So provided your relationships are correctly setup, you can access them anywhere you have an instance of that model.
So for example, lets say you have passed a collection of applications to your view ($apps):
#foreach($apps as $app)
{{ $app->term->startDate }}
{{ $app->term->endDate }}
{{ $app->appState->caption }}
#endforeach
Important Note: We are accessing the Eloquent relationship using ->appState rather than ->appState(). The later is actually accessing a Query Builder instance and has some more advanced use cases

Laravel store data thru model

I dont know how else to label the title. Anyone have ideas go ahead and make a suggested edit.
I have a series of Models for the database in my application.
I can currently add a global scope to the model and have the model automatically add a "where" clause on my queries to the database on a key:value pair. This is working great.
class Customers extends Model
{
protected $table = 'customers';
protected static function boot() {
parent::boot();
static::addGlobalScope('companyRecordID', function (Builder $builder) {
$builder->where('companyRecordID', Auth::guard('user')->user()->companyRecordID);
});
}
}
I am having troubles trying to identify if this can be done; Id like to be able to store the "companyRecordID" from the Auth::guard('user')->user()->companyRecordID automatically when a database record is created. Similar to created_at and updated_at are created automatically without requiring code from the controller to define.
Can someone direct me to what I should be looking for. Ive spent a few hours trying to google key word pairs to find an answer with no avail.
If you are using Models to create the records you can listen for the creating event for the Model and then add any additional fields you may need. You can create a listener for the creating event on Customers:
Customers::creating(function ($customer) {
if (auth('user')->user()) {
$customer->companyRecordID = auth('user')->user()->companyRecordID;
}
});
You can throw that in a Service Provider's boot method or your Model's boot method. If you throw it in the Model's boot method you may want to adjust to using static:: instead of Customers::.
I believe you got your answer but,
On your model please use protected $fillable
protected $fillable = ['','',''];
protected $table = 'customers';
also, you can use Relationships to optimize your codes.

Laravel - Using different field names in the database (userid in a table and created_by in other)

I am trying to use a table for my Users and separate table for users' Projects in my database. However I want the names of the fields to be different for user id. What I want to take the id from the 'Users' table; and while saving the created project to the database, use that (user) id as created_by_id in Projects table.
public function store(CreateProjectRequest $request)
{
$project = new Project($request->all());
Auth::user()->projects()->save($project);
// Project::create($request->all());
return redirect('pages/home');
}
Also in Users.php, I added:
public function projects()
{
return $this->hasMany('App\Project');
}
The commented field is working on its own. However, I guess my problem arises because when I comment that line again, and add the other two lines ($project... and Auth::user... bits), I guess it is assuming I have a field in the Projects table named id.
I thought I would work around this problem with changing the primary key but I couldn't find how to take the Auth::user()->id; and make it write that value in created_by_id in a secure way. This is what I found though:
class Project extends Eloquent {
protected $primaryKey = 'created_by_id';
}
Edit: I don't think changing the primary key is my solution.
You can pass a second and third parameter to hasMany() method to specify the keys to use. Documentation
public function projects()
{
return $this->hasMany('App\Article','userid','created_by');
}

Laravel - Multi-tenancy - One database multiple tables

I want to create a multi tenancy application using Laravel. I am using the one database, multiple tenant tables database architecture.
I want to create a new set of tenant related tables dynamically, whenever someone registers a new tenant account.
Please consider the following:
tenants table holds all the client registrations. Each tenant will have dedicated tables only for them. In this example every tenant has their own dedicated customer table.
Ex:
tenant01's tables will have tenant01 prefix. (tenant01.customer - only tenant01's customers)
tenant02's tables will have tenant02 prefix. (tenant02.customer - only tenant02's customers)
I don't want to use multiple databases as they are costly and I don't want to use one table for all the tenants, as there will be lots of customers/products etc in the system.
I'm planning to identify the tenant at the logging process and set the tenant name(or a code/Id) in a session. ex: tenant440
After that, in all customer related eloquent model classes, I could dynamically append that prefix (ex: tenant440) into the table name like this:
<?php
class Customer extends Eloquent {
protected $tenant_name = //get name/code from the session. ex: tenant440
//table name will become tenant440.'customers'
protected $table = $tenant_name.'customers';
?>
Is this a correct way to achieve this? What is the simplest to do this? Do you know any kind of resources/packages/libraries for this?
Thanks in advance!
You can set tenant name as a prefix in your database file:
Config::set('database.connections.mysql.prefix',$tenantName); // assuming 'mysql' is the default database connection name
I recommend to put it inside a filter
// routes.php
Route::group(array('before'=>'setTablePrefix'), function($noob)
{
Route::resource('customers', 'CustomersController');
Route::controller('sales', 'SalesController');
});
Route::get('/login',array('as' => 'login', 'uses' => 'UserController#getLogin'));
// filters.php
Route::filter('setTablePrefix', function($route, $request)
{
if (!Session::has('prefixTable'))
App::abort(404);
Config::set('database.connections.mysql.prefix',Session::get('prefixTable'));
});
To get data from all tables, you probably need two queries (or one if you use Session)
$tenants = DB::table('tenants')->lists('name'); // you can set it in Session
if($tenants){
$allCustomers = DB::table($tenants[0].'.customers');
for ($i = 1; $i < count($tenants); $i++) {
$allCustomers->unionall(DB::table($tenants[$i].'.customers'));
}
var_dump($allCustomers->get());
}

Resources