How to delete the first row - laravel

I have some trouble with Laravel SQL builder. I want to delete the first row. I am using the below code:
DB::table('ahah')->first()->delete().
In the controller, I've already imported DB class using the statement use Illuminate\Support\Facades\DB. Can you tell me what's the problem and how to fix it?

It doesn't work because DB::table('ahah')->first() is returning a stdClass object. And of course, stdClass has no delete() method.
So you will need to get the first item of your table with SQL statements:
// Supposing your primary key column is called 'id'
DB::table('ahah')
->orderBy('id')
->limit(1)
->delete();

If are working in Laravel then it's better to use Eloquent ORM by creating Model.
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
// Code Stuff
}
fetch the first records and delete
$user = \App\Models\User::orderBy('id')->first()->delete();

ModelName: Change with your model
$item = ModelName::orderBy('id', 'ASC')->first();
$item->delete();

Use the oldest method for getting the first record:
$ahah_first = \DB::table('ahah')->oldest()->first();
\DB::table('ahah')->where('id', $ahah_first->id)->delete();

As others answered, your requirement should be fulfilled as you described in your question.
I'm just adding a cleaner technique to delete the FIRST row of the table. Create the model (made using Eloquent), then add a scope method which will return the first row of the table and then you just need to call delete() on the query builder.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class FooBarModel extends Model
{
protected $table = 'foo_bar';
/**
* Scope a query to retrieve first row.
*
* #param \Illuminate\Database\Eloquent\Builder $query
* #return \Illuminate\Database\Eloquent\Builder
*/
public function scopeFirstRow($query)
{
return $query->orderBy('id')->first(); // Assuming id is the name of primary key column in the table
}
}
Then you may delete the first row as:
FooBarModel::firstRow()->delete(); // This will delete the very first available row every time it is called
However, handling the exceptions is always a good practice. Here if no row exists in the table, then calling the above statement will raise an exception as the query builder object will return null. So better first check if the result is not null then only call delete() method.
$firstRow = FooBarModel::firstRow();
if (!is_null($firstRow)) {
$firstRow->delete();
}
Similarly, you can create other scopes as well to delete the last row, last to the last row, etc.
If you want to go for a more cleaner way than this then you can just write a method in the Model itself and write all code to delete there.
/**
* #return bool
*/
public static function deleteFirstRow()
{
$firstRow = self::firstRow();
if (!is_null($firstRow)) {
$firstRow->delete();
return true;
}
return false;
}
Then call deleteFirstRow() to delete first row.
FooBarModel::deleteFirstRow();
Hope this helps.

Related

Laravel Mutator to add predefined values into database

I'm new into Laravel and I'm trying to store the user's company id on a column of the products table each time a user creates a new product. The company's id it's retrieved from the user's session. I'm trying it with Laravel's Mutator:
public function setFirstNameAttribute($value) {
$this->attributes['company_id'] = session()->get('company.id');
}
But each time I create a new Product the company id stored it's null. Seems like the function it's never executing. Is there any other resource to perform actions like this?
You must use model events - this will be executed on model creation before saving. Or you can use another events depends on you logic - see docs.
class YourModel extends Model
{
/**
* The "booted" method of the model.
*
* #return void
*/
protected static function booted()
{
static::creating(function (YourModel $model) {
$model->company_id = session()->get('company.id');
});
}
}
Mutators only works when you change mutating field directly:
$model->first_name = 'new_name'
And with your code - you will lost "new_name".
I noticed that the function name is incorrect, since the accessors use "studly" cased name of the column you wish to access, it may be as simple as to change
public function setFirstNameAttribute($value)
to
public function setCompanyIdAttribute($value)

Laravel - How to query a relationship on a pivot table

