i need implement mongodb and have a question;
at queue.php we have
'failed' => [
'database' => env('DB_CONNECTION', 'mysql'),
'table' => 'failed_jobs',
],
but I need to put MongoDB too at the same time, would have problems if duplicate 'failed' position?
Exist another way to do this?
You should only use one database to store your failed jobs.
If you use laravel-mongodb you can use MongoDB to store your failed jobs. Here is the documentation for that.
This would be a sample configuration for using MongoDB to save failed jobs:
'failed' => [
'driver' => 'mongodb',
// You can also specify your jobs specific database created on config/database.php
'database' => 'mongodb-job',
'table' => 'failed_jobs',
],
As I'm new to the cache mechanism, I gone through the yii2 documentation. As per the documentation, I added the below config in db.php in yii2 basic application.
<?php
return [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=db_new',
'username' => 'root',
'password' => 'root123',
'charset' => 'utf8',
'enableQueryCache' => true,
'queryCacheDuration' => 86400,
'enableSchemaCache' => true,
// Name of the cache component used to store schema information
'schemaCache' => 'cache',
// Duration of schema cache.
'schemaCacheDuration' => 86400, // 24H it is in seconds
];
also I added the cache component in web.php
'components' => [
'cache' => [
'class' => 'yii\caching\ApcCache'
]
]
And added the below code while retrieving a record from clients table.
$db = Clients::getDb();
$client = $db->cache(function ($db)use($id) {
return Clients::find()->where(['id' => $id])->all();
});
I assume my client table one record ex)$id = 3 is cached. So next time if I try to retrieve same record from clients table it will pull from cache not from scratch.
My questions are
What I did above is this correct or anything I need to configure
more?
Where it is storing in the local system.
Thanks in advance.
what you did is correct for query caching, found in data caching here.
there are more caching mechanisms available, like fragment, page or http caching
as far as i know, the place where the cached data is stored depends on the caching component. apc stores in memory
yii's FileCache will store files under /runtime
good to know you can flush caches with yii's console command yii cache/flush-all
I am using a yii2 with file cache and redis cache also. In my main config file redis cache settings are defined.
'redis' => [
'class' => 'yii\redis\Connection',
'hostname' => 'MY_IP',
'port' => MY_PORT,
'database' => 0,
],
I also added a component under file cache setting.
'cache' => [
'class' => 'yii\caching\FileCache',
],
so for a caching i'm using a $cache = Yii::$app->cache; and for setting a cache Yii::$app->cache->set($id, $value, $time); and get using Yii::$app->cache->get($id); so is this is set the value from file cache or it is override the filecache and using the redis over it.
If this is using the filecache so how we override the filecache with redis .Can we use the redis cache with this Yii::$app->cache->get($id); or we can use the redis with the use yii\redis\Cache; and set using the
$redis->hmset('test_collection', 'key1', 'val1', 'key2', 'val2');
Yes you can by simply setting the $cache property to this:
'cache' => [
'class' => 'yii\redis\Cache',
'redis' => 'redis' // id of the connection component as it is already defined
];
In my code I'm using it this way:
$cache = Yii::$app->cache;
$cache->add($access_token, ['id' => Yii::$app->user->id], $expire);
$user = $cache->get($access_token);
I've also noticed that some components are already using it like the urlManager which started storing the generated rules in the redis DB. See yii\redis\Cache docs for full list of available properties and methods when using within $cache.
I am having an issue specifying a different datasource to use in a custom session handler inside config/app.php. Here are the relevant bits:
config/app.php
<?php
return [
... ,
'Datasources' => [
'default' => [...],
'test' => [...],
'session' => [...]
],
'Session' => [
'defaults' => 'database',
'ini' => ['session.cookie_domain' => '.example.com'],
'handler' => [
'engine' => 'CustomSessionHandler', // file and class name of custom handler
'model' => 'sessions' // table name
]
]
];
CustomSessionHandler.php is a copy of the default DatabaseSession.php with a few customisations in the query building to work with our existing sessions table schema.
Right now, it's trying to use the 'default' datasource, and as you might guess, I'm trying to get it to use the 'session' datasource. However I can't find any information on how to do that.
Any assistance is greatly appreciated!
The session handler only knows about the model, respectively the table class, and it shouldn't really know more than that.
So what you could do is configure that table class to use a non-default connection. If you don't have a concrete SessionsTable class yet, create one, and override Table::defaultConnectionName(), like
public static function defaultConnectionName()
{
return 'session';
}
See also Cookbook > Database Access & ORM > Table Objects > Configuring Connections
I am trying to build and application using Laravel 5. It is supposed to be a multi tenant database architecture using multiple databases. My employer requires this for security purposes.
I have tried manually managing the main DB migrations and the Tenant migrations but failed. So I decided to take the help of a Laravel specific package which is supposedly what I require.
Tenanti provides a way to have my purpose solved but the problem is that me being a novice developer, am not able to fully understand how to use it in my application.
I have installed it correctly I believe doing:
composer require "orchestra/tenanti=~3.0"
Adding these providers and aliases in the config app file:
'providers' => [
// ...
Orchestra\Tenanti\TenantiServiceProvider::class,
Orchestra\Tenanti\CommandServiceProvider::class,
],
'aliases' => [
'Tenanti' => Orchestra\Support\Facades\Tenanti::class,
],
Finally publishing the config and tweaking it according to the documentation for multiple databases:
php artisan vendor:publish
return [
'drivers' => [
'user' => [
'model' => App\User::class,
'migration' => 'tenant_migrations',
'path' => database_path('tenanti/user'),
],
],
];
At this point I am still blurry what to do next?
My doubts are as follows:
Where will the migration files be generated and stored? I mean there are two kinds of databases in my application obviously. One set of files is for the main DB which will store all the tenant information and the other files will be for the tenant DB. So how and where will these be stored?
I see the word 'driver' a lot in the documentation but I am not sure what driver is exactly.
How will I handle the authentication for the application? I mean whenever a tenant logs in, I will have to make sure the connection to the database changes dynamically. How will I accomplish this?
I tried to go through the repository of the package itself and make sense of the code inside but in vain. I am not very good when it comes to design patters like facades, command bus, service provider and so on, which is why I am not able to understand the flow of the package or make sense of it.
I tried to run some of the artisan commands which come with the package like:
php artisan tenanti:install {driver}
php artisan tenanti:make {driver} {name}
But I am getting an error like so:
[InvalidArgumentException] Database connection
[tenants] is not available.
Where can I find the resources to understand how to proceed with this?
+1 to #morphatic answer, it quiet accurate on most of the stuff.
Migration
One set of files is for the main DB which will store all the tenant information and the other files will be for the tenant DB. So how and where will these be stored?
For your main database you should be able to use the default database/migration and utilize php artisan make:migration and php artisan migrate.
Tenanti however will use the migration path set under the "driver" configuration. e.g:
'path' => database_path('tenanti/user'),
In this case the migration will be created/migrated from database/tenanti/user (you can choose other folder and it will use that folder). Once you set this up you can create new migration file for the user tenant via php artisan tenanti:make user create_blogs_table (as an example) and run migration via php artisan tenanti:migrate user (see the similarity between Laravel migration command and Tenanti?).
Driver
Driver is just the grouping of a tenant, you maybe grouping it by users, companies, or team etc. And there is possibility that you may require more than one type of group per project, otherwise most of the time you only be using single "group" or "driver".
Authentication or Accessing DB
How will I handle the authentication for the application? I mean whenever a tenant logs in, I will have to make sure the connection to the database changes dynamically. How will I accomplish this?
First of all, you need to consider how you're planning to distinguish each tenant. Most of the time I would see people tend to opt for subdomain. So in this case you need to check if the subdomain belongs to any of the user (by querying the main database) using a middleware and then connect to the database that belongs to the user.
Tenanti doesn't manage that part of the process, because everyone has different style on that aspect, but we do provide a code to dynamically connect to your database tenant from a base database configuration.
Let say you have the following config:
<?php
return [
'fetch' => PDO::FETCH_CLASS,
'default' => 'primary',
'connections' => [
'primary' => [
//
],
'tenants' => [
'driver' => 'mysql',
'host' => 'dbhost', // for user with id=1
'username' => 'dbusername', // for user with id=1
'password' => 'dbpassword', // for user with id=1
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
],
],
'migrations' => 'migrations',
'redis' => [ ... ],
];
You can follow the step available in https://github.com/orchestral/tenanti#multi-database-connection-setup and add the following code.
<?php namespace App\Providers;
use Orchestra\Support\Facades\Tenanti;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Tenanti::setupMultiDatabase('tenants', function (User $entity, array $template) {
$template['database'] = "tenant_{$entity->getKey()}";
return $template;
});
}
}
This would ensure that you be using tenant_1 database for user=1, tenant_2 database for user=2 and so on.
So how does Tenanti detect which user if active?
This is where you need to add logic in your middleware.
$user = App\User::whereSubdomain($request->route()->parameter('tenant'))->first();
Tenanti::driver('user')->asDefaultDatabase($user, 'tenants_{id}');
I've never used this package, but using the code you submitted above here's what I think is probably close to the right solution. You will probably still need to play with some of these values to get them correct:
Migration Paths
Since you're using the multi-database configuration, I believe you should be able to keep your migrations in the normal location, i.e. database/migrations. Tenanti will then create an exact replica of the database for each tenant in a different database. However, when you run php artisan tenanti:install user it might actually create a folder under database/ that indicates where you should put your migrations.
What is a "driver"?
The driver describes whether Tenanti will use a single or multiple databases, what models to use for determining different tenants, and where to store migrations. It is what you identified in the Tenanti config file you used above.
Database Connection Selection
You need to update config/database.php as follows. In a normal Laravel app, you would have the DB connection setup as follows:
<?php
return [
'fetch' => PDO::FETCH_CLASS,
'default' => env('DB_CONNECTION', 'mysql'),
'connections' => [
'sqlite' => [ ...DB connection info... ],
'mysql' => [ ...DB connection info... ],
'pgsql' => [ ...DB connection info... ],
'sqlsrv' => [ ...DB connection info... ],
],
'migrations' => 'migrations',
'redis' => [ ... ],
];
However, in the case of Tenanti multi-database setup, you need to add in different connection info for each tenant's database. To do this you would add a new level to your database.php config file (this example assumes you're using mysql, but you could use any DB, or even different database engines for different tenants):
<?php
return [
'fetch' => PDO::FETCH_CLASS,
'default' => env('DB_CONNECTION', 'mysql'),
'connections' => [
'tenants' => [
'user_1' => [
'driver' => 'mysql',
'host' => 'dbhost', // for user with id=1
'database' => 'dbname', // for user with id=1
'username' => 'dbusername', // for user with id=1
'password' => 'dbpassword', // for user with id=1
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
'user_2' => [
'driver' => 'mysql',
'host' => 'dbhost', // for user with id=2
'database' => 'dbname', // for user with id=2
'username' => 'dbusername', // for user with id=2
'password' => 'dbpassword', // for user with id=2
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
],
],
'migrations' => 'migrations',
'redis' => [ ... ],
];
As you can see, each tenant has its own database instance that can be located on a different host and have a different username/password. Tenanti needs to be told how to figure out which database to use. This is what the documentation on Database Connection Resolver describes. In their example, they've named their tenant databases using acme_{$user->id} whereas in my example above I used user_{$user->id}.
Like I said, I've never actually set this up myself, but these are my best guesses based on the docs, and having used other packages by this same developer. Hope this helps!