Adding two created_at on one insert - laravel

I want to add another created_at column on the database columns for reference.
I want to have a created_at and created_at1 at the same time.
This is what I have in my Model:
const CREATED_AT = 'created_at1';
protected $dates = [created_at, created_at1];
But I'm receiving this error: Field 'created_at' doesn't have a default value.

You do not need to add casting to the created_at since Laravel has already done it for you.
You need to add inside the string like
protected $dates = ['created_at1']
If you want to set the created_at1 when a new model is created, you can add Model Events.
Inside your model,
protected static function boot(){
parent::boot();
static::creating(function($model){
$model->created_at1 = Carbon::now();
});
}
Inside controller
$model = Model::create([
...
]);
Now it will set created_at and created_at1
For the insert, you have to manually save the value to the created_at1 because it will not reflect the model event.
Model::insert([
...
'created_at1' => Carbon::now()
]);

You might not be passing value to created_at column while inserting data. Please do check. If this is not the case please do provide more information on your problem.

Related

Right way to save timestamps to database in laravel?

As part of a standard laravel application with a vuejs and axios front-end, when I try to save an ISO8601 value to the action_at field, I get an exception.
class Thing extends Model {
protected $table = 'things';
// timestamp columns in postgres
protected $dates = ['action_at', 'created_at', 'updated_at'];
protected $fillable = ['action_at'];
}
class ThingController extends Controller {
public function store(Request $request) {
$data = $request->validate([
'action_at' => 'nullable',
]);
// throws \Carbon\Exceptions\InvalidFormatException(code: 0): Unexpected data found.
$thing = Thing::create($data);
}
}
My primary requirement is that the database saves exactly what time the client thinks it saved. If another process decides to act on the "action_at" column, it should not be a few hours off because of timezones.
I can change the laravel code or I can pick a different time format to send to Laravel. What's the correct laravel way to solve this?
The default created_at and updated_at should work fine.
You should always set your timezone in your config/app.php to UTC
Add a timezone column or whichever you prefer in your users table
Do the time-offsets in your frontend or api response
Here's a sample code to do the time offset in backend
$foo = new Foo;
$foo->created_at->setTimezone('America/Los_Angeles');
or frontend using momentjs
moment(1650037709).utcOffset(60).format('YYYY-MM-DD HH:mm')
or using moment-timezone
moment(1650037709).tz('America/Los_Angeles').format('YYYY-MM-DD HH:mm')
class Thing extends Model {
protected $table = 'things';
// timestamp columns in postgres
protected $dates = ['action_at', 'created_at', 'updated_at'];
protected $fillable = ['action_at'];
}
class ThingController extends Controller {
public function store(Request $request) {
$data = $request->validate([
'action_at' => 'nullable',
]);
// convert ISO8601 value, if not null
if ($data['action_at'] ?? null && is_string($data['action_at'])) {
// note that if the user passes something not in IS08601
// it is possible that Carbon will accept it
// but it might not be what the user expected.
$action_at = \Carbon\Carbon::parse($data['action_at'])
// default value from config files: 'UTC'
->setTimezone(config('app.timezone'));
// Postgres timestamp column format
$data['action_at'] = $action_at->format('Y-m-d H:i:s');
}
$thing = Thing::create($data);
}
}
Other tips: don't use the postgres timestamptz column if you want to use it with protected $dates, laravel doesn't know how to give it to carbon the way postgres returns the extra timezone data.
See the carbon docs for other things you can do with the $action_at instance of \Carbon\Carbon, such as making sure the date is not too far in the future or too far in the past. https://carbon.nesbot.com/docs/

Set the value in the model so that when inserting or updating automatically added to the database in laravel?

