Laravel Guzzle Request gets wrong DB Connection - php

I am trying to make a request from one Laravel project to another. The issue that I am getting is that the second Laravel is using the first Laravel Database Connection. So it is complaining that a table does not exist.
Here is the code that I am using.
$data = ['test' => 'foobar'];
$client = new \GuzzleHttp\Client();
$url = getenv('API_BASE') . 'stock-list';
$res = $client->request('POST', $url, [
'headers' => [
'X-Public' => getenv('API_PUBLIC'),
'X-Hash' => ApiService::Encrypt(getenv('API_PRIVATE'), json_encode($data)),
],
'json' => $data,
'http_errors' => false,
]);
echo "<pre>" . print_r($res->getBody()->getContents(), true) . "</pre>";
Has anyone ever come across something like this?

The way to fix this as I am running both Laravel projects on the same server, is to change the environment variable names in the .env file.
DB_DATABASE=XXXX
becomes
XXX_DB_DATABASE=XXXX
This needs to be done on one of the Laravel setups then it all works properly.

You can change the default db connection runtime like this:
So let's say you have
1 security db with credentials that is the default db design time.
1 or more databases containing data for 1 or more users.
You log in using the security db and based on the user change the default db to the data db.
config(['database.connections.data' => array(
'driver' => 'sqlsrv',
'host' => $connection['Database_Server'],
'database' => $connection['Database_Name'],
'username' => $connection['Database_User'],
'password' => $connection['Database_Password']
)]);
DB::setDefaultConnection('data');
If you don't need such flexibility you can define the connection per model:
class A extends Model {
protected $connection = 'security';
protected $table = 'A';
}

Related

Correct way to edit a database service after first initiation

I use two different database services in my Phalcon application.
db: Global database with system-wide data, including accounts and users
db_data: This database hosts customer-specific data. The database-name is different for each customer/account. This is determined when the customer sign in.
This works in the web application, when I have one account active. Now I have a cronjob, that is going to loop through a table in the global "db" database. And after it is going to connect to the specific "db_data" database.
This works for the first account, but after this it will not connect to the new database. It still use the first initiated database.
The db_data service is a shared service in the services.php:
$di->set('db_data', function () use ($config, $di) {
if(!$di->getCore()->getAccount()) {
throw new \MyNamespace\Exception(_('Account is not set. Can not load account database.'));
}
$eventsManager = $di->getShared('eventsManager');
$dbListener = new \MyNamespace\Module\Core\Helper\Model\DatabaseListener();
$eventsManager->attach('db_data', $dbListener);
$connection = new \Phalcon\Db\Adapter\Pdo\Mysql(array(
'host' => $config->database->host,
'username' => $config->database->username,
'password' => $config->database->password,
'dbname' => $config->database->data_dbname_prefix.$di->getCore()->getAccount()->id,
'name' => 'data',
));
$connection->setEventsManager($eventsManager);
return $connection;
}, true);
In the first model in "db" i have the following in the initialize() function:
$this->setConnectionService('db');
In the second model in "db_data" i have the following in the initialize() function:
$this->setConnectionService('db_data');
Here is an example of the cron PHP-file:
$screens = \MyNamespace\Module\DigitalSignage\Model\Screen::find(array(
'conditions' => 'deleted_at IS NULL',
));
foreach($screens as $screen) {
$console->getDi()->getCore()->setAccount(\MyNamespace\Module\Core\Model\Account::findFirst('id='.$screen->account_id));
$campaign = \MyNamespace\Module\DigitalSignage\Model\Campaign::findFirst(array(
'conditions' => 'id = :id: AND account_id = :account_id: AND deleted_at IS NULL',
'bind' => array(
'id' => $screen->digitalsignage_campaign_id,
'account_id' => $console->getDi()->getCore()->getAccount()->id,
),
));
var_dump($campaign);
}
What is the correct way to change the database service parameteres after first initiation?
Phalcon version: 3.2.2 PHP version: 7.0.22

Is it possible to do migration on dynamic database connection with Laravel 5?