My Setup
I have a many-to-many relationship setup and working with my database. This is using a pivot table that has an extra column named "linked_by". The idea of this is that I can track the user that created the link between the other 2 tables.
Below is an attempted visual representation:
permissions -> permissions_roles -> roles
permissions_roles -> persons
The Issue
The permissions_roles table has an addition column names "linked_by" and I can use the ->pivot method to get the value of this column. The issue is that it only returns the exact column value. I have defined a foreign key constraint for this linked to persons.id but I can't manage to work out a way to query this from a laravel Eloquent model.
The Question
How do I query the name of the person linked to the "linked_by" column form the Eloquent query?
Ideally, I would like the query to be something like:
permissions::find(1)->roles->first()->pivot->linked_by->name;
BUT, as I haven't defined an eloquent relationship for this pivot table column I can't do this but I can't work out how I would do this if it is even possible?
Is the only way to do this to do:
$linkee = permissions::find(1)->roles->first()->pivot->linked_by;
$person = person::find($linkee);
$person->name;
->using();
I have discovered that Laravel has a way to do what I wanted out of the box by creating a model for the pivot table.
This works by adding ->using() to the return $this->belongsToMany() model function.
By putting the name of the newly created pivot model inside the ->using() method, we can then call any of the functions inside this pivot model just like any other eloquent call.
So assuming that my permissions belongs to many roles and the pivot table has a 3rd column named "linked_by" (which is a foreign key of a user in the Users table):
My permissions model would have:
public function roles()
{
return $this->belongsToMany('App\roles','permissions_roles','permissions_id','roles_id')
->using('App\link')
->withPivot('linked_by');
}
and the new link model would contain:
Notice the extends pivot and NOT model
use Illuminate\Database\Eloquent\Relations\Pivot;
class link extends Pivot
{
//
protected $table = 'permissions_roles';
public function linkedBy()
{
return $this->belongsTo('App\users', 'linked_by');
}
}
Obviously you would need to define the opposite side of the belongsToMany relationship in the roles model, but once this is done I can use the following to pull the name of the person that is linked to the first role in the linked_by column:
permissions::find(1)->roles->first()->pivot->linked_by->name;
You should be able to achieve that in toArray method in Permission model.
/**
* Convert the model instance to an array.
*
* #return array
*/
public function toArray(): array
{
$attributes = $this->attributesToArray();
$attributes = array_merge($attributes, $this->relationsToArray());
// Detect if there is a pivot value and return that as the default value
if (isset($attributes['pivot']['linked_by']) && is_int($attributes['pivot']['linked_by'])) {
$linkeeId = $attributes['pivot']['linked_by'];
$attributes['pivot']['linkee'] = Person::find($linkeeId)->toArray();
//unset($attributes['pivot']['linked_by']);
}
return $attributes;
}

How to create a universal getter/mutator for datetimes in Laravel?

