How to have conditional database seeding in Laravel? - php

Can I create seed groups? For instance I have seeds that I only want executed some of the time. How can I add a flag when executing php artisan migrate --seed --group1
What are my options for such feature?

Well, what you could do is create multiple Seeder extended classes, and having each one of them running $this->call() on a specific group of tables and then specify which one you want using the --class flag. Something like this:
class GroupOneDatabaseSeeder extends Seeder {
public function run() {
Eloquent::unguard();
$this->call('UserTableSeeder');
$this->call('RoleTableSeeder');
}
}
And then call it this way:
php artisan db:seed --class="GroupOneDatabaseSeeder"
Well, that or you could extend the SeedCommand to add this functionality via methods instead of classes.

Related

SQLSTATE[42S02]: Base table or view not found: 1146 Table 'iop.servicecategories' doesn't exist (SQL: select * from `servicecategories`)

I have a problem with this error so there are my table and model
I try to put this in my model:
protected $table = 'servicecategories';
but the problem is not solved.
also try to clear cache and delete table but the problem is not solved,
also if i try to make a simple php artisan
Please run command => php artisan migrate
In db ..Your table name is different from your class name. I think they both should be the same I think this is the problem ..
When you run
php artisan migrate works?
Maybe it's because you used model or function other in AppServiceProvider. You need comment it before call migrate
you can use php artisan migrate:fresh to rewrite all your db based on existing migration code you have done
It means the database was created but the tables were not.
For Laravel applications, you need to migrate the tables like so ;
php artisan migrate
In your migration you are using a common class, but Laravel uses anonymous classes.
Replace
class CreateServicecategoriesTable extends Migration {
With
return new class extends Migration {

How to seed pivot table in Laravel 5.4?

I am following a tutorial called Incremental API in laracasts by Jeffrey Way.
There is a different coding between Laravel 4 faker class seeding and laravel 5.4.
I still followed the same code lines from the tutorials "Seeders Reloaded". Now, I am stuck with "Class LessonTagTableSeeder does not exist"
TagTableSeeder
class TagsTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
$faker = Faker::create('App\Tag');
for($i=1; $i <= 10; $i++) {
DB::table('tags')->insert([
'name' => $faker->word,
'created_at' => \Carbon\Carbon::now(),
'updated_at' => \Carbon\Carbon::now(),
]);
}
}
LessonTagTableSeeder
use Illuminate\Database\Seeder;
use Faker\Factory as Faker;
use App\Lesson;
use App\Tag;
class LessonTagTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
$faker = Faker::create();
$lessonIds = Lesson::pluck('id')->all();
$tagIds = Tag::pluck('id')->all();
for($i=1; $i <= 30; $i++) {
DB::table('lesson_tag')->insert([
'lesson_id' => $faker->randomElement($lessonIds),
'tag_id' => $faker->randomElement($tagIds)
]);
}
}
DatabaseSeeder
use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
use App\Lesson;
use App\Tag;
use DB;
class DatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
DB::statement('SET FOREIGN_KEY_CHECKS=0');
Lesson::truncate();
Tag::truncate();
DB::table('lesson_tag')->truncate();
Model::unguard();
$this->call('LessonsTableSeeder');
$this->call('TagsTableSeeder');
$this->call('LessonTagTableSeeder');
DB::statement('SET FOREIGN_KEY_CHECKS=1');
}
I was able to seed TagsTableSeeder with php artisan db:seed --class=TagsTableSeeder
When i run "php artisan db:seed --class=LessonTagTableSeeder" , i am prompted with:
[ReflectionException]
Class LessonTagTableSeeder does not exist
Do you have any idea how to edit the code above? Any help is appreciated
When you make changes into the seeder files and it does not reflects your changes you need to run composer dump autoload.
you can use any one of the following commands
$ composer dump-autoload
$ composer du
$ composer dump
$ composer dump-autoload -o
Then try to run you command db:seed again and it reflects you changes.
what composer dump autoload do?
composer dump-autoload won’t download a thing. It just regenerates the list of all classes that need to be included in the project (autoload_classmap.php). Ideal for when you have a new class inside your project.
Ideally, you execute composer dump-autoload -o , for a faster load of your webpages. The only reason it is not default, is because it takes a bit longer to generate (but is only slightly noticeable)
Make sure the file is named as LessonTagTableSeeder.php and it's in the same directory as the other seeders. Then run this command:
composer du
After that try to execute the seeder again.
run this command and then try again
composer dump-autoload -o
Usually cache
php artisan cache:clear
composer update
php artisan serve
A pivot table, or association table, is a table which maps the relationship between two other tables, very useful for two tables which have a many-to-many relationship.
There are 3 critical lines of code which you supplied for the 'DatabaseSeeder':
$this->call('LessonsTableSeeder');
$this->call('TagsTableSeeder');
$this->call('LessonTagTableSeeder');
Based on what you wrote, you only ran the commands for the 'TagsTableSeeder' and the 'LessonTagTableSeeder'. You missed running the command for 'LessonsTableSeeder'.
In other words, you had records in the 'Tag' table, but none in the 'Lesson' table. Therefore there were no records associated between the two tables and SQL couldn't create a null association (pivot) table.
As a further note, the order of execution for seed operations is important when creating an association table. You must execute the seed command for the association table AFTER seeding the other two tables. The association table needs to know the unique identifiers in each of the other tables in order to create the relationships.