I am trying to dynamically create database for different users. (every user will have their own database server, so don't ask why I am not using a single database for all users) To do that, I have a default database storing all the connection information. I will need to:
Create a new database and run all migration files on new user registration.
Run new migration files on all database recorded in this default database when there is update in schema.
Is there a way I can dynamically set the database connection of the migration file based on the information I have on the default database?
P.S. For "dynamically set the database connection", I am NOT meaning the normal setting as you do in controller or class. I expect something that would at least create migration table in the target database and be able to self-detect what migration file to run.
Yes there is. First you need to add the connection details to the configuration. Once you have a named connection configured, just call the migrate command on the Artisan facade, selecting the name of the connection ("new" in this example) as option:
use Illuminate\Support\Facades\Artisan;
//...
$new_connection = 'new';
config(["database.connections.$new_connection" => [
// fill with dynamic data:
"driver" => "mysql",
"host" => "",
"port" => "",
"database" => "",
"username" => "",
"password" => "",
"charset" => "utf8",
"collation" => "utf8_unicode_ci",
"prefix" => "",
"strict" => true,
"engine" => null
]]);
Artisan::call('migrate', ['--database' => $new_connection]);
First you need to create the database
DB::getConnection()->statement('CREATE DATABASE :schema', array('schema' => $schemaName));
Then change the name of the database on the fly like this
$config = app(\Illuminate\Config\Repository::class);
$config->set('database.connections.mysql.database', UserRepotory::getCurrentDatabase());
You can include Config like this or trough laravel's service container.
And finally you call Artisan::call('migrate')
Hi little help for you,
first of all add '%new_connection%' in database.php file to handle new connection for future use too.
To dynamically create connection, let say you have a route with variable $name for database name.
step 1:
in routes.file I have created and call it on your desired route url in routes.php
function appendNewConnection($name){
$path = base_path('config' . DIRECTORY_SEPARATOR . 'database.php');
$contents = file_get_contents($path);
$updatedContents = str_replace('%new_connection%', $name . '\' => [
\'driver\' => \'mysql\',
\'host\' => \'127.0.0.1\',
\'database\' => \'' . $name . '\',
\'username\' => \'root\',
\'password\' => \'\',
\'charset\' => \'utf8\',
\'collation\' => \'utf8_unicode_ci\',
\'prefix\' => \'\',
\'strict\' => false,
],
\'%new_connection%', $contents);
file_put_contents($path, $updatedContents);
}
Step 2:
//to generate migration add below line in top of routes.php
use Illuminate\Support\Facades\Artisan;
add this line in function created above
Artisan::call('migrate', ['--database' => $name]);
Here I have some clue regarding how can you do this:
1. There will be a global database where you are maintaining all users
login details, Right?
2. Add one extra field for database name.
3. when user logs in success full then store their database details in session
variable.
Now,
4. Create a database file dynamic and give database name from that session variable as:
config(["database.connections.$new_connection" => [
// fill with dynamic data:
"driver" => "mysql",
"host" => "",
"port" => "",
"database" => "",//Here you need to set value of session variable
"username" => "",// credential will be the same for all
"password" => "",// credential will be the same for all
"charset" => "utf8",
"collation" => "utf8_unicode_ci",
"prefix" => "",
"strict" => true,
"engine" => null
]]);
Bingo you now are ready to go :D

How to test MySQL connection in PHP and Laravel? [duplicate]

