laravel 5.4 dynamic database connection - php

I am building the admission portal in laravel,
I have super admin database which has a schools table with 100 rows,
schools table structure
1.id
2.school_name
3.database details
I want to connect to the school database with its database details by its id.
technically
1.I will pass the school id from url
2.it will select that row from school table
3.after selecting the database details of particular school
4.will connect to the school database for further use.
I went through https://laracasts.com/discuss/channels/tips/set-up-dynamic-database-connection-globally
http://fideloper.com/laravel-multiple-database-connections
but no luck
please help to sort it out.

Actually you dont want multiple connections, but rather change existing connection.
public function setSchoolConnection($id) {
$school = School::find($id);
if ( $school ) {
config(['database.mysql' => [
'database' => $school->database,
'username' => $school->username,
'password' => $school->password
]]);
}
}
Now the default connection has been changed. I think.
If you don't want to change existing connection, just create a new connectio
config(['database.school' => [
'driver' => 'mysql',
'database' => $school->database,
'username' => $school->username,
'password' => $school->password
]]);
and use it like this
$users = DB::connection('school')->select(...);

Have you tried setting the connection in the School model? Laravel will take care of the rest, even if you have relations with different connection.
In your School model, I will override the constructor like so:
public function __construct(array $attributes = [])
{
$this->setConnection(env('DB_SCHOOL_CONNECTION'));
parent::__construct($attributes);
}
The one thing to be careful of is if you have a relation with a different connection, using whereHas or has in your query/builder wont work. as laravel will not be able to set the connection in the query generated.

Related

Laravel change db at runtime

i have an application with one level database for login the users and N databases for one or more users.
i want change the db after a user login.
the db params are stored in the table of the user, so after login i have this:
Config::set("database.connections.mysql", [
"host" => "localhost",
"driver" => "mysql",
'default' => 'mysql',
"database" => $dati->db,
"username" => "root",
"password" => ""
]);
DB::reconnect('mysql');
where $dati->db is the database name for the logged user.
it work only in the current controller but all the other model and controller don't have the new db and returns error for missing tables.
how can i propagate the new settings to all model?
thanks in advance.
You should put it into a middleware.
For example:
<?php
class UserDatabaseMiddleware {
public function handle($request, \Closure $next){
$databaseName = $request->user()->db;
config(['database.connections.mysql.database' => $databaseName]);
return $next($request);
}
}
Then you should define it in App\Http\Kernel.php
<?php
protected $routeMiddleware = [
'dbselect' => UserDatabaseMiddleware::class
]
And finally you can add it to your route file. For example:
<?php
Route::group([
'middleware' => 'dbselect',
], function(){
Route::get('/', [MyController::class, 'myMethod'])->name('index');
})
Now the config should be changed with every http request if user is logged in.
Important:
As it was mentioned in the comments - having multiple databases per user is a bad approach. You should consider it.
There is another way to do this - you can have user_id for each record in table and then create global scope to select only records of logged in user.

Disable or bypassing name conventions in cakePHP3

I have following Data:
Database name = ThisDatabase
Table name = InfoData
cakePHP3 convert the names in
ThisDatabase = this_database
InfoData = info_data
My problem is that I have no chance to rename the DB or Table names so I have to disable or bypass the name converting in cakePHP3.
But I have no clue how I can do this.
How can i disable the converting? So I can use the actual names (ThisDatabase and InfoData).
You should follow naming convention for your files and cakephp to work properly, and specify the table name in initialize function inside your App\Model\Table\ArticlesTable.php
Here you can find related documentation
That's easy, CakePHP offers you a way to change the name of the table as you wish.
For the database, in the app config, set the database name :
...
'Datasources' => [
'default' => [
...
'username' => 'username',
'password' => 'password',
'database' => 'ThisDatabase', // Here you can set the database name
'encoding' => 'utf8',
..
]
],
...
Here is some doc
For the table name : In your table definition, change the table name
class Infodata extends Table
{
public function initialize(array $config)
{
$this->table('InfoData');
}
}
Here is is the doc

PHP Yii: Database connect in runtime

I would like to connect to a second database with Yii at runtime. The database name would come from a database table after the user to login.
I saw in a tutorial I should do this:
$db2 = Yii::createComponent(array(
'class' => 'EMongoClient',
'server' => 'mongodb://127.0.0.1:27017',
'db' => $emp['database']
));
Yii::app()->setComponent('db2',$db2);
But in my controler when I access Yii::app()->db2 get the error:
Property "CWebApplication.db2" is not defined
What am I doing wrong?
The following works for me:
Yii::app()->mongodb->setActive(false);
Yii::app()->mongodb->setServer('mongodb://localhost:27017');
Yii::app()->mongodb->setDb('db1');
Yii::app()->mongodb->setActive(true);
UPDATED: Try, instead instance, pass configurations:
Yii::app()->setComponent( 'db2', array(
'class' => 'EMongoClient',
'server' => 'mongodb://127.0.0.1:27017',
'db' => $emp['database']
)
);
Or, you may create special index on params in configurations, such as:
...
'params' => array(
'db2' => null,
),
And the use Yii::app()->params['db2'] = $db2
From this comment:
My problem is not with the creation of the component. Soon after
creating if I access Yii::app()->db2 its works, but when I try to
access via another model or controller I get the error
I think you are setting this component only once somewhere, and then making subsequent requests to different controllers.
You need to put the code, somewhere it is being called EVERYTIME, on every Request. thats how PHP works, there is no "global application state"
by default Yii comes with protected/components/controller.php has base controller for the rest of the app.
my suggestion would be to put your code on the init() method of that controller, so that it always gets called.
You mentioned the database name comes from a table once the user logs in, so you need to save that value in the session, in other to be able to access it in the other requests:
<?php
// After login in
Yii::app()->user->setState('db_name', $db_name);
// in protected/components/controller.php
public function init()
{
if (!Yii::app()->user->isGuest) {
$db2 = Yii::createComponent(array(
'class' => 'EMongoClient',
'server' => 'mongodb://127.0.0.1:27017',
'db' => Yii::app()->user->getState('db_name')
));
Yii::app()->setComponent('db2',$db2);
}
}
Hope it helps, I am assuming many things here :)

