Laravel Jeffrey Way Generators: "Add To" Confusion - php

I'm following along with Jeffrey Way's generator tutorial for Laravel, and I'm a little confused by the "add to" syntax for migrations. If I run the following command
php artisan generate:migration add_user_id_to_posts_table
I generate the following migration script
public function up()
{
Schema::table('posts', function(Blueprint $table) {
});
}
The generate:migration command has successfully added a call to Schema::table — but there's no mention of the user_id from the command. Is it my responsibility to add this myself, or does the user_id field get added elsewhere? If the former, what's the syntax for adding this field to a table in place? If the later, where is "elsewhere"?
I know I can specify a list of fields when I first create the table, but I'm interested in knowing either the "Jeffrey Way way" or the "standard Laravel PHP code" way for modifying a table in place via migrations.

php artisan generate:migration add_user_id_to_posts_table --fields="user_id:integer"

Related

Is it possible to migrate migrations without an order? (If not, how can I fix this)

Best way for me to describe my problem and it's go-to solution would be this link;
StackOverflow
My problem is exactly this, and the solution actually is working, but not in my case, either I will have an alternative solution for mine, or I'm doing something wrong with my schema builder and I need to understand it better.
My code is basically like this:
//just an example, not my code
Schema A (as)
//other code, such as table->increments('id')
$table->unsignedInteger('b_id');
$table->unsignedInteger('c_id');
$table->foreign('b_id')->references('id')->on('bs');
$table->foreign('c_id')->references('id')->on('cs');
Schema B (bs)
$table->unsignedInteger('a_id');
$table->unsignedInteger('c_id');
$table->foreign('a_id')->references('id')->on('as');
$table->foreign('c_id')->references('id')->on('cs');
Schema C (cs)
$table->unsignedInteger('a_id');
$table->unsignedInteger('b_id');
$table->foreign('a_id')->references('id')->on('as');
$table->foreign('b_id')->references('id')->on('bs');
So neither order helps me with this solution.
Is there a solution to my case, or my code/schema logic is wrong and I need to modify my code?
Your schema is incorrect. You can't have tables being interdependent, i.e, they can't be both master and slave to each other at the same time. This way, you can never make them at all.
You should create master tables first, let's say A,B,C.
Schema A:
$table->increments('id');
// some other columns
Schema B:
$table->increments('id');
// some other columns
Schema C:
$table->increments('id');
// some other columns
Now, create the child tables, in other words, these are intermediate tables describing many-to-many relationships and you can access them using pivot attribute.
Schema AS:
$table->unsignedInteger('b_id');
$table->unsignedInteger('c_id');
$table->foreign('b_id')->references('id')->on('B');
$table->foreign('c_id')->references('id')->on('C');
Schema BS:
$table->unsignedInteger('a_id');
$table->unsignedInteger('c_id');
$table->foreign('a_id')->references('id')->on('A');
$table->foreign('c_id')->references('id')->on('C');
Schema CS:
$table->unsignedInteger('a_id');
$table->unsignedInteger('b_id');
$table->foreign('a_id')->references('id')->on('A');
$table->foreign('b_id')->references('id')->on('B');
Now, you can successfully run a migration in this order and you should be good to go.
In Laravel >= 5.0, one way to achieve this is to have certain scripts in properly named migration folders. Like I use to have migrations in Sprints.
--migrations/
---Sprint8/
------user_table.php
------car_table.php
--Sprint9/
------complaint_table.php
------supervisor_table.php
With this approach, you have to run the migration command on each of your subfolders:
php artisan migrate --path=/database/migrations/Sprint8
php artisan migrate --path=/database/migrations/Sprint9
However, what you can do is easily extend the artisan system to write your own migrate command that will iterate through all folders under the migrations folder, create these commands for you and run them.
You can also simply write a shell script if you don't want to get into doing this via artisan

What's the best way to refactor a database and its data? (Laravel 5.2)

I'm trying to figure out how to deal with structural as well as data concerned changes within migrations in Laravel 5.2.
At the moment I just change the existing data after applying structural changes to the database.
But that seems to collide with the version controlled code.
A simple example
A column owner_id should be added to the teams table. Simple migration, no problem. Afterwards, all existing teams should get such an id. Therefore I put this in the migration, too:
foreach ($teams as $team) {
// get the first user of this team over a many-to-many-relationship-table `team_user`
$team->owner_id = $team->users->first()->id;
...
}
At the first glance that works fine.
After a few days and commits, I decide to add a pivot column role in the mentioned relation table. I add the migration and in the team model I put something like this:
public function users() {
return $this->belongsToMany(...)->withPivot('role');
}
The resulting problem
If I want to completely refresh my local database now, I'll get an error in the first migration. That's because it called $team->users, but in this state of the database the role isn't available yet and so the method call fails. It's like a shift between version control and database migrations.
Is there a clean solution for this?
Big thanks in advance,
Richard
Usually migrating is DDL (data definition language) and seeding is DML (data manipulation language).
Migrating database tables is a matter of order. You cannot add code which depends on some DDL, which may be executed before those DDL are run.
Another thing you have to consider is: migrations are not the place to do data seeding, modification, manipulation, because seeding may require ALL data definition is done before you start seeding. That's why Laravel has data seeding.
So, there is no difference between seeding, fixing nor changing data, it's all DML. You can do it in your migrations, it's not forbidden, but in those you have to be very careful by undoing (on down) every single step you took in the up method. But sometimes it is too hard to manipulate back your data.
Your problem is that you are trying to access some data, via relations, which is not ready (or done, or seeded) yet, because a migration which would do that were not run yet. So you have a conflict between DDL and DML, which would not occur if you treated them separately.
Usually data seeding is done only for testing, but if you really need it you can do something like this in your seeder:
<?php
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
if (app()->environment('testing')) {
$this->call(TestingSeeders::class);
}
$this->call(ProductionReadySeeders::class);
}
}
Or you can just create a command to seed your data:
Artisan::command('app:seed', function ($email)
{
// Do whatever you need to seed your database tables
});
And run with
php artisan app:seed
If you want to make sure everyone who gets a new version if your app also get the correct data, you can use Composer post execution commands to do so:
"post-install-cmd": [
"Illuminate\\Foundation\\ComposerScripts::postInstall",
"php artisan optimize",
"php artisan migrate --force",
"php artisan app:seed"
],
"post-update-cmd": [
"Illuminate\\Foundation\\ComposerScripts::postUpdate",
"php artisan optimize",
"php artisan migrate --force",
"php artisan app:seed"
]