This question already has answers here:
How to connect to mysql with laravel?
(6 answers)
Closed 8 years ago.
I'm making a PHP application installer (something like Wordpress installation script) and I need to check mysql connection using host name, username, password and database provided by user during installation.
I'm using this code as a Laravel controller method to test connection:
public function TestDatabaseConnection(){
try {
$database_host = Config::get('config.database_host');
$database_name = Config::get('config.database_name');
$database_user = Config::get('config.database_user');
$database_password = Config::get('config.database_password');
$connection = mysqli_connect($database_host,$database_user,$database_password,$database_name);
if (mysqli_connect_errno()){
return false;
} else {
return true;
}
} catch (Exception $e) {
return false;
}
}
This code doesn't seem to properly test the connection. Function return value (true/false) doesn't depend whether user supplies db data at all, or if db data is correct/incorrect..
Fils /app/config/config.php contains the following array:
<?php return array('database_host' => 'localhost', 'database_name' => 'dbasename', 'database_user' => 'dbuser', 'database_password' => 'pass');
and it's being updated via form during installation process.
Is there any way to modify this code or maybe you have some other code suggestions?
Your question is:
How to test MySQL connection in PHP and Laravel?
But then you are setting up a standard PHP MySQLi connection like this:
$connection = mysqli_connect($database_host,$database_user,$database_password,$database_name);
Why would you do that? The whole purpose of using a framework is to work within the framework. And something that encompasses these two basic systems concepts:
Read a configuration file.
Establish a database connection.
Doing those things is something that pretty much every capable—and widely adopted—programming framework should be able to handle within it’s own structure & using it’s own methods.
So that said, looking at the Laravel documentation on “Basic Database Usage” shows the following. This is placed in your DB configuration file located in app/config/database.php.:
'mysql' => array(
'read' => array(
'host' => '192.168.1.1',
),
'write' => array(
'host' => '196.168.1.2'
),
'driver' => 'mysql',
'database' => 'database',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
The example has two distinct DB connections: One for read and the other for write, but that is not how most DB connections for simple projects work. So you can set this instead also using your settings:
'mysql' => array(
'host' => Config::get('config.database_host'),
'driver' => 'mysql',
'database' => Config::get('config.database_name'),
'username' => Config::get('config.database_user'),
'password' => Config::get('config.database_password'),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
Then to test that connection, you would just do this:
if(DB::connection()->getDatabaseName())
{
echo "Yes! successfully connected to the DB: " . DB::connection()->getDatabaseName();
}
But that said you are also saying:
I'm making a PHP application installer…
Why reinvent the wheel when PHP build systems such as Phing exist?
You can simply check whether the connection is made or not using this:
if(DB::connection()) {
// connection is made
}
Because you don't need to make connection manually. If the user provided right credentials in the app/config/database.php then the user will be able to query in the database but if you need to check the connection then given code above is able to check because if the connection is not made then an error will be thrown and on a valid connection the Illuminate\Database\MySqlConnection object will be returned. So, in this case it's also possible to use:
if(DB::connection() instanceof Illuminate\Database\MySqlConnection) {
// connection is made
}
So, according to your example of TestDatabaseConnection method you can do something like this:
public function TestDatabaseConnection(){
// Returns Illuminate\Database\MySqlConnection on successful
// connection; otherwise an exception would be thrown if failed
return DB::connection();
}
If you really want to catch the error of laravel db connection failure,
you can define this:
App::error(function(PDOException $exception, $code)
{
die('do what you want here');
});
I defined it inside:
/app/start/global.php
you can define it where ever you like.

Laravel 4.2 dynamic database connection

I am trying to setup connections to multiple database under the same instance for correlation data analysis
Here is the basic idea of the connection code
$a = array('a','b','c');
$b = array('a','b','c');
foreach($a as $ac){
foreach($b as $bc){
Config::set('database.connections.'.$ac.'_'.$bc, array(
'driver' => 'mysql',
'host' => 'somehost',
'port' => '3306',
'database' => $ac.'_'.$bc,
'username' => 'user',
'password' => 'user',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => ''
));
}
}
There are about 40 different db in that instance, and could change rapidly, so I want to avoid permanently create the connection in the config file and generate the connection on the fly with user input. And from what I gather, the above code should auto append the array to database.connections (see laravel github ), but I am getting this error.
SQLSTATE[HY000] [2002] No such file or directory
if I change database.connections.".$ac.'_'.$bc to database.connections.mysql the code runs okay. So what am I missing here :( , I am calling that piece of code under the constructor of the first controller the input will hit.
Thank you very much for the help in advance
After playing around a bit, found out what's the problem.
After calling the code above in controller,
in model, not only you have to make the initial connection but also you have to include a table in that statement in order to divert the connection to the specific DB, otherwise it will fall back to default connection if you use the way that builder query example from Laravel documentation. So instead of doing
$this->query = DB::connection($ac.'_'.$bc);
$this->query = DB::table('sometable');
do it like
$this->query = DB:connection($ac.'_'.$bc)->table('sometable');
Then connection for $this->query will lock to the new database pointed.

Laravel php script DB class not found

I'm trying to write a script for laravel that queries
my database and fetches tables, but I'm not sure what to include
in the file in order to get the DB class to work.
Thus far my code looks like:
$tables = DB::query("SHOW TABLES");
foreach ($tables as $table) {
print $table . "\n";
}
I've tried using require "../../vendor/autoload.php" but that doesn't help.
So for instance, the DB class works fine if I call it within a controller, but not
if I create a directory, say /application/scripts and create a file test.php .
If I try to call DB in that file, the DB class isn't defined (for good reason).
I'm wondering what I need to require in that file in order for that class to be defined.
I would suggest using the Illuminate/Database package (part of Laravel 4). You won't get the DB interface, because that's a special facade provided by the Laravel Framework, but all the query builder functionality is available through the capsule.
Install illuminate/database using composer and then follow the included readme notes (included below for completeness).
Illuminate Database
Usage Outside Of Laravel 4
$config = array(
'fetch' => PDO::FETCH_CLASS,
'default' => 'mysql',
'connections' => array(
'mysql' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'laravel',
'username' => 'root',
'password' => 'password',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
),
);
$capsule = new Illuminate\Database\Capsule($config);
// If you want to use the Eloquent ORM...
$capsule->bootEloquent();
// Making A Query Builder Call...
$capsule->connection()->table('users')->where('id', 1)->first();
// Making A Schema Builder Call...
$capsule->connection()->schema()->create('users', function($t)
{
$t->increments('id');
$t->string('email');
$t->timestamps();
});
You do not need to include anything. Laravel will include what it needs and setup the system itself. You are using a variable called $db but it is not defined and means/does nothing. What you are looking for is the DB class. Try this:
$tables = DB::query('SHOW TABLES');
foreach ($tables as $table)
{
echo $table.PHP_EOL;
}
Also, check out the Fluent DB class documentation:
http://laravel.com/docs/database/fluent
...Isn't it DB::query()? A call to the database engine is through a class, not a variable, for scoping issues.

Categories