I have created one and I thought it works:
<?php
namespace App\Traits;
use Carbon\Carbon;
trait FormatDates
{
public function setAttribute($key, $value)
{
parent::setAttribute($key, $value);
if (strtotime($value))
$this->attributes[$key] = Carbon::parse($value);
}
}
But there is a problem when calling related models. For example if you have an Article and Tag model and you want to get all tags like this:
$article->tags
it returns null because of that getter mutator.
How to fix this?
update 17.11.2017
I have found a solution to my problem. The best way to present the date in locale is to use this function:
\Carbon\Carbon::setToStringFormat("d.m.Y H:i");
simply create a service provider or a middleware and it will show all $dates in format you want. There is no need to make a getter.
Based from this: https://laravel.com/api/5.5/Illuminate/Database/Eloquent/Concerns/HasAttributes.html#method_getAttribute
The description says:
Get a plain attribute (not a relationship).
Luckily there are another two methods below it called getRelationValue and getRelationshipFromMethod, and it reads:
Get a relationship.
Get a relationship value from a method.
respectively.
And in your example, it looks like you're calling a relation.
I think you should consider it when doing your universal getter/mutator.
UPDATE:
If you inspect the code, the getAttribute also calls the getRelationValue method. But it is the last resort of the function; if the key is neither an attribute or has a mutator or is a method of the class.
Here is the stub: https://github.com/laravel/framework/blob/5.5/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php#L302
/**
* Get an attribute from the model.
*
* #param string $key
* #return mixed
*/
public function getAttribute($key)
{
if (! $key) {
return;
}
// If the attribute exists in the attribute array or has a "get" mutator we will
// get the attribute's value. Otherwise, we will proceed as if the developers
// are asking for a relationship's value. This covers both types of values.
if (array_key_exists($key, $this->attributes) ||
$this->hasGetMutator($key)) {
return $this->getAttributeValue($key);
}
// Here we will determine if the model base class itself contains this given key
// since we don't want to treat any of those methods as relationships because
// they are all intended as helper methods and none of these are relations.
if (method_exists(self::class, $key)) {
return;
}
return $this->getRelationValue($key);
}
ANOTHER UPDATE
Since you've changed your question:
You can just put the attribute name to $casts or $dates array (in your Model) so Laravel will automatically transform it into a Carbon instance when accessing it, like this:
class Article extends Model {
...
protected $dates = ['some_date_attribute`];
or with $casts
...
protected $casts = ['some_date_attributes' => 'date'];
You really can avoid this, it's already there!
on the model Class you can do:
protected $dates = ['nameOfTheDateOrTimestampTypeField','nameOfAnotherOne'];

Laravel 5 model deleting event ignoring attributes when soft deleting

Something I find puzzling in Laravel 5 is how it handles the the deleting event and any changed attributes. Basically a soft delete is just an update of the deleted_at column on the table. I was trying to be clever and also include the user ID of the user making the delete. Problem is the deleting method ignores the changed attributes when passing them to the query builder.
Take this model for example.
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model {
use SoftDeletes;
protected $table = 'users';
protected $fillable = [
'user_name', 'created_at', 'created_by', 'updated_at', 'updated_by', 'deleted_at'
];
public static function boot() {
parent::boot();
// This works and updates my updated_by column
User::updating(function($user) {
$user->updated_by = 1;
});
// This is being ignored and does not update the updated_by column
User::deleting(function($user) {
$user->updated_by = 1;
});
}
}
I have traced the create, update and delete model methods. In every case my event listeners are being picked up and processed.
In the create and update save method though, there is a difference. Both of these methods call the getDirty() method which looks for changed attributes and passes the array to the query builder. This is why that insert or update event works.
The delete method however does not do this check and therefore does not pass those attributes to the builder. Although if you look at the stack during the entire oprtation, $this->model['attributes'] has my changed updated_at attribute! The builder just never uses it.
So I guess my question without re-writing the source how would you go about injecting an attribute into the delete method when using soft deletes. Like in my model example.
The end goal here is to update the updated_by field while doing a soft delete. I am trying to avoid first doing an update of the table then doing a delete.
Just override the method runSoftDelete inside your model
class User extends Model
{
protected function runSoftDelete()
{
$query = $this->newQuery()->where($this->getKeyName(), $this->getKey());
$this->{$this->getDeletedAtColumn()} = $time = $this->freshTimestamp();
$query->update(array($this->getDeletedAtColumn() => $this->fromDateTime($time), 'updated_by' => 1));
}
}
I think the problem is the updating event calls the save() function after the event, so any changes you do will be included in the save() call.
The delete event probably does not call the same save() function - so your changes are being lost.
Try to force the save yourself and see if that works?
User::deleting(function($user) {
$user->updated_by = 1;
$user->save();
});

How to return database table name in Laravel

Is there a way that I can get the current database table in use by the model that I'm in? I see that there is a table() function in Laravel/Database/Eloquent/model.php but I've been unsuccessful calling it calling it from the model that I'm in.
There is a public getTable() method defined in Eloquent\Model so you should be able to use $model->getTable().
Taylor has an answer to your question:
Within the model class you can do something like this:
return with(new static)->getTable();
If you want all your models to have the ability to return table name statically, then so something like this:
class BaseModel extends Eloquent {
public static function getTableName()
{
return with(new static)->getTable();
}
}
class User extends BaseModel {
}
User::getTableName();
Edit April 2019: This answer is now out of date. See the new correct answer by Flyn San
Yes - Eloquent has a $table variable. There are two ways you can access this:
class yourModel extends Eloquent {
public static $table = "differentTable";
function someFunction()
{
return yourModel::$table;
}
}
or
class yourModel extends Eloquent {
public function someFunction()
{
return $this->table();
}
}
then in your code
Route::get('/', function () {
$model = new yourModel();
dd($model->someFunction());
});
In my case, i'm using laravel 5.4
return (new static)->getTable();
Since table is a protected property in the Model class (Laravel >= 5) you will need an instance of your Model.
Here is a case example:
DB::table( (new YourModelClassname)->getTable() )
->update(['field' => false]);
You can get name of a model's table by following code:
If we have a Model as ModelName:
ModelName::query()->getQuery()->from
This method also works fine in case of custom table name that are defined by protected $table = 'custom_table_name' in the Model.
It will return the table name from the model. perfectly worked on laravel 8
app(Modelname::class)->getTable()
you have to replace Modelname with your model class
Based on Lucky Soni answer, there is another easy trick if you want to directly call it from Vontroller or View.
Tested in Laravel 6, and I keep using it, if you are "One Line Programmer" who hates extra line instance declaration. No need for extra lines in Model file too.
$string_table_name = with(new \App\Model\TableModelName)->getTable();
or better you may also be able to just call this
$string_table_name = (new \App\Model\TableModelName)->getTable();
It will return plain string of the tabel name even if you rename $table variable inside model class.
EDIT :
Minus Rep ?? Maybe you should try this first in your controller instead making new function in model class just to get table name and no need to declare the object when calling.
with() itself is Laravel helper function that returns an object of the class. and inside class that extends Model, already has function getTable(). So, you don't have to put another new redundant function inside model class.
It seems the latest version, you can just call (new Class) without with() function.
The difference between this answer and Lucky's answer, mine doesn't make any new function inside Model class to get the table name, even you can just call the function inside the Controller and View without declaring the object of model class. It's for beautify the code.
While Lucky's answer create new function that inside Model class, and you need to call the function from the object.
Simple way to get table name from Laravel Model by this:
$tableName = app(\App\User::class)->getTable();
Don't forget to replace:
\App\User
With Model path.
Here's an other approach so that you can get a model's table name statically.
Define a Trait: app/Traits/CanGetTableNameStatically.php
<?php namespace App\Traits;
trait CanGetTableNameStatically
{
public static function tableName()
{
return (new static)->getTable();
}
}
Extend your required Model or BaseModel with the use statement.
app/Models/BaseModel.php
<?php namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Traits\CanGetTableNameStatically;
class BaseModel extends Model
{
use CanGetTableNameStatically;
// ...
}
On your models, if you set the custom table name on Laravel's reserved attribute: protected $table then it will still work & return correct table name.
app/Models/Customer.php
<?php namespace App\Models\Master;
use App\Models\BaseModel;
class Customer extends BaseModel
{
protected $table = 'my_customers';
// ...
}
Usage: just call YourModel::tableName() anywhere.
In Views:
{{ \App\Models\Customer::tableName() }}
When doing Joins:
DB::table( Product::tableName() . ' AS p' )
->leftJoin( ProductCategory::tableName() . ' AS pc', 'pc.id', '=', 'p.category_id')
// ... etc
Note:
I use this approach where needed but full disclosure, I found another answer here that have the exact same approach, so I copy pasted here for reference of course with citation thanks to #topher
Based on tailor Otwell's answer you could use something like this:
with(new Model)->getTable();
Note: tested on versions 5.x, 6.x, 7.x, 8.x and it works well.
another solution is to use the resolve helper like so:
resolve('\\App\\Models\\User')->getTable()
None of the answers so far will get you the table name with the prefix, if you are using a table name prefix. At this time it seems like we need to concatenate the prefix with the table name ourselves if we want the real name of database table.
Here's how to get the table name including the table prefix:
echo \App\MyModel::query()->getQuery()->getGrammar()->getTablePrefix() . app(\App\MyModel::class)->getTable();
in laravel 7.x (i'm used)
you can get table name with (new Target())->getTable();
$query->where('parent_id', function ($query) use ($request) {
$query->select('id')->from((new Target())->getTable())->where('unit_id', $request->unit_id);
});
hope it's helps
To people who want to get table name from a Builder object instead of other object, here you are:
$conn = DB::connection("my_private_mysql_conn");
$my_builder_object = $conn->table("my_table_name");
//This will print out the table name
print $my_builder_object->from;
It will work 100%. You will get table name.
$object = new OrderStockProduct();
// Use below line only when you have dynamic connection in laravel project
// $object->setConnection('mysql');
$object = $object->getTable();
dd($object);
I just wanted to add the following for people coming from search engines:
In case you do not even want to instantiate the Model at all (faster?) :
$model = 'App\User';
$modelTable = str_replace('\\', '', Str::snake(Str::plural(class_basename($model))));
dd($modelTable); // will return "users"
That might look ugly but that's exactly how the getTable() method resolves it under the hood, so...
You will need to use Illuminate\Support\Str; on top of your file.
Addendum: implying you follow the framework's standards (i.e: Post model has posts table, User model has users table, etc)
In Laravel 4 use static method
$table_name = Model::getTable();
or "self" inside Eloquent Model
$table_name = self::getTable();

Resources