How to run laravel migration and DB seeder except one

I am having many migration and seeder files to run, Although I will need to run all files but currently I need to skip one migration and seeder.
How could I skip one file from laravel migration and db seeder command.
I do not want to delete files from the migrations or seeds folder to skip the file.
Laravel doesn't give you a default method to do it. However, you can create your own console commands and seeder to achieve it.
Let's say you have this default DatabaseSeeder class:
class DatabaseSeeder extends Seeder
{
public function run()
{
$this->call(ExampleTableSeeder::class);
$this->call(UserSamplesTableSeeder::class);
}
}
the goal is to create a new command overriding "db:seed" and pass a new parameter, an "except" parameter, to the DatabaseSeeder class.
This is the final code, I created on my Laravel 5.2 instance and tried:
Command, put in app/Console/Commands, don't forget to update your Kernel.php:
namespace App\Console\Commands;
use Illuminate\Console\Command;
class SeedExcept extends Command
{
protected $signature = 'db:seed-except {--except=class name to jump}';
protected $description = 'Seed all except one';
public function handle()
{
$except = $this->option('except');
$seeder = new \DatabaseSeeder($except);
$seeder->run();
}
}
DatabaseSeeder
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
protected $except;
public function __construct($except = null) {
$this->except = $except;
}
public function call($class)
{
if ($class != $this->except)
{
echo "calling $class \n";
//parent::call($class); // uncomment this to execute after tests
}
}
public function run()
{
$this->call(ExampleTableSeeder::class);
$this->call(UserSamplesTableSeeder::class);
}
}
It the code, you'll find that I commented the line that calls the seed and added an echo for testing purposes.
Executing this command:
php artisan db:seed-except
will give you:
calling ExampleTableSeeder
calling UserSamplesTableSeeder
However, adding "except":
php artisan db:seed-except --except=ExampleTableSeeder
will give you
calling UserSamplesTableSeeder
This works overriding the default call method of your DatabaseSeeder class and calling the parent only if the name of the class is not in the $except variable. The variable is populated by the SeedExcept custom command.
Regarding migrations, the thing is similar but a little bit more difficult.
I can't give you tested code for this by now, but the thing is:
you create a migrate-except command that overrides the MigrateCommand class (namespace Illuminate\Database\Console\Migrations, located in vendor/laravel/framework/src/Illuminate/Database/Console/Migrations/MigrateCommand.php).
the MigrateCommand takes a Migrator object (namespace Illuminate\Database\Migrations, path vendor/laravel/framework/src/Illuminate/Database/Migrations/Migrator.php) in the constructor (injected via IoC). The Migrator class owns the logic that reads all the migrations inside the folder and execute it. This logic is inside the run() method
create a subclass of Migrator, for example MyMigrator, and override the run() method to skip the files passed with the special option
override the __construct() method of your MigrateExceptCommand and pass your MyMigrator: public function __construct(MyMigrator $migrator)
If I have time I'll add the code for an example before the bounty ends
EDIT
as promised, here's an example for migrations:
MyMigrator class, extends Migrator and contains the logic to skip files:
namespace App\Helpers;
use Illuminate\Database\Migrations\Migrator;
class MyMigrator extends Migrator
{
public $except = null;
// run() method copied from it's superclass adding the skip logic
public function run($path, array $options = [])
{
$this->notes = [];
$files = $this->getMigrationFiles($path);
// skip logic
// remove file from array
if (isset($this->except))
{
$index = array_search($this->except,$files);
if($index !== FALSE){
unset($files[$index]);
}
}
var_dump($files); // debug
$ran = $this->repository->getRan();
$migrations = array_diff($files, $ran);
$this->requireFiles($path, $migrations);
//$this->runMigrationList($migrations, $options); // commented for debugging purposes
}
}
The MigrateExcept custom command
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Database\Console\Migrations\MigrateCommand;
use App\Helpers\MyMigrator;
use Illuminate\Database\Migrations\Migrator;
use Symfony\Component\Console\Input\InputOption;
class MigrateExcept extends MigrateCommand
{
protected $name = 'migrate-except';
public function __construct(MyMigrator $migrator)
{
parent::__construct($migrator);
}
public function fire()
{
// set the "except" param, containing the name of the file to skip, on our custom migrator
$this->migrator->except = $this->option('except');
parent::fire();
}
// add the 'except' option to the command
protected function getOptions()
{
return [
['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'],
['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production.'],
['path', null, InputOption::VALUE_OPTIONAL, 'The path of migrations files to be executed.'],
['pretend', null, InputOption::VALUE_NONE, 'Dump the SQL queries that would be run.'],
['seed', null, InputOption::VALUE_NONE, 'Indicates if the seed task should be re-run.'],
['step', null, InputOption::VALUE_NONE, 'Force the migrations to be run so they can be rolled back individually.'],
['except', null, InputOption::VALUE_OPTIONAL, 'Files to jump'],
];
}
}
Last, you need to add this to a service provider to permit the Laravel IoC resolve the dependencies
namespace App\Providers;
use App\Helpers\MyMigrator;
use App\Console\Commands\MigrateExcept;
class CustomServiceProvider extends ServiceProvider
{
public function boot()
{
parent::boot($events);
$this->app->bind('Illuminate\Database\Migrations\MigrationRepositoryInterface', 'migration.repository');
$this->app->bind('Illuminate\Database\ConnectionResolverInterface', 'Illuminate\Database\DatabaseManager');
$this->app->singleton('MyMigrator', function ($app) {
$repository = $app['migration.repository'];
return new MyMigrator($repository, $app['db'], $app['files']);
});
}
}
Don't forget to add Commands\MigrateExcept::class in the Kernel.php
Now, if you execute
php artisan migrate-except
you have:
array(70) {
[0] =>
string(43) "2014_04_24_110151_create_oauth_scopes_table"
[1] =>
string(43) "2014_04_24_110304_create_oauth_grants_table"
[2] =>
string(49) "2014_04_24_110403_create_oauth_grant_scopes_table"
...
but adding the except param:
php artisan migrate-except --except=2014_04_24_110151_create_oauth_scopes_table
array(69) {
[1] =>
string(43) "2014_04_24_110304_create_oauth_grants_table"
[2] =>
string(49) "2014_04_24_110403_create_oauth_grant_scopes_table"
So, recap:
we create a custom migrate-except command, MigrateExcept class, extending MigrateCommand
we create a custom migrator class, MyMigrator, extending the behavior of the standard Migrator
when MigrateExcept is fire(), pass the name of the file to skip to our MyMigrator class
MyMigrator overrides the run() method of Migrator and skip the passed migration
More: since we need to instruct Laravel IoC about the new created classes, so it can inject them correctly, we create a Service Provider
The code is tested so it should work correctly on Laravel 5.2 (hoping that cut&paste worked correctly :-) ...if anyone has any doubt leave a comment
Skipping seeds are very simple, migrations not so much. To skip a seed, remove the following from your DatabaseSeeder class.
$this->call(TableYouDontWantToSeed::class);
For migrations, There are three ways you can do it:
Put the class you don't want to migrate into a different folder.
Insert your migrations into the database manually (Bindesh Pandya's answer elaborated).
Rename the file that you don't want to migrate to something like UsersTableMigration.dud.
Hope this helps
I also faced the same problem in my project but after long time wasting in R & D i have found that Laravel does not provide any way to do this with migration and seeding but you have 2 ways to do this.
1) you'll save a lot of time just putting them into different folders.
You could theoretically make your own artisan command that does what
you want, or spoofs its by making directories, moving files, and running
php artisan migrate.
For the seeders, just make a seeder and call the others seeders you want to run from with in it. Then just be explicit about what seeder you want to run. Try php artisan db:seed --help for more details there.
2) you can create a table Manually (which has same name as migration table is creating in you db) and insert the values of migration like this
insert into migrations(migration, batch) values('2015_12_08_134409_create_tables_script',1);
so migrate command will not create table which is already exist in migration table.
If you want just omit (but keep) migration and seeder:
Rename your migration by removing .php extension: mv your_migration_file.php your_migration_file
Go to: DatabaseSeeder.php and comment out line with your unwanted seeder: //$this->call('YourSeeder');.
Run: php artisan migrate --seed
Execute below sql query on db (be careful, there should be migration file name WITHOUT extension) (this will prevent artisan migrate to execute your_migration_file in future):
INSERT INTO migrations (migration, batch) VALUES (your_migration_file, 1)
Rename back your migration file: mv your_migration_file your_migration_file.php
Uncomment your seeder in DatabaseSeeder.php
And you are done. Now when you run php artisan migrate any migration should be executed (except new one if you add some new migration files).
just an idea comment seeder and schema. this is the way i guess
//$this->call(HvAccountsSeeder::class);
//Schema::create('users', function (Blueprint $table) {
// $table->increments('id');
// $table->string('name');
// $table->string('email')->unique();
// $table->string('password');
// $table->rememberToken();
// $table->timestamps();
// });
// Schema::drop('users');
To directly answer your question, Laravel does not have a way to do this currently.
If I understand you correctly, I assume you're looking for a way to temporarily disable/skip a specific class from the default DatabaseSeeder.
You can easily create your own command which will accept a string such as a model/table name and attempt to run the migration and seed for that particular table. You will simply need something like the following:
public function handle(){ //fire for Laravel 4.*
$tables = explode(',', $this->option('tables'));//default []
$skip = explode(',', $this->option('skip'));//default []
$migrations = glob("*table*.php");//get all migrations
foreach($migrations as $migrate){
//if tables argument is set, check to see if part of tables
//if file name not like any in skip.. you get the point

Error: Base table or view not found when Creating Records on Laravel Test SetUp()?

When creating a record in setUp():
public function setUp(){
parent::setUp();
$company = new App\Company();
$company->company_name = 'MyTest';
$company->save();
}
I get the following error:
Base table or view not found
I am using use DatabaseMigrations; in my TestCase. It could be that the migrations run just before a testCase starts, so when `setUpz is run there is no table created yet.
Using Laravel 5.1
Currently I have to repeat myself by creating this record in every test.
Any ideas how to make this work?
I had the same problem. Ended up using the DatabaseTransactions trait instead of DatabaseMigrations. That's not enough though, as you still need to run your migrations and create the db tables. You can do this by also overriding the setUp method on the main TestCase class:
public function setUp()
{
parent::setUp();
$this->artisan('migrate:refresh');
}
This way you rollback and rebuild all tables before each test. And your tests are wrapped in transactions, which are also rolled back.
You can then override the setUp function on your individual test classes and do DB stuff without errors.
Try adding a \ befor App, like this:
$company = new \App\Company();

Hook into laravel 4 artisan command

Is there a way to hook into an artisan command easily? What I'm looking to accomplish is have a piece of code executed everytime the php artisan migrate command is executed.
Just add a listener some place in your code (even at the top of app/start/artisan.php) to listen for the 'artisan.start' event.
Event::listen('artisan.start', function($app)
{
// $app is instance of Illuminate\Console\Application
// since the $app hasn't figured the command yet you'll
// have to do it yourself to check if it's the migrate command
});
You may try something like this (you may put it in the filters.php file):
Event::listen('artisan.start', function($app) {
if( isset($_SERVER['argv'][1]) && $_SERVER['argv'][1] == 'migrate' ) {
// do something because it's migrate command
}
});
You can extend the Schema Builder facade and override the build function like so:
protected function build(Blueprint $blueprint)
{
your_function();
Parent::build($blueprint);
}
However, your function won't be called when using the --pretend option for the migrate. I don't know of any built-in ways to hook into the migration without extending either the Schema Builder or Migrator classes.

Categories