I have a model of Posts with status column. I wonder, what would be be practice in Laravel to retrieve from something like 0 or 1(stored integers in DB) and instead of that show "displayed" or "hidden"? Not inside of the blade temples but when doing something like:
return response()->json(['posts' => $posts])
"status" of $posts would be not "0" but "displayed"?
You can make it in Posts Model:
const displayed = 1;
const hidden = 0;
public static function status()
{
return [
self::displayed => 'displayed',
self::hidden => 'hidden',
];
}
And retrieve it.
$post = [
"status" => Posts::status()[$request->status]
];
Related
On my project, Picture model has some "one to many" relations to create featured images. Those relations:
public function featuredByPosts()
{
return $this->hasMany('App\Post', 'featured_image_id');
}
public function featuredByProduct()
{
return $this->hasMany('App\Products', 'featured_image_id');
}
public function featuredByPages()
{
return $this->hasMany('App\Page', 'featured_image_id');
}
One of the inverse relations is like so:
public function featured_image()
{
return $this->belongsTo('App\Picture', 'featured_image_id');
}
When I get the pictures with those relations, each picture in collection has featured_by_posts, featured_by_products and featured_by_pages keys and related content as values of those keys.
What I want to do is to create a new key named "featured_by" directly in each picture in the collection and move current featured_by_* relations into new key by modifing their keys like so:
From this:
$picture = [
"id" => "1",
"name" => "someName",
"featured_by_posts" => [array of posts],
"featured_by_pages" => [array of pages]
]
To this:
$picture= [
"id" => "1",
"name" => "someName",
"featured_by" => [
"posts" => (values of featured_by_posts),
"pages" => (values of featured_by_pages)
]
]
I don't know if it can be done while getting data from database. That's why I tried to add the codes down below in index function on my API controller to produce formatted item of picture.
$relations = ["tags", "posts", "products", "featuredByPosts", "featuredByProducts", "featuredByPages"];
$pictures = Picture::with($relations)->get();
foreach ($pictures as $picture) {
$featureds = ["posts", "products", "pages"];
$key = "featured_by";
$picture[$key] = [];
foreach ($featureds as $featured) {
$oldKey = "{$key}_{$featured}";
$picture[$key][$featured] = $picture[$oldKey]; //This line produces the error
unset($picture[$oldKey]);
}
}
//ERROR: Indirect modification of overloaded element of App\Picture has no effect.
I don't understand what that means since the think. I searched this error and found some answers, but I couldn't make it work. So I hope someone can help. Thanks.
You should use the eloquent API resources:
https://laravel.com/docs/7.x/eloquent-resources
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class PictureResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'featured_by' => [
'posts' => $this->featuredByPost,
'products' => $this->featuredByProduct,
],
];
}
}
Your controller:
return new PictureResource(Picture::find(1));
I have User model which has relationships hasMany with UserPosition eloquent model:
User model
public function positions()
{
return $this->hasMany(UserPosition::class);
}
How I can use updateOrCreate method when from request come array of data positions?
Code
$positions = [
"doctor",
"developer"
];
$user->positions()->each(function($position) use ($positions, $user) {
$id = $user->id;
foreach ($positions as $name) {
$position->updateOrCreate(['user_id' => $id, 'name' => $name], [
'name' => $name
]);
}
});
Note: In this example user doesn't has any positions on the table of database
But my code not work. Why?
You are iterating on the existing positions of a user, meaning that if a user has no positions the iteration will never happen. You can iterate along the positions you need to make:
$positions = collect([
"doctor",
"developer"
]);
$positions->each(function($position) use ($user) {
$user->positions()->updateOrCreate(['name' => $position], [
'name' => $position
]);
}
});
It doesn't work because your running your updateOrCreate() method inside an each iteration which never runs because as you stated in your note "this example user doesn't has any positions on the table of database"
Here your trying to loop through your currently existing positions attached to your user model:
$user->positions()->each()
But that won't run because the user doesn't have any positions at the moment.
I'm guessing you are trying to update the the user's positions, where it is possible that the user already has one or more of those positions associated to him and you don't want to create duplicates, for that you can do this:
$positions = [
"doctor",
"developer"
];
foreach($positions as $position) {
UserPosition::firstOrCreate(['user_id' => $user->id, 'name' => $position]);
}
I am trying to return pivot data to a resource.
The pivot table works, I can add and remove entrys like expected, but I am not able to get the user_id returned in ActivityResource...
In the Laravel Documentation it looks so easy, am I missing something?
// Activity.php
class Activity extends Model
{
public function members()
{
return $this->belongsToMany('App\User', 'activity_user', 'user_id', 'activity_id')->withPivot('activity_id','user_id')->withTimestamps();
}
}
// User.php
class User extends Authenticatable
{
public function joinedactivities()
{
return $this->belongsToMany('App\Activity');
}
}
In my ActivityController I want to return a newly created ActivityResource with 'eager-loaded' relationship
// ActivityController
public function show($id)
{
$activity = Activity::with('members')->findOrFail($id);
/* foreach ($activity->members as $user) {
echo $user->id . " "; // With this I can actually see the right ids
}
return;*/
return new ActivityResource($activity);
}
ActivityResource:
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'attendees' => $this->whenPivotLoaded('activity_user', function () {
return $this->pivot->user_id;
}),
];
}
I dont get any errors instead the attendees field is just not returned. I tried so many things, struggeling with that. Help very appreciated.
I am using Laravel 6.
->withPivot('activity_id','user_id') is not needed. Those fields will appear on your relation object no matter what. For the resource, I think you can do the following:
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
// If the relation 'members' is loaded, get an array of user ids otherwise, return null
'attendees' => $this->relationLoaded('members') ? $this->members->pluck('pivot.user_id')->unique()->all() : null
];
}
The main problem is the relationship is a Many to Many, meaning there's more than 1 pivot. With this solution, your object will look like this.
{
id: 3,
title: 'A Title',
attendees: [
1,
2,
3,
],
}
If you want the ids concatenated in a single string like in your commented foreach, replace all() by join(' ')
// If the relation 'members' is loaded, get an string of user ids otherwise, return null
'attendees' => $this->relationLoaded('members') ? $this->members->pluck('pivot.user_id')->unique()->join(' ') : null
{
id: 3,
title: 'A Title',
attendees: '1 2 3',
}
I have usermodel and brandmodel. relationships of those two are as follows.
Brand Model
class BrandModel extends Eloquent
{
protected $table = 'tbdb_brand';
public function users() {
return $this->hasMany(UserModel::class,'brand_id');
}
}
User Model
class UserModel extends Eloquent
{
public function brand() {
return $this->belongsTo('TopBetta\Models\BrandModel');
}
}
When i try to get brand of user i get following output.
"Brand" => array:6 [
"id" => 1
"created_at" => "2018-06-01 07:07:41"
"updated_at" => "2018-06-01 07:07:41"
"keyword" => "sports_settings"
"name" => "TopBetta"
"description" => ""
]
what i need is above result without timestamps. how can i modify above source code to do so?
Thanks
You can achieve your result by specifying column name when you want to retrieve it. You can write something like this:
UserModel::with(['brand' => function($query) {
$query->with(['id', 'keyword', 'name', 'description']);
}]);
In Laravel 5.4, I do something more straightforward like this:
UserModel::with('brand:id,keyword,name,description');
This will include only the fields of the brand listed after :.
For the following factory definition, the column order needs to be sequential. There is already a column id that is auto-incremented. The first row's order should start at 1 and each additional row's order should be the next number (1,2,3, etc.)
$factory->define(App\AliasCommand::class, function (Faker\Generator $faker) {
return [
'user_id' => App\User::inRandomOrder()->first()->id,
'command' => $faker->word,
'content' => $faker->sentence,
'order' => (App\AliasCommand::count()) ?
App\AliasCommand::orderBy('order', 'desc')->first()->order + 1 : 1
];
});
It should be setting the order column to be 1 more than the previous row, however, it results in all rows being assigned 1.
Here's something that might work.
$factory->define(App\AliasCommand::class, function (Faker\Generator $faker) {
static $order = 1;
return [
'user_id' => App\User::inRandomOrder()->first()->id,
'command' => $faker->word,
'content' => $faker->sentence,
'order' => $order++
];
});
It just keeps a counter internal to that function.
Update:
Laravel 8 introduced new factory classes so this request becomes:
class AliasCommandFactory extends Factory {
private static $order = 1;
protected $model = AliasCommand::class;
public function definition() {
$faker = $this->faker;
return [
'user_id' => User::inRandomOrder()->first()->id,
'command' => $faker->word,
'content' => $faker->sentence,
'order' => self::$order++
];
}
}
The answer by #apokryfos is a good solution if you're sure the factory model generations will only be run in sequential order and you're not concerned with pre-existing data.
However, this can result in incorrect order values if, for example, you want to generate models to be inserted into your test database, where some records already exist.
Using a closure for the column value, we can better automate the sequential order.
$factory->define(App\AliasCommand::class, function (Faker\Generator $faker) {
return [
'user_id' => App\User::inRandomOrder()->first()->id,
'command' => $faker->word,
'content' => $faker->sentence,
'order' => function() {
$max = App\AliasCommand::max('order'); // returns 0 if no records exist.
return $max+1;
}
];
});
You almost had it right in your example, the problem is that you were running the order value execution at the time of defining the factory rather than the above code, which executes at the time the individual model is generated.
By the same principle, you should also enclose the user_id code in a closure, otherwise all of your factory generated models will have the same user ID.
To achieve true autoIncrement rather use this approach:
$__count = App\AliasCommand::count();
$__lastid = $__count ? App\AliasCommand::orderBy('order', 'desc')->first()->id : 0 ;
$factory->define(App\AliasCommand::class,
function(Faker\Generator $faker) use($__lastid){
return [
'user_id' => App\User::inRandomOrder()->first()->id,
'command' => $faker->word,
'content' => $faker->sentence,
'order' => $faker->unique()->numberBetween($min=$__lastid+1, $max=$__lastid+25),
/* +25 (for example here) is the number of records you want to insert
per run.
You can set this value in a config file and get it from there
for both Seeder and Factory ( i.e here ).
*/
];
});
In Laravel 9 (and possibly some earlier versions?), there's a pretty clean way to make this happen when you're creating models (from the docs):
$users = User::factory()
->count(10)
->sequence(fn ($sequence) => ['order' => $sequence->index])
->create();
If you'd like to start with 1 instead of 0:
$users = User::factory()
->count(10)
->sequence(fn ($sequence) => ['order' => $sequence->index + 1])
->create();
The solution also solves already data on table conditions:
class UserFactory extends Factory
{
/**
* #var string
*/
protected $model = User::class;
/**
* #var int
*/
protected static int $id = 0;
/**
* #return array
*/
public function definition()
{
if ( self::$id == 0 ) {
self::$id = User::query()->max("id") ?? 0;
// Initialize the id from database if exists.
// If conditions is necessary otherwise it would return same max id.
}
self::$id++;
return [
"id" => self::$id,
"email" => $this->faker->email,
];
}
}