In the database I have columns: id, name, order, createdAt, updatedAt, createdBy, updateBy .
In controller : PostController.php
public function store(Request $request)
{
$req = Validator::make($request->all(), [
'name' => 'required',
'order' => 'required',
]);
if ($req->fails()) {
return response()->json(['error' => $req->errors()], 400);
}
$data = $request->all(); // name and order
Post::insert($item);
}
I want when I add data. Then createAt column and createBy column will be added. Instead of setting date('Y-m-d H:i:s) and $request->user()->id in controller, Then I want it to be placed in model, when i insert createAt and createBy columns are added. If it's update then I want the updatedAt and updatedBy columns to be added
You can add both createdAt and updatedAt in your migration file.
That will insert the current timestamp while inserting values into the table without adding them into the controller.
Please try like this while adding migration
Schema::create('table_name', function (Blueprint $table) {
$table->timestamp('createdAt');
$table->timestamp('updatedAt');
});
Instead of doing POST::insert($data); you could create/update a model more explicitly.
To add a new Post with only createdAt and createdBy you could do something like this:
$post = new Post;
$post->createdAt = $dateTime;
$post->createdBy = $userId;
$post->save();
Of course you can set any other attributes you are wanting to include before you save. And your updatedAt and updatedBy columns will have to be nullable in the database so that you don't get an error when you try to insert a record without including them.
Also as a note, Laravel has a feature that includes created_at and updated_at columns if you have: $table->timestamps(); included in your table's migration file. These fields will get automatically updated whenever a database entry is created/updated.
in your migration, you can just use the timestamps, it by default creates created_at and updated_at, and when you update an entry, Eloquent will update the value automatically for you, as for the created_by and updated_by, you can create them as well in migration, then setup an observer to set the values on create/update
ref: https://laravel.com/docs/8.x/eloquent#observers

laravel current timestamp in migration with carbon

I want to display created_at as a timestamp like this :
created_at : 1625501162
so this is my created_at column in migration:
$table->string('created_at')->Carbon::now()->timestamp;
Now I want this field to be created automatically when a new record is created and record the current time. so when i change the line to this :
$table->string('created_at')->useCurrent(Carbon::now()->timestamp);
gives me this error :
Method call is provided 1 parameters, but the method signature uses 0 parameters
so how can i fix this problem?
What other ways do you suggest for timestamp created_at and store it automatically?
If you want your column to be a timestamp you should use timestamp() instead of string(). useCurrent() doesn't take a parameter. Change
$table->string('created_at')->useCurrent(Carbon::now()->timestamp);
to
$table->timestamp('created_at')->useCurrent();
https://laravel.com/docs/8.x/migrations#column-method-timestamp
https://laravel.com/docs/8.x/migrations#column-modifiers
Edit: to always get a timestamp instead of a date you can use
protected $casts = ['created_at' => 'timestamp'];
in your Model.
Instead of string you may use timestamp() in your migration.
$table->timestamp('created_at')->useCurrent();
Also you may use casting inside model to always get expected format when receiving model.
class Something extends Model {
protected $cast = [
'created_at' => 'timestamp'
];
}
A simpler way is to configure the date format of the model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Flight extends Model
{
/**
* The storage format of the model's date columns.
*
* #var string
*/
protected $dateFormat = 'U';
}
No need to put a default value in the migration. everytime created_at, updated_at and deleted_at(if you use soft delete) is to be updated/filled, it will be in a unix timestamp format
Migration should be an integer
$table->integer('created_at')->nullable(); //you can omit this nullable
$table->integer('updated_at')->nullable(); //you can omit this nullable
// if you use softDelete trait
$table->integer('deleted_at')->nullable();
This is an example of a column createdAt. When a new record is created, it defaults to the date in UNIX format.
$table->integer('createdAt')->default(DB::raw('extract(epoch from now())'));

How does laravel/lumen dateformat 'U' actually works?

I'm not able get the timestamps with dateformat 'U' working in lumen.
In migration:
$table->timestamps();
In Model:
protected $dateFormat = 'U';
protected $dates = [
'created_at',
'updated_at',
'deleted_at'
];
public function getDateFormat()
{
return 'U';
}
Insert row from controller:
$model = new ApiKey;
$model->random= rand();
$model->name = $name;
$model->scope = $scope;
$model->save();
It does insert the row in the database but with 0000-00-00 00:00:00 values for created_at and updated_at columns.
Also, while retrieving a model via toArray or toJson it thrown exception:
I want lumen to autoupdate the timestamps and retrive timestamps as unixtimestamp format i.e. number of seconds from 1st Jan 1970.
Also, $table->timestamps() didn't create deleted_at column. What do I need to do get this column created via laravel.
Is there any other option than $table->timestamp('deleted_at');?
I've found a solution bay changing timestamps columns to int. But I want the things to be done in laravel way.
Unix timestamps are integers, not compatible with SQL datetime/timestamp fields. If you want to use unix timestamps, use integer field types for storage.
The timestamps() method only creates created_at and updated_at, soft deletes are not enabled by default. This method should not be used if you want integer storage.
If you only want to change the output format when serializing data, use casting:
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'created_at' => 'datetime:U',
];
This is likely caused by the fact that Laravel/Lumen created the date/time columns as the type timestamp not int so you're trying to save wrong type of data in the field, causing the 0000-00-00 00:00:00.
This would also cause the carbon issue as you are trying to createFromFormat with the wrong format compared to the content.
You can use $table->integer('deleted_at'); in your migration to create a deleted_at column.
TL;DR:
Manually create your date time columns with $table->integer('updated_at').
<?php
namespace App\Traits;
use Illuminate\Support\Carbon;
trait sqlServerDateFormat
{
public function fromDateTime($value)
{
return Carbon::parse(parent::fromDateTime($value))->format('d-m-Y H:i:s');
}
}

Return Eloquent model with different name from database tables

I want to return a JSON of an Eloquent model, but I'd like to change the array keys. By default they are set as the table field names, but I want to change them.
For example if I have a users table with two fields : id and user_name
When I return User::all(); I'll have a JSON with "[{"id" => 1, "user_name" => "bob}] etc.
I'd like to be able to change user_name to username. I haven't found the way to do it without an ugly foreach loop on the model.
I'm not sure why you would want to do this in the first place and would warn you first about the structure if your app/would it be better to make things uniform throughout.. but if you really want to do it.. you could do:
$user = User::find($id);
return Response::json(array('id' => $user->id, 'username' => $user->user_name));
That will return a JSON object with what you want.
You can also change the name of the key with:
$arr[$newkey] = $arr[$oldkey];
unset($arr[$oldkey]);
Just have a look at robclancy's presenter package, this ServiceProvider handles those things you want to achieve.
GITHUB LINK
Just set the $hidden static for you model to the keys you want to hide:
class User extends Eloquent
{
public static $hidden = 'id';
}
and name them the way you like with get and set functons.

Resources