Return a Boolean instead of the whole collection - laravel

The Stack model can have "user progress", users can "clear" stacks. And that progress is stored in the Progress model.
Progress model:
public function stack(){
return $this->belongsTo(Stack::class);
}
It would be neat if it was possible to fetch all stacks, and if the user has "cleared" it or not, with a boolean true or false. I don't won't to fetch all data corresponding to the progress. So I have tried setting up a "finished" relation on the Stack model
public function finished(){
return $this->hasOne(Progress::class) ? true : false;
}
But this setup gives me the following error
Call to a member function addEagerConstraints() on boolean.
This is how I call the relationship at the moment
$user = \App\Stack::with(['finished' => function($q){
return $q->where('user_id', auth()->user()->id);
}])->get();
But that returns the whole collection, and that is not necessary. The expected result should be like:
{
"id": 5,
"user_id": 2,
"subject_id": 2,
"name": "tstar igen",
"slug": "tstar-igen",
"description": "asdasd",
"image": null,
"created_at": "2017-10-06 08:27:36",
"updated_at": "2017-10-06 08:27:36",
"finished": true/false
},
So lets say that here is an relation entry in in the progress table for the stack above.
+----+---------+----------+
| id | user_id | stack_id |
+----+---------+----------+
| 1 | 1 | 5 |
+----+---------+----------+
So when fetching the stacks, with relation finish. The finished column should be true or false. So the return from Stack, with relation finished should be like the following. Notice the finished column changed to false on the last stack, because the relation is not present in the progress table.
{
"id": 5,
"user_id": 2,
"subject_id": 2,
"name": "tstar igen",
"slug": "tstar-igen",
"description": "asdasd",
"image": null,
"created_at": "2017-10-06 08:27:36",
"updated_at": "2017-10-06 08:27:36",
"finished": true
},
{
"id": 6,
"user_id": 2,
"subject_id": 2,
"name": "another stack",
"slug": "another-stack",
"description": "This is a test stack for all the stacks out there",
"image": null,
"created_at": "2017-10-06 08:27:36",
"updated_at": "2017-10-06 08:27:36",
"finished": false
},

You can try withCount that counts your related models. But it will return number of related models not boolean. Here is an example:
Stack.php
public function progress(){
return $this->hasOne(Progress::class);
}
then:
\App\Stack::withCount('progress')->get();
Now results have count_progress attribute with number of related 'Progress' models. Because your relation is hasOne it should be 0 or 1.

You are almost done, You have your relationship setup well except for the boolean stuffs, remove it:
public function finished(){
return $this->hasOne(Progress::class);
}
Then when you need to check you can use has or whereHas relationship method:
$stack = \App\Stack::whereHas('finished', function($q){
return $q->where('user_id', auth()->user()->id);
})->get();
Based on your need thats the best I could conceive. I think this should be sufficient.
It would do well to learn how has and whereHas works. But just to summarize: has simply is like whereHas except that it checks if there is at least one model related to the first model, and the other helps you to make more advanced constraints as shown in the example I gave.

Your model
public function progress(){
return $this->hasOne(Progress::class);
}
Your controller
...
$stacks->load('progress');
resource
'finished' => $this->whenLoaded('progress')->isNotEmpty()

Related

Query specific value in array from a metadata entity in Dynamics 365

