Background
I am trying to extend class Blueprint to make my Blueprint.Finally,I found the way .But when I made attempt to overwrite some ColumnDefinition ,some trouble stopped me.
Problem 1
Schema::create('Person',function(Blueprint $table){
$table->string('id')->comment('身份证号');
$table->string('id')->comment('学号')->change();//this line doesn't work!
});
Like the code above,the second line in that Closure doesn't work and i don't know why.
What I know is that some 'Modify Cloumn' operations need a dependency called doctrine/dbal and I have installed it.
The function change() neither reports any error nor meets expectation.It is strange.
Please help me!
Problem 2
By reading the source code of Schema,I found the relationship between Schema and Blueprint is Schema->Builder->Blueprint.Schema::create() will call $blueprint->create() before the Closure function(Blueprint $table).It seems that it is the same effect whether I define the fields in the Closure or directly put the field definitions in the $blueprint->__constructor().But,when I run migrate,the Blueprint's constructor is called more than once.If I put all of the column definitions in that Closure,everyting is fine.Strange!
And,I also noticed that $table->unique() finally becomes alter table $table add unique,why not compile command before creating like create table $table(...,unique key $keyname (k1,k2,)).
At present,I believe that Blueprint saves column definitions in a array $commands[] and finally compiles the commands into sql.If so,why not support overwrite when before table is created?
Related
I'm using spatie/laravel-menu and spatie/laravel-persmissions in my laravel project.
I have created a permission, assigned it to a role, and assigned the role to my user. This works fine.
Then I have generated a menu the middleware way using a macro like so:
\Menu::macro('main', function () use ($request) {
return \Menu::new()
->withoutWrapperTag()
->withoutParentTag()
->setActiveClassOnLink()
->route('preparation', 'Anstehende Termine')
->route('postprocessing', 'Nachbereitung')
->routeIfCan('administrate', 'protocols', 'Protokolle')
->addItemClass('nav-link')
->setActive($request->url());
});
In my application I have two User models with different connections:
App\User; using connection_a with database db_a and
App\DirectoryA\User; using connection_b with database db_b
In the auth config the first one is defined, and using Auth::user()->can('administrate') works fine, even in the Middleware that defines the menu.
Since I have added the menu item via routeIfCan, I'm getting an error. It tells
Base table or view not found: 1146 Table 'db_b.permissions' doesn't exist (SQL: select permissions.*, model_has_permissions.model_id as pivot_model_id, model_has_permissions.permission_id as pivot_permission_id, model_has_permissions.model_type as pivot_model_type from permissions inner join model_has_permissions on permissions.id = model_has_permissions.permission_id where model_has_permissions.model_id = 1 and model_has_permissions.model_type = App\User)
What is going wrong here? It should use the App\User model. Placing a dd() at the point the framework throws the exception shows me the correct connection...
Please help.
this mean table permissions not exist on your database maybe you forgot to run php artisan migrate after install laravel-permission?
A member of spatie helped to solve the problem:
Under the hood, routeIfCan calls app(Gate::class)->allows($ability, $ablityArguments). I assume Gate behaves slightly different than Auth::user() when it comes to multiple guards.
I don't see much room in routeIfCan to add an additional $guard or $connection argument, so I suggest you use $menu->addIf(Auth::user()->can('administrate'), ...) instead.
I am using Laravel 4.2. I have the following library loaded in my composer.json
"doctrine/dbal": "2.4.*",
I created the following migration:
class RenameDeliveryNotesColumnOnOrderHeaderTable extends Migration {
public function up()
{
Schema::table('order_header', function(Blueprint $table)
{
$table->renameColumn('delivery_notes', 'packing_notes');
});
}
}
Where delivery_notes column type is text.
When I run the migration, I get the following error:
[Doctrine\DBAL\DBALException] Unknown database type enum requested,
Doctrine\DBAL\Platforms\MySqlPlatform may not support it.
Any idea why I am getting this error? How should I go about fixing this? I need to rename a column in my table. Are there any alternative way to rename the column?
DB::getDoctrineSchemaManager()
->getDatabasePlatform()
->registerDoctrineTypeMapping('enum', 'string');
This works for me on Laravel 5.1
Laravel's documentation says that:
Note: Renaming enum column types is not supported.
Here: https://github.com/laravel/framework/issues/1186
You can find some workarounds about this issue. And since you said that this column is not enum, take a look at #upngo's comment:
"...The issue is renaming ANY column on a table that has an enum."
Also I found this article that focuses on this issue and suggest an option that might help you.
http://www.paulbill.com/110/laravel-unknown-database-type-enum-requested-doctrinedbalplatformsmysqlplatform-may-not-support-it
I met this problem in Laravel version 5.1.19 (LTS). This is actual for earlier versions too.
I wanted to inform you as I resolved the issue base on previous comments.
First of all, I tried next code in my migration file:
$table->renameColumn('column_name');
But after command php artisan migrate, I got next error:
[Symfony\Component\Debug\Exception\FatalErrorException] Class
'Doctrine\DBAL\Driver\PDOMySql\Driver' not found
As you know DBAL was removed from the laravel core and we need add it to the composer.json.(For example:"require": {"doctrine/dbal": "2.5.1"}).
I set DBAL as required and tried again to do migrate command but got next error:
[Doctrine\DBAL\DBALException]
Unknown database type enum requested,
Doctrine\DBAL\Platforms\MySqlPlatform may not support it.
Then I tried next raw sql in my migration file:
For up():
DB::statement("ALTER TABLE `table_name` CHANGE `old_column_name` `new_column_name` ENUM('first value', 'second_value', ...) DEFAULT 'first_value' AFTER `some_field`");
For down():
DB::statement("ALTER TABLE `table_name` CHANGE `new_column_name` `old_column_name` ENUM('first value', 'second_value', ...) DEFAULT 'first_value' AFTER `some_field`");
and it works.
P.S. For renaming other fields in the table which contains an enum field we should
use same schema with raw sql as was written in previous comments.
You can add custom constructor to migration and explain to Doctrine that enum should be treated like string.
public function __construct(\Doctrine\DBAL\Migrations\Version $version)
{
parent::__construct($version);
$this->platform->registerDoctrineTypeMapping('enum', 'string');
}
Here is the answer for Laravel 5.2.45+ (might work in 5.1 as well, have not tested or checked yet, please let me know so I can update this question.)
Add this line in your up method:
Schema::getConnection()->getDoctrineSchemaManager()->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string');
Something like this:
public function up()
{
Schema::getConnection()->getDoctrineSchemaManager()->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string');
Schema::table('users', function (Blueprint $table) {
$table->text('bio')->change();
});
}
I had the same problem with Laravel 5.1 and PostGres.
So basically I used the DB::statement to create the ENUM and solve the problem:
DB::statement("CREATE TYPE e_users AS ENUM('data1','data2')");
And then:
DB::statement("ALTER TABLE users ADD COLUMN column e_users");
Though the original author had issues with Laravel 4, this can safely be fixed in Laravel 5 by bumping the version of doctrine/dbal in your composer.json to ^2.6, as it was fixed in this PR on release 2.6.0
Make sure to check for compatibility-breaking changes in the release changelog
Currently, there is no legal solution for this problem except avoiding enums, but there is a workaround:
Create migration with the following:
public function up()
{
DB::statement("ALTER TABLE `table` CHANGE `example_enum_column` `example_enum_column` ENUM('enum1', 'enum2', 'enum3+');");
}
And that will do the trick with the ENUM update you are looking for. Additionally, you can create handle down functions to revert field status as it used to be:
public function down()
{
DB::statement("ALTER TABLE `table` CHANGE `example_enum_column` `example_enum_column` ENUM('enum1', 'enum2');");
}
Is there any method to adding column in existing table without using migration. I mean executing php artisan migrate and creating migration file through program/code in Laravel rather than CLI. Thank you.
Migration files are only an easy way to create tables and other db actions, you still can use raw queries on Laravel anywhere by using DB::raw(...); check its documentation (https://laravel.com/docs/5.8/queries) to proper use it.
You may also be able to write a Schema::table(,,,) anywhere on your code, it will return some a Schema object which you can execute some method to run the code on your apo runtime, if you are using some IDE just try to explore and see what will you have by typing Schema::table(...)->
TRy this add just coloumn in your migration table
public function up()
{
Schema::table('users', function($table) {
$table->string('name');// only add this line
});
}
php artisan migrate:refresh
So, going into the problem straight away. someone told me that we dont need to make a pivot table if we only want to have ids of the table. laravel can itself handle this situation. I dont know how this works. I have a table community and another table idea. relation is like this;
One community can contain many ideas and an idea can be found in many
communities.
Relation in idea Model:
public function community() {
return $this->belongsToMany('App\Community')->withTimestamps();
}
Relation in community Model:
public function idea() {
return $this->belongsToMany('App\idea');
}
Now i want to fetch all the records related to a single community to show on its page Let's say the community is Arts.
Here is Controller function:
public function showCommunities($id) {
$community = Community::findOrFail($id)->community()->get();
return view('publicPages.ideas_in_community', compact('community'));
}
When i attach ->community()->get() to the Community::findOrFail($id) Then it throws the error
SQLSTATE[42S02]: Base table or view not found laravel
Any help would be appreciated.
Edit:
Logically, this piece of code Community::findOrFail($id)->community()->get() should be like this Community::findOrFail($id)->idea()->get(). Now it is true but it has little issue. it throws an error
Fatal error: Class 'App\idea' not found
The way you define the many-to-many relation looks ok - I'd just call them communities() and ideas(), as they'll return a collection of objects, not a single object.
Make sure you use correct class names - I can see you refering to your model classes using different case - see App\Community and App\idea.
In order to find related models, Eloquent will look for matching rows in the pivot table - in your case it should be named community_idea and have 3 fields: community_id, idea_id and autoincrement primary key id.
With that in place, you should be able to get all ideas linked to given community with:
$ideas = Community::findOrFail($communityId)->ideas;
If you need communities linked to given idea, just do:
$communities = Idea::findOrFail($ideaId)->communities;
You can read more about how to use many-to-many relationships here: https://laravel.com/docs/5.1/eloquent-relationships#many-to-many
someone told me that we dont need to make a pivot table if we only want to have ids of the table
The above is not true (unless I've just misunderstood).
For a many-to-many (belongsToMany) their must be the two related table and then an intermediate (pivot) table. The intermediate table will contain the primary key for table 1 and the primary key for table 2.
In laravel, the convention for naming tables is plural for your main tables i.e. Community = 'communities' and Idea = 'ideas'. The pivot table name will be derived from the alphabetical order of the related model names i.e.
community_idea.
Now, if you don't want/can't to follow these conventions that's absolutely fine. For more information you can refer to the documentation: https://laravel.com/docs/5.2/eloquent-relationships#many-to-many
Once you're happy that you have the necessary tables with the necessary fields you can access the relationship by:
$ideas = $community->ideas()->get();
//or
$ideas = $community->ideas;
So you controller would look something like:
public function showCommunities($id)
{
$community = Community::findOrFail($id);
//The below isn't necessary as you're passing the Model to a view
// but it's good for self documentation
$community->load('ideas');
return view('publicPages.ideas_in_community', compact('community'));
}
Alternatively, you could add the ideas to the array of data passed to the view to be a bit more verbose:
public function showCommunities($id)
{
$community = Community::findOrFail($id);
$ideas = $community->ideas
return view('publicPages.ideas_in_community', compact('community', 'ideas));
}
Hope this helps!
UPDATE
I would imagine the reason that you're receiving the App\idea not found is because the model names don't match. It's good practice (and in certain environments essential) to Capitalise you class names so make sure of the following:
Your class name is Idea and it's file is called Idea.php
The class has it's namespace declared i.e. namespace App;
If you've added a new class and it's not being found you might need to run composer dump-autoload from the command line to update the autoloader.
I'm upgrading a big project form Yii1 to Yii2. I'm having some problems regarding to ORM.
I have several relation declared in the following fashion(basically a copy-paste from the guidebook):
class Order extends \yii\db\ActiveRecord {
/* other code */
public function getAffiliate()
{
return $this->hasOne(Affiliate::className(), ['id_affiliate' => 'affiliate_id']);
}
Whenever I try to echo or w/e $order->affiliate->name; I get the following error:
yii\base\ErrorException: Trying to get property of non-object
I've got no experience with Yii1 what so ever. Something weird about this project is the database. All tables start with yii_tablename and id's are: id_tablename. Was that normal for Yii1 and could this be causing the issue above?
Edit: When I execute the function like so: $order->getAffilate() it returns an ActiveQuery WITHOUT the data from the affiliate.
When I execute the following:
$order->getBillingAddress()->one();
I get a weird error:
Getting unknown property: app\models\Order::billing
return $this->hasOne(Affiliate::className(), ['id_affiliate' => 'affiliate_id']);
It's mean that when you call $order->affiliate yii2 will find in Affiliate table on id_affiliate field current Order affiliate_id value and selected one value.
Check that you have right field names and database have right data.
When you call $order->affiliate you will get Affiliate object. But if you call $order->getAffiliate() you will get ActiveQuery object.
I found a solution. One which I don't really like though, but it does the job. Was reading this thread: link.
Kartik V
The problem is clearly in uniqueness in naming your relation and your model attribute. In your User model, you have an attribute named role and you also have a relation getter named getRole.
So I changed the name of the getter like so:
public function getOrderAffiliate()
{
return $this->hasOne(Affiliate::className(), ['id_affiliate' => 'affiliate_id']);
}
And that fixed the issue. Never had this issue before and wonder why this happened though.