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
Related
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.
I'm asking/answering because I have had so much trouble getting this working and I'd like to show a step-by-step implementation.
References:
https://laravel.com/docs/5.0/facades#creating-facades
http://www.n0impossible.com/article/how-to-create-facade-on-laravel-51
This may not be the only way to implement facades in Laravel 5, but here is how I did it.
We're going to create a custom Foo facade available in the Foobar namespace.
1. Create a custom class
First, for this example, I will be creating a new folder in my project. It will get its own namespace that will make it easier to find.
In my case the directory is called Foobar:
In here, we'll create a new PHP file with our class definition. In my case, I called it Foo.php.
<?php
// %LARAVEL_ROOT%/Foobar/Foo.php
namespace Foobar;
class Foo
{
public function Bar()
{
return 'got it!';
}
}
2. Create a facade class
In our fancy new folder, we can add a new PHP file for our facade. I'm going to call it FooFacade.php, and I'm putting it in a different namespace called Foobar\Facades. Keep in mind that the namespace in this case does not reflect the folder structure!
<?php
// %LARAVEL_ROO%/Foobar/FooFacade.php
namespace Foobar\Facades;
use Illuminate\Support\Facades\Facade;
class Foo extends Facade
{
protected static function getFacadeAccessor()
{
return 'foo'; // Keep this in mind
}
}
Bear in mind what you return in getFacadeAccessor as you will need that in a moment.
Also note that you are extending the existing Facade class here.
3. Create a new provider using php artisan
So now we need ourselves a fancy new provider. Thankfully we have the awesome artisan tool. In my case, I'm gonna call it FooProvider.
php artisan make:provider FooProvider
Bam! We've got a provider. Read more about service providers here. For now just know that it has two functions (boot and register) and we will add some code to register. We're going to bind our new provider our app:
$this->app->bind('foo', function () {
return new Foo; //Add the proper namespace at the top
});
So this bind('foo' portion is actually going to match up with what you put in your FooFacade.php code. Where I said return 'foo'; before, I want this bind to match that. (If I'd have said return 'wtv'; I'd say bind('wtv', here.)
Furthermore, we need to tell Laravel where to find Foo!
So at the top we add the namespace
use \Foobar\Foo;
Check out the whole file now:
<?php
// %LARAVEL_ROOT%/app/Providers/FooProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Foobar\Foo;
class FooProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->bind('foo', function () {
return new Foo;
});
}
}
Make sure you use Foobar\Foo and not Foobar\Facades\Foo - your IDE might suggest the wrong completion.
4. Add our references to config/app.php
Now we have to tell Laravel we're interested in using these random files we just created, and we can do that in our config/app.php file.
Add your provider class reference to 'providers': App\Providers\FooProvider::class
Add your facade class reference to 'aliases': 'Foo' => Foobar\Facades\Foo::class
Remember, in aliases, where I wrote 'Foo', you will want to put the name you want to reference your facade with there. So if you want to use MyBigOlFacade::helloWorld() around your app, you'd start that line with 'MyBigOlFacade' => MyApp\WhereEverMyFacadesAre\MyBigOlFacade::class
5. Update your composer.json
The last code change you should need is to update your composer.json's psr-4 spaces. You will have to add this:
"psr-4": {
"Foobar\\" : "Foobar/",
// Whatever you had already can stay
}
Final move
Okay so now that you have all that changed, the last thing you need is to refresh the caches in both composer and artisan. Try this:
composer dumpautoload
php artisan cache:clear
Usage & A Quick Test:
Create a route in app/routes.php:
Route::get('/foobar', 'FooBarController#testFoo');
Then run
php artisan make:controller FooBarController
And add some code so it now looks like this:
<?php
namespace App\Http\Controllers;
use Foobar\Facades\Foo;
use App\Http\Requests;
class FooBarController extends Controller
{
public function testFoo()
{
dd(Foo::Bar());
}
}
You should end up with the following string:
Troubleshooting
If you end up with and error saying it cannot find the class Foobar\Facades\Foo, try running php artisan optimize
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();
I am trying to update my database using Eloquent model but the class is not recognized.
First I created my table using migration and that worked fine.. Below is the code
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreatePaintings extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('paintings',function($thepainting){
$thepainting->increments('id');
$thepainting->string('title');
$thepainting->string('artist');
$thepainting->integer('year');
$thepainting->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('paintings');
}
}
Next, I created a class "paint" using the model. But note that the recent version of laravel don't have the model folder specified explicitly. So when I ran the code below on the command prompt I was able to create the paint class
php artisan make:model paint
Lastly, I tried updating the created table, paintings, via routes.php using the code below..
Route::get('/', function()
{
$paintings = new Paint;
$paintings->title = 'Emmanuel';
$paintings->artist = 'D. DoRight';
$painitngs->year = 2014;
$paintings->save();
return view('trynn');
});
Route::get('about/directions', function()
{
return "Direction content goes here";
});
Route::get('about/{theSubject}', function($theSubject)
{
return $theSubject. " content goes here";
});
please I am new to laravel, so I will appreciate any help to get this resolved. I am presently stranded. Lest I forget, The error message is shown below
Whoops, looks like something went wrong.
1/1
FatalErrorException in routes.php line 18:
Class 'Paint' not found
in routes.php line 18
Ah, this is a simple error. Can you copy-paste the whole content of the file in if that is not all of it.
Also the error for this is because you haven't brought in the class from the autoloader. In Laravel, everything is namespaced. In your Paint Model, at the top you will see namespace App, if you moved the Paint model into say a models directory, you need to namespace the class App\Models;
To fix this error, at the top of the routes.php file, write use App\Paint;. But you should really send that route to a controller to separate the code from the routes.
Let me know if that helps.
it's normal the class Pain not found, check what you done here :
php artisan make:model paint
and on your routes file :
$paintings = new Paint;
try to correct your model class name to this Paint , and when you want to instanciate it don't forget the namespace by default for the generated model class , so you routes file will look like this
Route::get('/', function()
{
$paintings = new App\Paint;
$paintings->title = 'Emmanuel';
$paintings->artist = 'D. DoRight';
$painitngs->year = 2014;
$paintings->save();
return view('trynn');
});
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.