I'm trying to avoid iterating through this array, but I imagine that is the only way to handle this. Just seeing if there is a way to directly query this value in the array from the Web API URI.
This is the URI example:
https://example.crm.dynamics.com/api/data/v9.0/GlobalOptionSetDefinitions(f4a9de67-1d00-ea11-a811-000d3a33f702)
And this is an example of the response:
{
"#odata.context": "https://example.crm.dynamics.com/api/data/v9.0/$metadata#GlobalOptionSetDefinitions/Microsoft.Dynamics.CRM.OptionSetMetadata/$entity",
"MetadataId": "f4a9de67-1d00-ea11-a811-000d3a33f702",
"Options": [
{
"Value": 799680006,
"Color": "#0000ff",
"IsManaged": false,
"ExternalValue": "",
"ParentValues": [],
"MetadataId": null,
"HasChanged": null,
"Label": {
"LocalizedLabels": [
{
"Label": "ABC123",
"LanguageCode": 1033,
"IsManaged": false,
"MetadataId": "b4eb2c69-b500-ea11-a811-000d3a33fe19",
"HasChanged": null
}
],
"UserLocalizedLabel": {
"Label": "ABC123",
"LanguageCode": 1033,
"IsManaged": false,
"MetadataId": "b4eb2c69-b500-ea11-a811-000d3a33fe19",
"HasChanged": null
}
}
}
]
}
Basically, I have the "Value": 799680006 which is what I want to somehow add to the URI query parameters, so that I can ultimately get "Label": "ABC123".
Any suggestions or is iterating through the array of objects with if Value = x really the only option?
Let me clarify two things:
Querying metadata like you are using GlobalOptionSetDefinitions to get all the localized labels if you have multiple language packs or for verifying customizations or for Devops deployment purpose is one thing
Getting the label for the selected picklist value in one of the transaction database record is another purpose
If you simply need for second purpose, you can get it by selecting the Formatted value, after adding a header in web api request. Read more in my SO answer
Another way to inspect the label is using stringmap entity.
https://crmdev.crm.dynamics.com/api/data/v9.1/stringmaps?$filter=objecttypecode eq 'account' and attributename eq 'accountclassificationcode' and attributevalue eq 1

How to fetch data using with via object in Laravel eloquent?

Actually, I want to fetch data using Model object not through Model facade like mention below.
$user = $this->getGuard()->user();
Above user is current logged user which is
"id": 6,
"name": "kuser",
"email": "kuser#gmail.com",
"phone": "03345154067",
"is_subscribed": 0,
"subscription_date": null
But when I try to fetch same $user object with its related model like cards, by execute $user->with(['cards'])->first(); than it gives first record of user table with cards like mentioned below.
"id": 1,
"name": "admin",
"email": "admin#gmail.com",
"phone": "03056494616",
"is_subscribed": 1,
"subscription_date": "2019-10-08",
"cards": []
Above mentioned record which is user object. It is first record of my user table.
Actually, I am expecting.
"id": 6,
"name": "kuser",
"email": "kuser#gmail.com",
"phone": "03345154067",
"is_subscribed": 0,
"subscription_date": null
with its related model cards like
"id": 6,
"name": "kuser",
"email": "kuser#gmail.com",
"phone": "03345154067",
"is_subscribed": 0,
"subscription_date": null
"cards":[] // array of cards those belongs to it.
You can use Lazy Eager Loading, you don't have to query for the user again, you already have it:
$user = $this->getGuard()->user();
$user->load('cards');
Laravel 6 Docs - Eloquent - Relationships - Lazy Eager Loading
Use a simple where ?
$user->where('id', Auth::id())->with(['cards'])->first();
won't that work?
Here is another way
User::with(['cards'])->find($user->id);

How should I use redis?

I'm doing an api in laravel and I want to use Redis. I'm not sure if I'm doing well.
How should I use Redis to store json and then get a value by ID or another column.
Should I save the json as plain text? Then how do I go through it to look for a specific value or how you should keep the values?
{
"id": 1,
"name": "Package A",
"dimensions": "100x100x100",
"created_at": "2019-05-29 01:35:53",
"updated_at": "2019-05-29 01:35:53"
},
{
"id": 2,
"name": "Package B",
"dimensions": "150x150x150",
"created_at": "2019-05-29 01:36:53",
"updated_at": "2019-05-29 01:36:53"
}
$package = Package::where->get();
Redis::hmset('packages', array($package));
Or I shoud ..
$package = Package::where->get();
Redis::set('packages', serialize($package));
Then How I get a value?
For example: all fields id=2
I recommend saving the information in the following way, so it is easier to access later.
Package::all()->each(function($package){
Redis::set("package:{$package->id}", $package->toJson());
});
And if you need to recover information :
json_decode(Redis::get("package:$id"), true);
In redis you have to consider how to access the information, and then how to save it. For example, if you want to search by name, your key will be composed of the same name.
If you want retrive all packages from Redis, you will need all of packages key´s.
The folowing command retrive all keys matches with the structure :
Redis::keys('package:*');
After that, you can do the following
$keys = Redis::keys('package:*');
$packages = [];
foreach ($keys as $key){
array_push($packages, json_decode(Redis::get($key), true));
}
return $packages;

