Laravel, change connection in model for one method? - php

I have got a dev database and a live database. I need to return some results from the live database but only for one method within this model.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class TableName extends Model
{
protected $table = 'table_name';
protected $connection = 'dev';
public $timestamps = false;
public static function live($index) {
$liveId = Settings::where('index', $index)->get()[0];
$live = new TableName;
$live->setConnection('live');
$data = $live::where('index', $liveId->live_index)->get();
dd($live);
return $data;
}
}
If I dd() the $live variable after calling setConnection then it does say that the connection is indeed live. However as soon as I dd() the $data I get the rows from the dev database!

Eloquent provides a nice way to handle multiple connections.
You should just be able to use the on method. For example.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class TableName extends Model
{
protected $table = 'table_name';
protected $connection = 'dev';
public $timestamps = false;
public static function live($index) {
$liveId = Settings::where('index', $index)->get()[0];
$data = self::on('live')->where('index', $liveId->live_index)->get();
return $data;
}
}
That should then run the query using the live connection in your database configuration.

I have personally haven't done anything like this, but I found out way to do this by following these steps.
In the .env file add these new env variables =>
DB_CONNECTION_2=mysql
DB_HOST_2=127.0.0.1
DB_PORT_2=3306
DB_DATABASE_2=database2
DB_USERNAME_2=root
DB_PASSWORD_2=secret
Now inside the config/database.php file specify the 2nd mysql connection with the previously entered env variables.
'mysql2' => [
'driver' => env('DB_CONNECTION_2'),
'host' => env('DB_HOST_2'),
'port' => env('DB_PORT_2'),
'database' => env('DB_DATABASE_2'),
'username' => env('DB_USERNAME_2'),
'password' => env('DB_PASSWORD_2'),
],
Now you can create a Model for the required table =>
class myModel extends Eloquent {
protected $connection = 'mysql2';
}
Then you can use it as the regular way will all the Eloquent features in controller methods =>
$newMy = new myModel;
$newMy->setConnection('mysql2');
$newMy = $someModel->find(1);
return $something;
Here is the doc link that you can read about this more.

You can try to get the default connection before the point with
$defaultConnection = DB::getDefaultConnection();
then change the default connection to before obtaining the results from 'live'
DB::setDefaultConnection('live');
and then restore the connection as soon as 'live' connection is no longer needed
DB::setDefaultConnection($defaultConnection);
As an alternative you can generate your data using DB::connection('live'). More info at Using Multiple Database Connections

Related

Laravel Mongodb - Can't get the data from the collection

