Eloquent: Invalid default value with timestamps - php

Here's my migration schema:
public function up()
{
Schema::create('objects', function (Blueprint $table) {
$table->increments('id');
$table->timestamp('timestamp1');
$table->timestamp('timestamp2');
});
}
But when I execute php artisan migrate, I get this error:
Illuminate\Database\QueryException : SQLSTATE[42000]: Syntax error or access violation: 1067 Invalid default value for 'timestamp2' (SQL: create table objects (id int unsigned not null auto_increment primary key, timestamp1 timestamp not null, timestamp2 timestamp not null) default character set utf8mb4 collate utf8mb4_unicode_ci)
I must indicate that when I remove one of the 2 $table->timestamp(...); lines it works, but it doesn't when there is both. And the Object.php model is empty as it can be. Did I make a mistake?
I have read this post, but even though there is no longer errors when I change timestamp(...) into dateTime(...), I only want timestamps.

Timestamps are a little special, they must either be nullable or they must have a default value. So you must choose between timestamp('timestamp1')->nullable(); or timestamp('timestamp1')->useCurrent() or a custom default value like timestamp('timestamp1')->default(DB::raw('2018-01-01 15:23')).

I found this solution on laracasts:
nullableTimestamps() are only for default fields created_at, updated_at. for custom fields use timestamp()->nullable();

You can make one of the two timestamps nullable by using
timestamp()->nullable();
using your example, you would use:
$table->timestamp('timestamp2')->nullable();
Also laravel has built in timestamps by using
$table->timestamps();
which would automatically handle updated_at and created_at timestamping for you

Related

Postgres and Laravel how to change column from type string to integer?

