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

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

Related

Reusing Code In Commands, i.e. Creating a BaseCommand to reuse "use" statements, arguments, and common variables

I'm writing many import commands in Laravel 5.8 that all take the same argument and import a section of the data. For example, I have an ImportUsersCommand.php, ImportFilesCommand.php, and ImportNotesCommand.php that all take a location_id argument (there are a ton more commands, but I'm trying to keep this example simple). The scripts all connect to an external MS SQL Server database specific to that location and then run some code to import the data into a MySQL database.
I've noticed that I'm reusing a lot of the same come, and I'd like to refactor it out to something like a BaseImportCommand.php.
Example Command - ImportUsersCommand.php (What I Currently Have)
<?php
namespace App\Console\Commands\Imports;
use Illuminate\Console\Command;
// Models
use App\Models\Location;
use App\Models\Files;
use App\Models\Notes;
use App\Models\User;
// ... and the list continues with many more models!
use DB;
use Hash;
use Schema;
use Carbon\Carbon;
// ... and the list continues with many more!
class ImportUsers extends Command
{
protected $signature = 'import:users {location_id}';
protected $description = 'Import users from another data source';
public function __construct()
{
parent::__construct();
}
public function handle()
{
$this->info($this->description);
ini_set('memory_limit', '4000M');
$location = Location::findOrFail($this->argument('location_id'));
Config::set("database.connections.chirotouch", [
'driver' => env('SQLSERVER_DB_CONNECTION'),
'host' => env('SQLSERVER_DB_HOST'),
'port' => env('SQLSERVER_DB_PORT'),
'database' => 'location_'.$location->id,
'username' => env('SQLSERVER_DB_USERNAME'),
'password' => env('SQLSERVER_DB_PASSWORD'),
]);
// ... and the code continues just for setting up the command...
// Only after about 100 lines of code do we actually get to the
// specifics of what this particular command does.
foreach ($location->users as $user) {
// Do what I need to do
}
}
}
What I'd like ImportUsersCommand.php to look like
<?php
namespace App\Console\Commands\Imports;
use App\Console\Commands\Imports\BaseImportCommand;
class ImportUsers extends BaseImportCommand
{
protected $signature = 'import:users {location_id}';
protected $description = 'Import users from another data source';
public function __construct()
{
parent::__construct();
}
public function handle()
{
foreach ($location->users as $user) {
// Do what I need to do
}
}
}
But I'm having trouble drafting my BaseImportCommand.php. How can I extract the use statements, the connecting to the external DB, the $this-info() statements, the configuration statments such as increasing the memory limit, and the assignment of the $location variable to another file that can be reused for every import command?
Any help would be much appreciated!
You pretty much have it.
Your custom command extends your common BaseImportCommand which extends Laravel's Command.
You can set up all of your common use statements in your BaseImportCommand file.
And any common code that your commands need for setup can in the __construct() inside BaseImportCommand, which you already have, but it's just empty.

Laravel, change connection in model for one method?

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

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"

Can I remove Request from Laravel Controller

Can I remove the following line of code
use Illuminate\Http\Request;
form laravel Controller? Is this a good practice?
For example, my HomeController:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HomeController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
$totals = [
'customers' => \App\Customer::count(),
'jobs' => \App\Job::count(),
'invoices' => \App\Invoice::count(),
];
$data = [
'page_title' => 'Dashboard',
'totals' => $totals
];
return view('home', $data);
}
}
Here I don't need the "Request", because none of the functions doesn't use that parameter.
To obtain an instance of the current HTTP request via dependency injection, you should type-hint the Illuminate\Http\Request class on your controller method. The incoming request instance will automatically be injected by the service container.
So if you don't want To obtain an instance of the current HTTP request then remove it.
Yes if you are using just select data query you can go ahead and remove this line. It's need where you will use any get or post form in your class function.

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

Categories