How to create database migrations?

I am new in the database migration world. I use or try to use migrations in Rails and Laravel but in none of them I did not understand this parts:
1.For each modification of database like adding a column, change a field type from integer to string, change database type from InnoDB in Myisam should I generate a migration from comand line?
php artisan make:migration ........ for laravel
rake db:migration ..... for rails
Or to edit existing migration files and after execute migration? Or create manually file?
2.When Laravel documentation say:
To rename a column, you may use the renameColumn method on the Schema
builder. Before renaming a column, be sure to add the doctrine/dbal
dependency to your composer.json file:
Schema::table('users', function ($table) {
$table->renameColumn('from', 'to');
});
This mean that I have to insert this code to the last migration file or to create a new migration file?
Most common practice is to generate new migrations for changes. Compare workflows:
When creating new migration:
rails g migration ...
rake db:migrate
When editing existing:
rake db:rollback # you should not forget to execute it first; also, data may be lost
edit migration
rake db:migrate
Restore data if it was lost on first step
Also, when you work in team, each member should process these steps, too. Just too much noise, better to generate new migration.

Building database schema Laravel4 vs Symfony2

To make it clear let's make classic example - User and Post.
Creating db schema in Symfony2 is clean and simple:
we create entities Post and User
additionaly we can simply add columns/indexes to each.
then just add value with OneToMany annotation in User and ManyToOne in Post
..well, that's it. Now if we run db:schema:update --force and we can get what we want - database schema and simple adding another rows in database.
What about Laravel4? So far only solution I found:
create/generate Post and User models
declare in each model which table it refers to
create migrations and in Post migration add foregin key to user_id column
run migration
add in each model methods in which we refer to the other model (hasMany, belongsTo .. )
As I wrote it, it doesn't seem so complicated, but it's not so concentrated in Laravel as it is in Symfony. I'm kinda lazy person and I really enjoy the process in Symfony, while in Laravel it is a little bit too diffuse. Is there any simpler ( lazier :P ) way to do this in Laravel? Something like creating schema based on Model?
The question makes sense but unfortunately there isn't such functionality on Laravel at the moment.
As opposed to running migrations from your models (symfony) you must create the migrations first, the you can use the models to seed database tables if they have foreign keys.
I use the Jeffrey Way Generators https://github.com/JeffreyWay/Laravel-4-Generators
to speed up the process so for example if I have a users table and a profile table (many to many) then I would perform these tasks on command line:
php artisan generate:migration create_users_table --fields="username:string, password:string, email:string"
php artisan generate:migration create_profiles_table --fields="name:string, lastname:string, phone:string"
php artisan migrate
php artisan generate:pivot users profiles
php artisan migrate
Then you can create your models (you can also generate an entire CRUD resource or Scaffold)
php artisan generate:model user
php artisan generate:model profile
Then in your User Model
public function profile()
{
return $this->belongsToMany('Profile');
}
In your Profile Model
public function user()
{
return $this->belongsToMany('User');
}
Yes, there are some plugins / commands that speed up the development.
For example Jeffrey Way's Laravel-4-Generators

Sentry 2 and Laravel 4 adding fields to the user model

Im trying to add fields to the Users model that is based around Sentry 2 for Laravel 4.
I want to do it properly with migrations.
Is there a way to simply add to the sentry 2 migrations? or should i simply make my own migrations and add the required extra fields?
any guidance with the framework would be awesome!
If you want add some fields you need this:
run Sentry Migrations: php artisan migrate --package=cartalyst/sentry
create a migration to add custom fields to Users table: php artisan migrate:make --table=users
example in funcion up():
Schema::table('users', function(Blueprint $table)
{
$table->string('new_field');
});
And then extend the Sentry User Model:
Check this example is extending Sentry Model and full implementation example check this: Laravel 4 Backend and simple web site
The purpose of migrations is versioning of the database structure. The answer to any question similar to "where should I put database changes?" is always: "in a new migration", because then you're able to rollback changes.
In this case, I think I would first add Sentry 2 to your project and commit "Added Sentry 2". After, I would create a new migration with your desired changes, then commit: "Added fields x y and z to Users table".
See also the introduction paragraph of the documentation: http://four.laravel.com/docs/migrations
The best way to do this is simple navigate to the actual sentry migration file found at
vendor/cartalyst/sentry/src/migrations
copy the needed migrations out and create your own migrations file.
There is no other way. Just me being lazy i guess.

Categories