Laravel firstOrCreate without Eloquent - laravel

Eloquent has a firstOrCreate method which gets a model based on a condition, or creates it if it doesn't exist.
Is there any equivalent method in Laravel's query builder (i.e. NOT in Eloquent)? For example:
$row = DB::table('users')->where('user_id', 5)->firstOrCreate('name' => 'Peter', 'last_name' => 'Pan');
That would try to get a row from users with 'user_id'==5. If it doesn't exist, it would insert a row with that id number, plus the other mentioned fields.
EDIT: I'm not trying to apply my question with users. I used users as an example to make as clear as possible what I'm looking for.

updateOrInsert function with empty values give me the result like firstOrCreate

Nope, Laravel firstOrCreate is function, that says next:
public function firstOrCreate(array $attributes, array $values = [])
{
if (! is_null($instance = $this->where($attributes)->first())) {
return $instance;
}
return tap($this->newModelInstance($attributes + $values), function ($instance) {
$instance->save();
});
}
But you can add it with query micro:
DB::query()->macro('firstOrCreate', function (array $attributes, array $values = [])
{
if ($record = $this->first()) {
// return model instance
}
// create model instance
});
So than you will be able to call it same way you do with Eloquent.
$record= DB::table('records')->where('alias', $alias)->firstOrFail();

Yeah of course! Just use normal SQL and ->selectRaw( your conditions ) and look for if there is a entry where your specifications are.
https://laravel.com/docs/5.7/queries#raw-expressions

Related

use indirect relation when intermediate model is empty

i have made indirect relation from one model to another in couple of my models.
this is my Work Model:
public function GeoEntities()
{
return $this->hasMany(\App\GeoEntity::class);
}
public function geoLand()
{
$builder = $this->GeoEntities()->where("entity_type", 0);
$relation = new HasOne($builder->getQuery(), $this, 'work_id', 'id');
return $relation;
}
public function geoLandPoints()
{
return $this->geoLand->geoPoints();
}
this return $this->intermediateModel->FinalModel(); would work, if intermediate relation is belongsTo() and returns a relation instance.
but in this case, when geoLand is Empty it produce error:
Call to a member function geoPoints() on null
like below line:
$points = $work->geoLandPoints;
The Intermediate Relation is a hasMany
i want to have this like relation call geoLandPoints and not geoLandPoints() but,
when intermidate models are null, i want an empty relation.
but i can not figure it out, how to achieve this.
with Fico7489\Laravel\EloquentJoin\Traits\EloquentJoin
using Fico7489\Laravel\EloquentJoin\Traits\EloquentJoin package, i have tried to refactor relation like below:
public function geoLandPoints()
{
$builder = $this
->select("works.*")
->join("geo_entities", "works.id", "geo_entities.work_id")
->join("geo_points", "geo_entities.id", "geo_points.geo_entity_id")
->where("entity_type", 0)
->where("works.id", $this->id);
return new HasMany($builder->getQuery(), $this, "work_id", "id");
}
but it couldn't convert Database Query Builder to Eloquent Query Builder.
Argument 1 passed to
Illuminate\Database\Eloquent\Relations\HasOneOrMany::__construct()
must be an instance of Illuminate\Database\Eloquent\Builder, instance
of Illuminate\Database\Query\Builder given
Why don't you use the hasOne() method instead of trying to return your own HasOne class? Also, you can use withDefault() so the relationship returns an empty GeoEntity instead of null.
public function geoLand()
{
return $this->hasOne(\App\GeoEntity::class)->where("entity_type", 0)->withDefault();
}
You could even pass an array of default values. withDefault(['column' => 'value', 'column2' => 'value2', ...])

How can I use laravel db query ->update() method in if statement