Array with single attribute of many-to-many Eloquent relationship

I created a model NearMiss that has a many-to-many relationship with a Type model. When there is a GET request for a specific NearMiss, I want an array to be attached to the JSON output that has the name attribute of all Type instances that belong to the NearMiss instance.
I can attach an array of Types to the output, but I want to get rid of all the additional information (such as pivot information).
The GET request /nearmisses/{nearmiss} executes the following method:
public function show($id)
{
try {
$nearmiss = NearMiss::findOrFail($id)->first();
$nearmiss->types->makeHidden(['id', 'created_at', 'updated_at']);
return response()->json($nearmiss);
} catch(ModelNotFoundException $e) {
abort(400, 'Model not found');
}
}
The NearMiss model has the following types relation:
public function types()
{
return $this->belongsToMany('App\Type', 'near_miss_type', 'near_miss_id', 'type_id');
}
Current output:
{
"id": 1,
"location_long": "0.0000000",
"location_lat": "0.0000000",
"employee_id": 1,
"created_at": "2019-02-11 16:38:24",
"updated_at": "2019-02-11 16:38:24",
"types": [
{
"id": 1,
"name": "Brandgevaar"
"created_at": "2019-02-11 16:33:25",
"updated_at": "2019-02-11 16:33:25",
},
{
"id": 2,
"name": "Slipgevaar",
"created_at": "2019-02-11 16:34:12",
"updated_at": "2019-02-11 16:34:12",
}
]
}
I know that I can remove additional attributes (such as id, created_at, updated_at), but that still leaves me with an array of Type instances (with just a single name attribute). When I try flatten() I receive an error that flatten() can't be used on BelongsToMany relationships.
Desired output:
{
"id": 1,
"location_long": "0.0000000",
"location_lat": "0.0000000",
"employee_id": 1,
"created_at": "2019-02-11 16:38:24",
"updated_at": "2019-02-11 16:38:24",
"types": [
"Brandgevaar", "Slipgevaar"
]
}
Can someone help me to get the desired output please.
You could load the types manually and use the pluck() function to only get the name of each type.
$nearmiss->types = $nearmiss->types()->pluck('name');
However I'm not sure if this will interfere with the magic properties from Eloquent.

Laravel Eloquents: Check if child relationship has no data, Dont return any data

I have three entities Inbox , Document , Category
inbox has relation with document and document has many categories,
I have an Eloquent query that check relation between inbox and document and return inbox with documents data,
The Problem is:
I want to list all inbox with documents data only if document has no category (if it has one or more categories i dont want list this document with it's inboxes).
So i have this query now, that is not works correctly:
public static function getUserAndJobPositionsInbox($id, $type)
{
return self::with(['documents' => function($q){
$q->has('categories', '==', 0);
}])->where('inboxable_id', $id)
->where('inboxable_type', $type)->get();
}
This query will return inbox data with no documents if the documents has no categories
BUT i don't want inbox data if documents has no categories. just return empty
The result is :
{
"data": {
"user_inbox_documents": null,
"job_positions_documents": [
[
{
"id": 2,
"document_id": 3,
"document_reference": "RPL2p",
"inboxable_id": 3,
"inboxable_type": "App\\Models\\JobPosition",
"path_id": "2",
"created_at": "2018-09-12 13:21:23",
"updated_at": "2018-09-12 13:21:23",
"documents": []
}
],
[
{
"id": 1,
"document_id": 3,
"document_reference": "RPL2p",
"inboxable_id": 2,
"inboxable_type": "App\\Models\\JobPosition",
"path_id": "1",
"created_at": "2018-09-12 13:21:23",
"updated_at": "2018-09-12 13:21:23",
"documents": []
}
]
]
}
}
Thanks in advance.
You can check the existence of nested relationships using dot (.) for example following code (Laravel documentation) gets all the posts that have at least one comment and that comment should have atleast one vote.
// Retrieve all posts that have at least one comment with votes...
$posts = App\Post::has('comments.votes')->get();
So from above example, you can modify you code as follows:
public static function getUserAndJobPositionsInbox($id, $type)
{
return self::has('documents.categories')
->where('inboxable_id', $id)
->where('inboxable_type', $type)->get();
}

Resources