I have an application using Vue + Laravel and I am using mysql database. Now, I need to use mongodb database too.
So, here is my live mongodb database table (projects) and collection (product_1, product_2 etc...)
Like this:
https://prnt.sc/D08akhBur6z4
Now, I want to get all the collection. To do that I have created Model called Import
Import.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Jenssegers\Mongodb\Eloquent\Model;
class Import extends Model
{
protected $connection = 'mongodb';
protected $collection = 'projects';
}
and created a controller called ImportController.php.
ImportController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use App\Models\Import;
class ImportController extends Controller
{
public function show_import () {
$all_import = Import::all();
return response()->json( $all_import, 200);
}
}
.env file
MONGO_DB_HOST=107.200.220.71
MONGO_DB_PORT=57019
MONGO_DB_DATABASE=projects
MONGO_DB_USERNAME=marketplus_pr
MONGO_DB_PASSWORD="my-password"
database.php
'mongodb' => [
'driver' => 'mongodb',
'dsn' => 'mongodb+srv://marketplus_pr:my-password#107.200.220.71/projects?retryWrites=true&w=majority',
'database' => 'projects'
],
Now using this api route call:
http://localhost:3000/api/projects/import/show-import/343-3-3-3-3
I am getting this message:
{"success":false}
But Its should give me all the collection, right?
Can you tell me what I am doing wrong here?
Your request is being intercepted by a different route declaration / controller. (chat reference) Also, wrong collection name.
You should make a few changes in the api.php file:
Move this route declaration:
Route::get('projects/import/show-import/{token}', [App\Http\Controllers\ImportController::class, 'show_import'])->name('show_import');
just after:
Route::group([], function ($router) {
making it as:
Route::group([], function ($router) {
Route::get('projects/import/show-import/{token}',
[App\Http\Controllers\ImportController::class, 'show_import'])-
>name('show_import');
...
}
also, the {token} URL parameter makes not sense so you should remove it.
and, change the collection name to products_1 in the Import.php model file:
class Import extends Model
{
protected $connection = 'mongodb';
protected $collection = 'products_1'; // this should be collection name and not the database name: products_1, products_2, etc.
...
}
By default mongodb runs on port 27017, but looking at your connection string you are not sending that port to the connection. In case you are sure you are running mongodb in that port your connection string needs to be:
mongodb+srv://marketplus_pr:my-password#107.200.220.71:57019?retryWrites=true&w=majority
On the other hand if you are not set the port at the moment of running your mongodb instance, this would be 27017, so the connection string will be:
mongodb+srv://marketplus_pr:my-password#107.200.220.71:27017?retryWrites=true&w=majority

Laravel 6: User models uses UUID instead of auto-increment. Where to update DB session logic?

OK so my User models uses webpatser/laravel-uuid. All migrations are using UUID.
So now my model looks like:
<?php
namespace App\Models;
use App\Models\Traits\Uuid;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Hash;
class User extends Authenticatable
{
use Notifiable;
use Uuid;
public $incrementing = false;
public $timestamps = true;
protected $guarded = [
'uuid',
];
protected $keyType = 'string';
protected $primaryKey = 'uuid';
protected $table = 'users';
protected $dates = [
'created_at',
'updated_at',
];
protected $hidden = [
'password',
'remember_token',
];
public function setPasswordAttribute($password): void
{
$this->attributes['password'] = Hash::make($password);
}
}
I want to use database session driver. I created session table via php artisan session:table. All migrations are done. I obviously had to rename existing user_id column. I've changed it to user_uuid. I know it's not enough as I can't find the logic responsible for populating this db table. I guess it's somewhere in the vendor (Illuminate).
Where is the logic to populate my non-default session column?
Now each open the page gives:
So I know what's the issue, what's causing it, how to change it, but I don't know where to start. Thanks for any hints.
I think you would benefit of a custom session handler because the name of the column user_id is hardcoded into the addUserInformation() method.
Extend the existing DatabaseSessionHandler.php and replace the addUserInformation() method so it looks for the correct column name:
class DatabaseUuidSessionHandler extends DatabaseSessionHandler
{
protected function addUserInformation(&$payload)
{
if ($this->container->bound(Guard::class)) {
$payload['user_uuid'] = $this->userId();
}
return $this;
}
}
Register it in one of your service providers:
class SessionServiceProvider extends ServiceProvider
{
public function boot()
{
Session::extend('databaseUuid', function ($app) {
return new DatabaseUuidSessionHandler;
});
}
}
Finally update SESSION_DRIVER in your .env to use the newly created databaseUuid driver.
Remember that this is untested code and should only be used as a guideline of how this could work.

yii2-redis find() returns empty results

I have the following simple model:
<?php
namespace app\models;
use Yii;
use yii\base\Model;
use \yii\redis\ActiveRecord;
use \yii\db\ActiveQuery;
class StatsModel extends ActiveRecord
{
public function attributes()
{
return ['user'];
}
public function rules()
{
return [
['user' : 'string']
];
}
public static function getDb()
{
return \Yii::$app->db_redis;
}
}
\Yii::$app->db_redis; is a config in web.php:
<?php
return [
'class' => 'yii\redis\Connection',
'hostname' => 'localhost',
'port' => 6379,
'database' => 0
];
I do in the redis-cli:
127.0.0.1:6379> select 0
OK
127.0.0.1:6379> hmset key123 user michael
OK
127.0.0.1:6379>
But when i do $test = \app\models\StatsModel::find()->all(); inside layout view i see in the xdebug debugger, that it returns empty set, like there are no records inside redis. I can't understand why, i just added a user and a key to database with index 0. Can someone explain it
ActiveRecord for redis uses dedicated structure and multiple keys to store data about models. Don't expect that you can push some data with random keys and it will be interpreted as active record model. StatsModel::find()->all() does not return anything, because you've not created any model - you've pushed some data to redis, but this is not a active record model. You should use ActiveRecord to save model, if you want to use it with StatsModel::find():
$model = new StatsModel();
$model->id = 1;
$model->user = 'rob006';
$model->save();
$result = StatsModel::find()->all(); // finds one model
Or don't use ActiveRecord and use queries directly:
$result = Yii::$app->db_redis->hget('key123', 'user'); // "michael"

Laravel relationship DB connection

I m trying to get Model relationship with different connection, basically my connections are dynamic.
$con = 'con1'
$persons = new \App\Models\Person;
$persons->setConnection($con);
$persons = $persons->where('somevalue', 1)->get()
So here I get Person from con1 (where con1 is stored in config/databse.php
It can be con2, con3, con4 and etc.
However this works, but when I am trying to loop through this data and get relationship it switches to default Database connection.
#foreach($persons as $person)
{{$person->data->name}}
#endforeach
In above loop data is a belongsTo relation ship in Person Model, and it throws error because it switches back to default Database connection and not using con1
It is possible to setConnection() and keep for hasMany relationship and also for belongsTo relationship?
I cant set protected $connection; in Model because connections are changble
What I tried until now is I created an absctract class that extendseloquent, and my models extending this abstract class
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model as Eloquent;
abstract class Database extends Eloquent {
protected $connection;
}
<?php
namespace App\Models;
use App\Models\Database as Database;
class Person extends Database{
protected $table = 'persons';
}
So theoritically when I setConnection I set connection to all models that extends this class but still no luck.
You may try eager loading of the relationship:
$persons = $persons->with('data')->where('somevalue', 1)->get();
I found a solution maybe wrong but is working:
I create a file in config where I add all my connections:
<?php
return [
'con1' => [
'name' => 'Persons Connection',
'url' => 'persons',
'active' = true
],
'con2' => [
'name' => 'Italy Persons Connection',
'url' => 'italypersons',
'active' = false
],
];
So like this I can event control if con2 is available
In Database connection config file I have con1 connection with all db data
After in routes.php a bind the url example /info/{con} where con = 'persons'
Route::bind('con', function($con, $route){
foreach(config('connections') as $key => $value){
if($value['url'] == $con && $value['active'] == true){
session(['connection' => $key]); //where $key == con1
return $key;
}
abort(404);
}
});
So: I have a Class Person that extends abstract method with __construct function
<?php
namespace App\Models;
use App\Models\Database as Database;
class Person extends Eloquent{
protected $table = 'persons';
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model as Eloquent;
abstract class Database extends Eloquent {
function __construct(array $attributes = array())
{
parent::__construct($attributes);
$this->setConnection(session('connection'));
}
}
So like this I am sure if user get to URL /info/{con} It will set the connection sessions if it exist in my connections config file, without losing sensitive data from config/database.php
If somebody have better idea please write it

Accessing dependency injected class variables

I'm currently injecting my eloquent models in my controllers like this:
class ComputerController extends BaseController {
public function __construct(User $user, Machine $machine, MachineType $machineType){
$this->user = $user;
$this->machine = $machine;
$this->machineType = $machineType;
}
So I can access the models quickly with:
$this->machine->get();
But how to I access the properties such as validation rules that are stored in the class?
I used to use
Machine::$rules;
But using this method
$this->machine->$rules
Does not work. Is there a way to retrieve the rules array that is stored in the eloquent model?
This is my class as an example:
class Machine extends Eloquent {
protected $table = 'machines';
public $timestamps = true;
protected $softDelete = true;
public static $rules = array(
'computer_name' => 'required|min:2',
'computer_user' => 'required',
'computer_ip' => 'ip'
);
Thanks a lot!
Edit:: Tried this according to Antonio just to test, still no avail, brings an error when I run it.
Error:
For static variables, this should work fine:
$this->machine::$rules
EDIT:
Somehow using an object this way it doesn't work, but here's a workaround:
$machine = $this->machine;
dd($machine::$rules);

Categories