I want to check something in if, and if that condition is true I want to update the record that was fetched before.
$resultQuery = DB::table('cards')->where('api_id', $card->id)->first();
if (this condition will pass I want to update this record) {
$resultQuery->update(array('price_usd' => $card->prices->usd));
}
When I use the ->update() like this, I get an error:
Call to undefined method stdClass::update();
How can I do this ?
The first() function on laravel query builder returns a stdClass meaning Standard Class.
There is no function called update() in stdClass in php. You have called update() on stdClass, and that causes the error.
There are several ways to achieve your goal.
Use Laravel query builder update() function.
$resultQuery = DB::table('cards')->where('api_id', $card->id)->first();
if (your_condition) {
Db::table('cards')
->where('api_id', $card->id)
->update([
'price_usd' => $card->prices->usd
]);
}
If you don't want to fetch the card data, don't call first()
$resultQuery = DB::table('cards')->where('api_id', $card->id);
if (your_condition) {
$resultQuery
->update([
'price_usd' => $card->prices->usd
]);
}
Use Eloquent models (Laravel's preferred way)
Create an Eloquent model for Cards (if you have not done already).
public class Card extends Model
{
}
Use eloquent query builder to fetch data. And use model update() function to update data.
$resultingCard = Card::where('api_id', $card->id)->first();
if (your_condition) {
$resultingCard->update([
'price_usd' => $card->prices->usd,
]);
}
If you're using model
You can add in card controller
$card = Card::where('api_id', $card->id)->first();
if (someConditional)
{
// Use card properties, number is a example.
$card->number = 10
// This line update this card.
$card->save();
}
You can learn more about eloquent here.
Something like this:
$resultQuery = DB::table('cards')->where('api_id', $card->id);
if ($resultQuery->count()) {
$object = $resultQuery->first();
$object->price_usd = $card->prices->usd;
$object->save();
}
Or look for an alternative solutions here: Eloquent ->first() if ->exists()

Laravel Nova Metrics Partition belongsToMany relationship

I have the following data model:
(Publication) <-[belongsToMany]-> (Subscriber)
I want to create a Nova Partition Metric to display the number of Subscribers for each Publication.
The calculate method of my Partition class looks like this:
public function calculate(Request $request)
{
return $this->count($request, Subscriber::with('publications'), 'publication.id');
}
But I am getting an "unknown column" error. Anyone know how to make this work?
You could do something like this:
public function calculate(Request $request)
{
$subscribers = Subscriber::withCount('publications')->get();
return $this->result(
$subscribers->flatMap(function ($subscriber) {
return [
$subscriber->name => $subscriber->publications_count
];
})->toArray()
);
}
The count helper only allows to group by a column on model's table. It also don't allow to join tables.
If you want a more complex query, with a join and a group by column in another table, you can build your own array of results and return it with the results helper.
You can see the results helper docs here: https://nova.laravel.com/docs/1.0/metrics/defining-metrics.html#customizing-partition-colors
You should create your array (you can use eloquent or query builder here) inside the calculate function, then return that array with the results helper.
Hope this helps!
You can make the groupBy on publication_foreign_key in Subscriber table and edit the publication_foreign_key to publication_name using ->label() method
Like this
public function calculate(Request $request)
{
return $this->count($request, Subscriber::class, 'publication_id')
->label(function($publicationId)
{
switch($publicationId)
{
case publication_foreign_key_1 : return publication_name_1;
break;
case publication_foreign_key_2 : return publication_name_2;
break;
default: return 'Others';
}
});
}

How to add data to additional column in pivot table in laravel

I'm trying to build an app in Laravel 5.3, I want to add additional column data in the pivot table. Following is my code:
My Users model:
public function relations()
{
return $this->belongsToMany('App\Plan')->withPivot('child');
}
My Plan model:
public function relations()
{
return $this->belongsToMany('App\User')->withPivot('child');
}
In my controller I'm fetching the user data from Auth::user(); and for plans and child element I'm getting through request. I want to store this to my pivot table. Following is the code which I tried in my controller:
$user = \Auth::user();
$plan_id = $request->plan_id;
$childid = $request->child_id;
$plan = App\Plan::find($plan_id);
$user->relations()->attach($plan, ['child' => $childid]);
Help me out in this.
You should use attach() like this:
$user->relations()->attach($plan_id, ['child' => $childid]);
Try the save method as:
$user->relations()->save($plan, ['child' => $childid]);
Docs
Both save and attach work. Just that attach will return null while save will return $user object when I try with tinker

Returning mysql_insert_id equivalent from Laravel's fluent query builder

I am using Laravel's fluent query builder to insert a row into a table and want to get the newly inserted row's id. For instance, I would normally do something like:
public static function next_id() {
$con = self::getInstance();
return (int)mysqli_insert_id($con);
}
Is there a simple solution?
Ok, just flicked through \laravel\database\query.php and on line 820, there is a function called insert_get_id($values, $column = 'id') where the second parameter appears to return any column, but id by default!
yup it's on the doc http://laravel.com/docs/database/fluent - inserting record part
$id = DB::table('table_name')->insertGetId(
array('email' => 'john#example.com', 'votes' => 0)); return $id;

Resources