I want to create databases and users with CI programmatically. So far i have these 2 simple MySQL statements.
CREATE DATABASE `testdb` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
and
CREATE USER 'test_user'#'%' IDENTIFIED BY '***';
GRANT ALL PRIVILEGES ON * . * TO 'test_user'#'%' IDENTIFIED BY '***' WITH GRANT
OPTION MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0
MAX_USER_CONNECTIONS 0 ;
GRANT ALL PRIVILEGES ON `testdb` . * TO 'test_user'#'%';
Can those be converted to Active Record, or does CI provides its own way of creating users/tables? i search the docs and couldn't find anything...
EDIT: I do this as an intranet application so no worries about permissions
CodeIgniter provides a class called as Database Forge , it contains some functions which can be used to perform basic maintenance on your DB.
$this->load->dbforge()
if ($this->dbforge->create_database('my_db'))
{
echo 'Database created!';
}
and regarding adding users, its possible, but I don't know if its a good practice or not.
and also make sure that the mysql user who runs the queries has the permissions to create db.
$data = array(
'Host' => 'localhost' ,
'User' => 'krish' ,
'Password' => 'somepass',
'Select_priv' => 'Y',
'Insert_priv' => 'Y'
);
$this->db->insert('mysql.user', $data);
IF I understand, you can try
$config['database'] = 'mysql';
// other config details e.g username. port, pass
$this->load->database($config);
$query = "INSERT INTO user (host, user, password, select_priv,
insert_priv, update_priv)
VALUES ('localhost', 'user', PASSWORD('mypass'), 'Y', 'Y', 'Y')";
$this->db->query($query);
My syntax might be a little off.
Essentially - use the mysql database, insert directly in to the user table.
Some hosts may deny access to this directy, however.
Related
This question already has answers here:
Laravel: connect to databases dynamically
(8 answers)
Closed 3 years ago.
I have the master database with login table and corresponding database settings for each user. On login I should dynamically change the db settings fetching from the table.
I can change the db connection but this is not persisting.
Config::set("database.connections.mysql", [
'driver' => 'mysql',
"host" => $usr_host,
"database" => $usr_database,
"username" => $usr_username,
"password" => $usr_password,
...
]);
edit:
New database is created for each user when he/she registers with the app and thus i dont have the database connection for each user defined in the config/database.php
This way you can set new parameter when it comes to database:
\Config::set('database.connections.mysql.database', $schemaName);
Remember about PURGE to persist this settings
DB::purge('mysql');
Cheers!
Well you can use the default database for user login and have a new field for the database name. Then whenever you need to query a different database, you can just change your db connection.
Something like this
$someModel = new SomeModel;
$databaseName = "mysql2"; // Dynamically get this value from db
$someModel->setConnection($databaseName);
$something = $someModel->find(1);
You can read more about it here.
http://fideloper.com/laravel-multiple-database-connections
you need to get the config first.. then alter the specific field then set it back..
$config = Config::get('database.connections.company');
$config['database'] = "company_tenant_$id";
$config['password'] = "test2123";
config()->set('database.connections.company', $config);
I think a good place to change the database connection place is in bootstrap/app.php file, use the code below:
$app->afterBootstrapping(\Illuminate\Foundation\Bootstrap\LoadConfiguration::class, function ($ap) {
// your database connection change may happens here
});
It is before ServiceProvider register and boot, so even if you use DB or Eloquent staff in ServiceProvider, it works very well.
In laravel what you can do is create the different connections in the connections array of the file conf/database, then these connections you can use them when you are going to carry out operations in your application.
If you use query builder or raw expresions you must use the connection ('name') method to perform queries, for example:
$users = DB::connection('mysql')
->table('users')
->select(...)
->get();
If you use eloquent you can specify the name of the connection in the model file in the connection attribute, for example:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* The connection name for the model.
*
* #var string
*/
protected $connection = 'mysql';
}
A solution to your problem could be that you have created the different types of connections according to the users in the file conf/database, and save the name of the connection that the user uses as a column in the user table, and when you go to make the queries you get the name of the connection of the user, for example:
$user = User::find(Auth::id());
$connection = $user->connection;
$users = DB::connection($connection)
->table('users')
->select(...)
->get ();
more info:
https://laravel.com/docs/5.5/eloquent#eloquent-model-conventions
https://laravel.com/docs/5.5/database#read-and-write-connections
After an extensive search I found it this way:
Go to this file vendor\laravel\framework\src\Illuminate\Auth\Middleware\Authenticate.php
Go to the method: protected function authenticate($request, array $guards)
and right after the method has started, paste the following code:
if(auth()->check() && !empty( auth()->user()->db_name )){
$dynamic_db_name = auth()->user()->db_name;
$config = \Config::get('database.connections.mysql');
$config['database'] = $dynamic_db_name;
$config['password'] = "Your DB Password";
config()->set('database.connections.mysql', $config);
\DB::purge('mysql');
}
first we are checking if the user is logged in with
auth()->check()
Then as you may have added db_name name or the like column table to your users table according to each user. So in the next condition, I am making sure that the db_name is available:
&& !empty( auth()->user()->db_name )
Then after execution enters the if condition I get the db_name from the user record and set the configuration according to the user database, save the config and use purge method of DB class to persist this setting.
I was really stuck with it. I did not wanted to change my db connection in every class. So this is how I got it. Now I can use both Eloquent and DB without any tension anywhere. In my application I have one centeral database for login of all users and then for each organization there is a different database. So after the user has logged in, I do not need the centeral database (login database), I juse need the user/organization specific database. So this is how I got it to work.
I have an instanced web application that uses different databases for every instance but uses the same files.
What I want my application to do on boot:
Get database credentials from master instance table. This instance table is in the default 'mysql' connection that I have defined in app/config/database.php.
Connect to the instance database from that point on (I don't need the master instance database anymore)
I have tried to do this in my App:before() event, but that won't work as I don't have a sessions table in my master database. If I do it before the return array() in database.php it obviously can't connect because it doesn't have the correct master database credentials yet.
Where am I supposed to do this? Should I just disable sessions and do it in my App::before() and then enable sessions after?
Don't think its possible, But here is a possibility.
Read / Write Connections
Sometimes you may wish to use one database connection for SELECT statements, and another for INSERT, UPDATE, and DELETE statements. Laravel makes this a breeze, and the proper connections will always be used whether you are using raw queries, the query builder, or the Eloquent ORM.
To see how read / write connections should be configured, let's look at this example:
'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' => '',
),
Note that two keys have been added to the configuration array: read and write. Both of these keys have array values containing a single key: host. The rest of the database options for the read and write connections will be merged from the main mysql array. So, we only need to place items in the read and write arrays if we wish to override the values in the main array. So, in this case, 192.168.1.1 will be used as the "read" connection, while 192.168.1.2 will be used as the "write" connection. The database credentials, prefix, character set, and all other options in the main mysql array will be shared across both connections.
After some hours of experimenting and trying I have found out that the best option really is to create a PDO instance manually in the /app/config/database.php file and get the database credentials that way:
// Get instance row
if (!App::runningInConsole() && !array_key_exists('instance_found', $_ENV)) {
$conn = new PDO('mysql:dbname=instances;host=127.0.0.1', 'root', 'password');
$stmt = $conn->prepare('SELECT * FROM instances WHERE http_host=?');
$stmt->bindParam(1, $_SERVER['HTTP_HOST']);
$stmt->execute();
$instance = $stmt->fetch(PDO::FETCH_OBJ);
$conn = null;
if (!$instance) {
return Response::make('Whoops!', 404);
} else {
$_ENV['instance_found'] = true;
$database = $instance->mysql_database;
$username = $instance->mysql_username;
$password = $instance->mysql_password;
}
}
I am using PHP PDO to access a PostgreSQL database with various schemas, so first i create a connection and then i set the correct schema, like below:
$Conn = new PDO('pgsql:host=localhost;port=5432;dbname=db', 'user', 'pass');
$result = $Conn->exec('SET search_path TO accountschema');
if ( ! $result) {
die('Failed to set schema: ' . $Conn->errorMsg());
}
Is this a good practice? Is there a better way to do this?
In order to specify the default schema you should set the search_path instead.
$Conn->exec('SET search_path TO accountschema');
You can also set the default search_path per database user and in that case the above statement becomes redundant.
ALTER USER user SET search_path TO accountschema;
I connect the normal way:
$dbh = ibase_connect($host, $username, $password) OR die("could not connect");
Then I run a query:
ibase_query($dbh, 'ALTER TABLE USERS ADD OLDUSERPASS VARCHAR(32) COLLATE NONE') or die(ibase_errmsg());
Directly after this I run:
ibase_query($dbh, 'UPDATE USERS SET OLDUSERPASS = USERPASS') or die(ibase_errmsg());
It complains:
Column unknown OLDUSERPASS At line 1
But when I look in the DB, the column has been created. So, for some reason that split second after run ALTER, the query is not actually committed to the server.
Any ideas why?
Try
ibase_commit($dbh) after alter statement
In Firebird, DDL is under transaction control and you are not allowed to use newly created objects (tables, columns, etc) within the same transaction. So you will first need to commit before executing a query that uses that object.
i am developing a app that scans/crawls/monitors certain websites
the app is available for free at www.linkbook.co
now, i will explain what i want to do:
I have a main DB, that stores the websites, the urls found on the websites and url patterns from each website; The website knows the Db that he has been assigned to, the url knows the website id;
Because i have a 2 GB / DB limit, i need secondary DB's.
I read all from http://www.yiiframework.com/wiki/123/multiple-database-support-in-yii/ and what Google could find, and there is not a single complete example using dinamicaly the connection;
So, each time my app scans a website, each url found will be inserted in the main DB, and also in the DB that has been assigned to the website that the url belongs to.
In time, the data from the main DB gets deleted, but it is still available in the secondary DB.
So, only the HOT info gets stored in the main but they remain saved in the secondary db's
The Yii guys give this example, but i need a parameter, from 1 to N, N=1->infinite,in order to switch to the right DB.
class MyActiveRecord extends CActiveRecord {
...
private static $dbadvert = null;
protected static function getAdvertDbConnection()
{
if (self::$dbadvert !== null)
return self::$dbadvert;
else
{
self::$dbadvert = Yii::app()->dbadvert;
if (self::$dbadvert instanceof CDbConnection)
{
self::$dbadvert->setActive(true);
return self::$dbadvert;
}
else
throw new CDbException(Yii::t('yii','Active Record requires a "db" CDbConnection application component.'));
}
}
...
$dbadvert needs to be dinamic, this is my problem.
also, the tables from the secondary DB's are not exactly the same, as i dont need all the fields from all the tables, and some tables get dropped also, so i need a model;
the model i can write it, it's not hard, i will just delete some fields;
this is what i have now, just the insert, in a specific DB, db1 a.k.a. linkbookco1
$command = Yii::app()->db1->createCommand("INSERT INTO `url` (
`id` ,
`website_id` ,
`link` ,
`name` ,
`created` ,
`instance_scanner_id` ,
`status`
)
VALUES (
NULL , '".($model_url->website_id)."', '".($model_url->link)."', '".($model_url->name)."', '".($model_url->created)."', '".($model_url->instance_scanner_id)."', '".($model_url->status)."'
);
");
$command->query();
db1 and it's params are mentioned in the config file, as the yii developers say;
from your example I can guess you have a secondary database connection configured in your app like
'dbadvert' => array(
'class' => 'CDbConnection',
...
)
the point where you need to get the database connection you have this:
self::$dbadvert = Yii::app()->dbadvert;
So, to have multiple database connections you'd need to add them to your database configuration
'dbadvert1' => array(
'class' => 'CDbConnection',
...
)
'dbadvert2' => array(
'class' => 'CDbConnection',
...
)
And in your code you can do something like
self::$dbadvert = Yii::app()->getComponent("dbadvert".Yii::app()->request->getQuery('dbid', ''));