Yii2-user: How to create admin user in batch mode? - yii2

When deploying my application there is of course always an admin user.
How can I create such an admin user as a first user without any interaction ...
... by means of SQL?
... using a Yii2-migration?

Found it. There is an easy way to do this with Yii2 builtin migrations.
In Yii2-user there are some hooks we can use to create users.
This code has to be inserted in a migration. after creating a new migration ./yii migrate/create, preferably after creating initial tables in the database:
use yii\db\Transaction;
use app\models\user\User;
public function safeUp()
{
$transaction = $this->getDb()->beginTransaction();
$user = \Yii::createObject([
'class' => User::className(),
'scenario' => 'create',
'email' => 'admin',
'username' => 'admin#example.com',
'password' => 'mysecret',
]);
if (!$user->insert(false)) {
$transaction->rollBack();
return false;
}
$user->confirm();
$transaction->commit();
}
The skeleton code can be found in ./migrations/....
Don't forget to add database config parameters in ./config/db.php
and the user module in ./config/console.php

Related

How to add a role to user when having basic User model in Yii2

Building a lightweight app using basic installation of Yii2.
I need to assign a role for a user but don't want to have users and user roles stored in database.
How can I set a role for users defined in User->users class?
Default User model and default user definition look like this:
class User extends \yii\base\BaseObject implements \yii\web\IdentityInterface
{
public $id;
public $username;
public $password;
public $authKey;
public $accessToken;
private static $users = [
'100' => [
'id' => '100',
'username' => 'admin',
'password' => 'admin',
'authKey' => 'test100key',
'accessToken' => '100-token',
],
You can use RBAC PhpManager for that that will store all roles info in files instead.
First configure your AuthManager component in config/web.php:
// ...
'components' => [
// ...
'authManager' => [
'class' => 'yii\rbac\PhpManager',
],
// ...
],
By default it uses 3 files to keep the data:
#app/rbac/items.php
#app/rbac/assignments.php
#app/rbac/rules.php
So make sure there is folder rbac in your application's root and that it's write-able by the www process. If you want to place the files somewhere else (or rename them) you can provide the new path in the configuration like:
'authManager' => [
'class' => 'yii\rbac\PhpManager',
'itemFile' => // new path here for items,
'assignmentFile' => // new path here for assignments,
'ruleFile' => // new path here for rules,
],
The rest now is just like in the Authorization Guide.
Prepare roles and permissions (example in console command - by running this command once you set all roles; remember that if you want to run it in console you need also configure console.php with the same component).
Assign role to a user (example - here it's done during the signup but you can do it also in the above command).
Now you can control access with direct check or behavior configuration.

Yii2 console migration down with a different connection fails

Am trying to perform console migrations to a different connecton but down fails
in my connection i have
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=pos_db',
....other configs
],
'connection_identifier' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=newdbo',
...other configs
],
In my console i have
public function init()
{
$this->db = 'connection_identifier';
parent::init();
}
public function safeUp()
{
$this->createTable('database_connection_domains', [
'id' => $this->primaryKey(),
'domain'=>$this->text()->notNull(),
'connection_id'=>$this->integer()->notNull(),
'created_at' => $this->integer()->notNull(),
'status'=>$this->integer()->defaultValue(0),
'FOREIGN KEY (connection_id) REFERENCES database_connections (id) ON DELETE RESTRICT ON UPDATE CASCADE',
]);
}
/**
* {#inheritdoc}
*/
public function safeDown()
{
$this->dropTable('database_connection_domains');
}
When i run the up migration the database in correctly created on the newdbo database. The problem comes in during down command where the table is not dropped. How do i make this drop the table.
When i run /yii migrate/fresh am getting an error Base table or view already exists: 1050 Table 'database_connections' already exists which means that the table is not dropped
What am i missing?
./yii migrate/fresh does not use migrations to cleanup database, is uses custom implementation which just deletes all tables in correct order. So your settings for DB component are never used. You need to configure database on command call:
./yii migrate/fresh --db=connection_identifier

Laravel: Store error messages in database

Any one know how to send error messages to database in laravel which generate from app/exceptions/handler.php ?
I need to send what error massages generated in report() method to database.
If you are interested doing this manually, you can do something as following.
Step 1 -
Create a model to store errors that has a DB structure as following.
class Error extends Model
{
protected $fillable = ['user_id' , 'code' , 'file' , 'line' , 'message' , 'trace' ];
}
Step 2
Locate the App/Exceptions/Handler.php file, include Auth, and the Error model you created. and replace the report function with the following code.
public function report(Exception $exception) {
// Checks if a user has logged in to the system, so the error will be recorded with the user id
$userId = 0;
if (Auth::user()) {
$userId = Auth::user()->id;
}
$data = array(
'user_id' => $userId,
'code' => $exception->getCode(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'message' => $exception->getMessage(),
'trace' => $exception->getTraceAsString(),
);
Error::create($data);
parent::report($exception);
}
(I am demonstrating this using laravel 5.6)
Because Laravel uses Monolog for handling logging it seems that writing Monolog Handler would be the cleanest way.
I was able to find something that exists already, please have a look at monolog-mysql package. I did not use it, so I don't know whether it works and if it works well, but it's definitely good starting point.

CakePHP 3 Auth on model other than User

I'm working on a project rebuild using CakePHP, and following the new Authentication documentation here:
http://book.cakephp.org/3.0/en/controllers/components/authentication.html
From what I'm reading, Cake3 uses the userModel='User' by default, but it has the option to set it to whatever you want. In my case, I have all the auth data in the 'Account' model (i.e. userModel => 'Account').
So, in my Account Entity, I added the following code:
protected function _setPassword($password)
{
return (new DefaultPasswordHasher)->hash($password);
}
Additionally, in my accounts table, my 'passwd' field is set to varchar(255) [I've read that's required for some reason].
When I use my default baked 'add' and 'edit' methods, the password is stored in plain text, and not hashed. The ONLY way I've found to get around this is to create a custom method in the AccountsTable class then call it using this kludge:
$this->request->data['passwd'] = $this->Accounts->hashPassword($this->request->data['passwd']);
My Auth component looks like this...
$this->loadComponent('Auth', [
'loginAction' => [
'controller' => 'Accounts',
'action' => 'login'
],
'authError' => 'Unauthorized Access',
'authenticate' => [
'Form' => [
'fields' => [
'username' => 'username',
'password' => 'passwd'
],
'userModel'=>'Accounts'
]
]
]);
Is there a way to do this without dinking around with the raw request data?
Your mutator is named wrongly, the convention for mutators is _set followed by the camel cased field/property name. So since your field name is passwd, not password, it has to be named _setPasswd instead.
protected function _setPasswd($password)
{
return (new DefaultPasswordHasher)->hash($password);
}
See also Cookbook > Entities > Accessors & Mutators

Multiple database connections and Yii 2.0

I have two databases, and every database has the same table with the same fields, but how do I get all records from all of two databases at the same time in Yii 2.0?
First you need to configure your databases like below:
return [
'components' => [
'db1' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=db1name', //maybe other dbms such as psql,...
'username' => 'db1username',
'password' => 'db1password',
],
'db2' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=db2name', // Maybe other DBMS such as psql (PostgreSQL),...
'username' => 'db2username',
'password' => 'db2password',
],
],
];
Then you can simply:
// To get from db1
Yii::$app->db1->createCommand((new \yii\db\Query)->select('*')->from('tbl_name'))->queryAll()
// To get from db2
Yii::$app->db2->createCommand((new \yii\db\Query)->select('*')->from('tbl_name'))->queryAll()
If you are using an active record model, in your model you can define:
public static function getDb() {
return Yii::$app->db1;
}
//Or db2
public static function getDb() {
return Yii::$app->db2;
}
Then:
If you have set db1 in the getDb() method, the result will be fetched from db1 and so on.
ModelName::find()->select('*')->all();
Just to add:
I followed the answer provided but still got an error:
"Unknown component ID: db"
After some testing, here is what I discovered: The function getDB is only called AFTER a connection is made to db. Therefore, you cannot delete or rename 'db' in the config file. Instead, you need to let the call to 'db' proceed as normal and then override it afterwards.
The solution (for me) was as follows:
In config/web.php add your second database configuration below db as follows:
'db' => require(__DIR__ . '/db.php'),
'db2' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=name',
'username' => 'user',
'password' => 'password',
'charset' => 'utf8',
'on afterOpen' => function ($event) {
$event->sender->createCommand("SET time_zone = '+00:00'")->execute();
},
],
DO NOT rename db. Failure to find db will cause an error. You can name db2 whatever you like.
Now in the model, add the following code:
class ModelNameHere extends \yii\db\ActiveRecord {
// add the function below:
public static function getDb() {
return Yii::$app->get('db2'); // second database
}
This will now override the default db configuration.
I hope that helps somebody else.
Note: you can include the configuration for db2 in another file but you cannot include it in the db.php file (obviously). Instead, create a file called db2.php and call it as you do db:
'db' => require(__DIR__ . '/db.php'),
'db2' => require(__DIR__ . '/db2.php'),
Thanks
Our situation is a little more complex, we have a "parent" database which has a table that contains the name of one or more "child" databases.
The reason for this is that the Yii project is instantiated for each of our clients, and the number of child databases depends on the client, also the database names are arbitrary (although following a pattern).
So we override
\yii\db\ActiveRecord
as follows:
class LodgeActiveRecord extends \yii\db\ActiveRecord
{
public static function getDb()
{
$lodgedb = Yii::$app->params['lodgedb'];
if(array_key_exists( $lodgedb, Yii::$app->params['dbs'])) {
return Yii::$app->params['dbs'][ $lodgedb ];
}
$connection = new \yii\db\Connection([
'dsn' => 'mysql:host=localhost;dbname=' . $lodgedb,
'username' => Yii::$app->params['dbuser'],
'password' => Yii::$app->params['dbpasswd'],
'charset' => 'utf8',
]);
$connection->open(); // not sure if this is necessary at this point
Yii::$app->params['dbs'][ $lodgedb ] = $connection;
return $connection;
}
}
Before calling any database function, first set Yii::$app->params['lodgedb'] to the name of the database required:
Yii::$app->params['lodgedb'] = $lodge->dbname; // used by LodgeActiveRecord
Your model classes don't change except they extend from LodgeActiveRecord:
class BookingRooms extends \app\models\LodgeActiveRecord
If you're using schmunk42/yii2-giiant to generate model classes, there is a 'modelDb' property which you can set to use a database component other than 'db'.