I am trying to change a column from type string to integer on Postgres and Laravel 6.x. I've tried to do this with a migration like so:
public function up()
{
Schema::table('job_listings', function (Blueprint $table) {
$table->integer('company_id')->change();
});
}
When I run this migration I get an error that the column cannot be automatically cast to an integer:
In Connection.php line 664:
SQLSTATE[42804]: Datatype mismatch: 7 ERROR: column "company_id" cannot be cast automatically to type integer
HINT: You might need to specify "USING company_id::integer". (SQL: ALTER TABLE job_listings ALTER company_id TYPE INT)
In PDOStatement.php line 123:
SQLSTATE[42804]: Datatype mismatch: 7 ERROR: column "company_id" cannot be cast automatically to type integer
HINT: You might need to specify "USING company_id::integer".
In PDOStatement.php line 121:
SQLSTATE[42804]: Datatype mismatch: 7 ERROR: column "company_id" cannot be cast automatically to type integer
HINT: You might need to specify "USING company_id::integer".
How do we specify USING to change this column from type string to integer in PostgreSQL?
You must specify an explicit cast since there is no implicit (automatic) cast from text or varchar to integer. I don't know of a Laravel function to specify the cast so I would suggest you use raw DB statement to achieve this.
You could do this:
public function up()
{
DB::statement('ALTER TABLE job_listings ALTER COLUMN
company_id TYPE integer USING (company_id)::integer');
}
There can also be cases where there are whitespace in your text or varchar fields so you would have to trim before casting
public function up()
{
DB::statement('ALTER TABLE job_listings ALTER COLUMN
company_id TYPE integer USING (trim(company_id))::integer');
}
Even the tables has row or not, it's still return that error. So if you don't want raw query and your column doesn't have value or has but not important, just drop column and create new one:
public function up()
{
Schema::table('job_listings', function (Blueprint $table) {
$table->dropColumn('company_id');
$table->integer('company_id');
});
}

Laravel 5.5 migration fails: Update column datatype string to json

When I migrate my db I get a error on updating a table column from string to JSON.
The column value is like:
{"images":["/vendors/57/horse-16.png"]}
I checked if this is a valid JSON and that looks good to me..
My migration file is:
public function up()
{
Schema::table('vendor_horses', function (Blueprint $table) {
$table->json('image')->change();
});
}
My error in Laravel:
SQLSTATE[42000]: Syntax error or access violation: 1253 COLLATION 'utf8mb4_
unicode_ci' is not valid for CHARACTER SET 'binary' (SQL: ALTER TABLE vendo
r_horses CHANGE image image JSON DEFAULT NULL COLLATE utf8mb4_unicode_ci)
I don't know what's wrong, the strings are json correct so why does the update fails?
I dig some issues related to the error in Github and found that when changing into a JSON field, the collation should be set to an empty string and this issue will be solved. So you can try by changing the below code:
$table->json('image')->change();
to
$table->json('image')->customSchemaOptions(['collation' => ''])->change();
For more details you can check this issue
$query = "ALTER TABLE tablename MODIFY image JSON DEFAULT NULL";
\Illuminate\Support\Facades\DB::statement($query);
Try this in laravel migration.. working for me

Laravel schema builder primary key as foreign key

I'm using the Laravel 4.2 schema builder to create some tables referencing each other, and am having some issues.
I have a simplified ERD. Note that only relevant columns are shown:
Note that I cannot modify the tblcurrencies and tbldomains tables in any way, since I am developing a module to hook into an existing system.
I am trying to achieve the following:
The extensions table contains extra information about rows in the tbldomains table
The prices table contains pricing information about a domain in a certain currency, with the additional type value (registration, renewal, transfer)
I want to use foreign keys so that I can cascade deletions.
Currently, I use the following code to create the two tables:
Capsule::schema()->create('extensions', function ($table) {
$table->engine = 'InnoDB';
$table->integer('relid', 10);
// ...
$table->primary(['relid']);
$table->foreign('relid')->references('id')->on('tbldomains')->onDelete('cascade');
});
Capsule::schema()->create('prices', function ($table) {
$table->engine = 'InnoDB';
$table->integer('relid', 10);
$table->integer('currency', 10);
$table->enum('type', ['domainregister', 'domainrenew', 'domaintransfer']);
// ...
$table->primary(['relid', 'currency', 'type']);
$table->foreign('relid')->references('relid')->on('extensions')->onDelete('cascade');
$table->foreign('currency')->references('id')->on('tblcurrencies')->onDelete('cascade');
});
The creation script for the prices table results in the following SQL query:
create table `prices` (`relid` int unsigned null auto_increment primary key, `currency` int unsigned null auto_increment primary key, `type` enum('domainregister', 'domainrenew', 'domaintransfer') not null, ...) engine = InnoDB
Which in turn results in the following error:
SQLSTATE[42000]: Syntax error or access violation: 1075 Incorrect table definition; there can be only one auto column and it must be defined as a key
I have also tried setting the primary keys as unique instead, figuring that perhaps Laravel automatically set primary integer keys as auto increment.
Furthermore, I tried setting the columns as unsigned and index, as suggested by this and this answer
How do I stop the schema builder from setting the relid and currency fields to auto increment, since they are simply foreign keys?
based on Laravel Documentation Api on the below link, only string() method can have length attribute.
Laravel Documentation Api
So to make those two column unsigned and not primary key or auto increment make the following change:
from this:
$table->integer('relid', 10);
$table->integer('currency', 10);
to this:
$table->integer('relid', false, true);
$table->integer('currency', false, true);
Because as per the documentation the integer() method syntax is:
integer(string $column, bool $autoIncrement = false, bool $unsigned = false)
And what you did is you assigned a value (10) to a boolean variable ($autoIncrement) which will always returns true on this case. For further proof of this, please refer back to the below link from php.net.
php.net Boolean
I had the same issue before, and when I start referring back Laravel documentation 90% of confusion will be cleared. Hope this helps you.
Note: you can also use unsignedInteger() method, which i think it's more explicit and easier to remember:
unsignedInteger(string $column, bool $autoIncrement = false)
So the code will be like so:
$table->unsignedInteger('relid');
$table->unsignedInteger('currency');

Laravel timestamps() doesn't create CURRENT_TIMESTAMP

I have a migration that has the timestamps() method, and then I have a seed to seed this table.
Schema::create('mytable', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->timestamps();
});
The seed looks like this:
DB::table('mytable')->insert([
[
'title' => 'My Awesome Title'
]
]);
When it all gets run using:
php artisan migrate:refresh --seed
The item gets inserted, but the values of created_at and updated_at are both 0000-00-00 00:00:00 why are they not set correctly?
here are the column schemes that it creates:
`created_at` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
I would like these schemes:
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
When you insert data not using Eloquent you need to insert timestamps on your own.
If you use:
$x = new MyTable();
$x->title = 'My Awesome Title';
$x->save();
you will have timestamp filled correctly (of course you need to create MyTable model first)
EDIT
If you really want it you can change:
$table->timestamps();
into:
$table->timestamp('created_at')->default(\DB::raw('CURRENT_TIMESTAMP'));
$table->timestamp('updated_at')->default(\DB::raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));
And if you create model for this table, you should set
$timestamps = false;
to make sure Eloquent won't try to set them on his way.
EDIT2
There is also one more important issue. In case you mix setting dates in tables from PHP and in other in MySQL you should make sure that both in both PHP and MySQL there's exact same datetime (and timezone) or you should use the same date comparison as you set in record (either MySQL or PHP). Otherwise when running queries you might get unexpected results for example
SELECT * FROM mytable WHERE DATE(created_at) = CURDATE()
might be different than running query with passing PHP date
"SELECT * FROM mytable WHERE DATE(created_at) = '".date('Y-m-d")."'"
because on PHP server it might be for example 2015-12-29 but on MySQL server 2015-12-30
For later versions, you can simply use. (source)
$table->timestamp('created_at')->useCurrent();
$table->timestamp('updated_at')->useCurrent();
i would use the carbon library if i am seeding in the timestamps and set that up in the factory.
if not you could do something like this :
$timestamps = false;
and i would remove the the $table->timestamps();
from the migration if i am not going to use it.

How can I make auto-increment columns non-auto-increment?

I am trying to create a table with this code.
public function up()
{
Schema::create('BookInfo', function (Blueprint $table) {
$table->increments('id');
$table->integer('bookId',11);
$table->string('Name',255);
$table->string('Publisher')->nullable();
$table->integer('Publishing_year',4)->nullable();
$table->integer('Price',5)->nullable();
$table->string('Language',30);
$table->timestamps();
});
}
When I tried php artisan migrate it shows me this error.
[Illuminate\Database\QueryException]
SQLSTATE[42000]: Syntax error or access violation: 1075 Incorrect
table definition; there can be only one auto column and it must
be defined as a key (SQL: create tableBookInfo(bookIdint not
null auto_increment primary key,Namevarchar(255) not null,
Publishervarchar(255) null,Publishing_yearint null
auto_increment primary key,Priceint null auto_increment primary key,
Languagevarchar(30) not null,created_attimestamp default 0
not null,updated_attimestamp default 0 not null) default character
set utf8 collate utf8_unicode_ci) and
[PDOException]
SQLSTATE[42000]: Syntax error or access violation: 1075 Incorrect
table definition; there can be only one auto column and it must be
defined as a key
It seems laravel takes all the integer columns as auto-increment.What happened here actually and what will be solution?
The error says it all,
$table->integer('bookId',11);
^// this is considered as autoincrement rather than length
There is no length option for integers
See this
References on SO, this and this
$table->integer('bookId',11); is not syntactically correct in Eloquent ORM(you can't set any size limit for integers) and that is causing the error in your case.
And $table->increments('id'); automatically sets id as a primary key.
Find all necessary table building commands in Eloquent ORM here: http://laravel.com/docs/4.2/schema#adding-columns

Categories