CakePHP log in system

I am editing a website which someone has made in CakePHP, but I don't have any previous experience in Cake. I'm reading the manual but finding it quite hard to understand so thought I would post a question on here to see if I can get any quick answers.
I think that this code is being used to display a login box, and you can only log in with username test and password 123123
var $components = array("Auth", "Acl");
function beforeFilter(){
$this->Security->loginOptions = array(
'type' => 'basic',
'realm' => 'Authenticate Emergency Response Center'
);
$this->Security->loginCredentials = array(
'test' => '123123'
);
$this->Security->requireLogin();
$this->_bindToSite();
parent::beforeFilter();
}
I want the log in box to appear still, but I want to fill the loginCredentials array automatically with information from the database. I have a table called 'operators' which contains the fields 'user_id' and 'password'.
Could someone tell me how I would alter the code above to allow any of the usernames/passwords stored in the operators table to log in?
Thanks for any help
Build an array from the database and set $this->Security->loginCredentials equal to your array.
You can leave most of the hard work up to CakePHP's Auth component, but if you want to use a model other than the default 'User', you'll just need to set this in beforeFilter(). The best place to do this is probably app_controller.php in your app\ directory.
function beforeFilter(){
$this->Auth->userModel = 'Operator';
$this->Auth->fields = array(
'username' => 'user_id',
'password' => 'password'
);
);

What are the step you have to go through when updating an application to be multilingual?

I need to update an application which is built on Zend Framework.
Most of the text is hard-coded in views scripts, forms, etc.
The application will be available in say, 3 languages AND is language specific (the content is not the same for all) and will have one domain per language (ie: mygreatsite.com, monsupersite.com, ilmiosupersite.com, etc.)
First question:
What is the best way to "handle" this kind of application?
I can imagine several solution like:
One copy per language, using different db, etc... (probably not the best way for maintenance)
Only one application, handling different content, db, etc, depending on the locale (based on the route)
Second question:
What should I need to know about the existing code to start the "migration"?
What about any best practice when building a i18n website?
What are the best adapter? (I already used gettext() and I think it's the best)
I am by no means an expert but this is what I do.
I use array as my translation adapter because it’s easier for my clients to update as they are just regular Joes. And I use translation keys instead of sentences. For example
Some people would use
$this->translate(‘Some sentence to translate’);
I use
$this->translate(‘default-index-dashboard-title’);
This makes it far easier for me to know where the text I’m looking for is to change. I don’t know if there are any advantages other than that though.
You will need to setup your translation adapter and translation cache (if you want) in your bootstrap. I do mine like this:
protected function _initLocale()
{
$locale = new Zend_Locale(Zend_Locale::BROWSER);
$config = Zend_Registry::get('config');
Zend_Registry::set('Zend_Locale', $locale->toString());
return $locale;
}
protected function _initTranslation()
{
try{
$translate = new Zend_Translate(array('adapter' => 'array', 'content' => ROOT . '/callmanagement/languages/' . strtolower(Zend_Registry::get('Zend_Locale')) . '.php'));
}catch(Exception $e){
$translate = new Zend_Translate(array('adapter' => 'array', 'content' => ROOT . '/callmanagement/languages/en_gb.php'));
}
Zend_Registry::set('Zend_Translate', $translate);
return $translate;
}
I would use a single code base unless the sites are completely different and store the shared data in one database and have other databases for the site specific stuff.
You can setup multiple db adapters either in the bootstrap or in the congfig.
$dbLocal = new Zend_Db_Adapter_Pdo_Mysql(array(
'host' => 'localhost',
'username' => $result['user'],
'password' => $result['password'],
'dbname' => $result['database']
));
Zend_Db_Table_Abstract::setDefaultAdapter($dbLocal);
$dbShared = new Zend_Db_Adapter_Pdo_Mysql(array(
'host' => 'localhost',
'username' => ‘root’,
'password' => 'pass',
'dbname' => 'dbname'
));
Zend_Registry::set('db_local', $dbLocal);
Zend_Registry::set('db_shared', $dbShared);
return $dbLocal;
You can get Zend Form to translate for you just put your translation key into the label field.
$this->addElement(‘text’, ‘test’, array(‘label’ => ‘translation-key’, ‘required’ => true)); etc.
Then if you are using Zend_Db_Table_Abstract classes you can change the default schema and database connection like this:
class Default_Model_Table_Topics extends Zend_Db_Table_Abstract
{
protected $_name = 'topics';
protected $_id = 'topic_id';
protected $_rowClass = 'Default_Model_Topic';
protected $_schema = 'dbname';
protected $_adapter = 'db_shared';
}
If you need any more examples I’ll try and help.

Categories