Filter laravel collection in sub collection - php

My collection is like this.
Collection {
0 => Name_Model {
"id" => 44
"name" => "The name of "
"list_angg" => Collection {
0 => Name_Model_sub {
"code" => "02"
"nameofcode" => "The name of 02"
}
1 => Name_Model_sub {
"code" => "01"
"nameofcode" => "The name of 01"
}
}
}
1 => Name_Model {
"id" => 45
"name" => "The name of thus"
"list_angg" => Collection {
0 => Name_Model_sub {
"code" => "03"
"nameofcode" => "The name of 3"
}
}
}
}
I want to filter that model by value of list_angg->code. So I try like this. Filter and foreach that list_angg->code
$jurnals = $filterCollection->filter(function($value, $key) use ($kode_fakultas){
foreach ($value->list_angg as $lists) {
$filtered = $lists->where('code', $kode_fakultas);
return $filtered;
}
return $filtered;
});
dd($jurnals);
I try use method reject() and map().
But filter didn't work as well. Is I miss something?

Hope I understood the question correctly.
To filter all elements which list_angg->code has the given value you can use a combination of filter() and contains().
$filterCollection->filter(function ($value) use ($code) {
return $value->list_angg->contains('code', $code);
});
filter() returns all values in a collection which return a truthy value.
contains() returns true or false if a collection contains a value matching the condition provided, which can be a closure, a value or a key and value.
Keep in mind contains() uses "loose" comparison, so if you need a strict match you can use containsStrict.
Your code is not filtering correctly because in the filter closure you are always returning the model instance, which evaluates to true or false based on the first element and therefore it is considered as a pass or fail based on that.
References:
https://laravel.com/docs/8.x/collections#method-contains
https://laravel.com/docs/8.x/collections#method-filter
https://laravel.com/docs/8.x/collections#method-containsstrict

you can do this by first restructuring the collection according to your requirements. For example:
public function formatCollection($collection)
{
$results = [];
foreach ($collection as $item)
{
$results[] = [
'foe' => $item['bar'],
'baz' => $item['foo']
];
}
return collect($results);
}
This will return the required json format and after that you can apply your filters to it. For Example:
$result = formatCollection($collection);
This will return the collection on which you can apply
$result->filter(function(value){
return (value === 'foo');
}
This will return the required information or models you require in your collection.

Related

Get value of dynamic sub-array, in multidimensional array

Not sure if my question is clear, but here's what I'm trying to achieve. Let’s say I have a multidimensional array like so:
$arr['client1']**['dog']['Jack']**
$arr['client2']['cat']['Stacy']
How can I get the second portion of the array (between **), knowing it can be anything. For client 3, it could be a crocodile. For Client 4, it could be a car.
So I'm looking to "build" the structure of the array, dynamically. Something like so:
$arr['client1']{partBetweenThe**InTheExemple}
{partBetweenThe**InTheExemple} would be constructed "on the fly" (hence, the dynamically).
EDIT: Hopefully some clarifications...
The array changes every time. Basically, I'm building an addon to poll any API on the web. The data structure I'm getting can be anything. So what I need to do is build the key combination "on the fly", with variables.
In the exemple above, my variable would be something like $query = ['dog']['Jack'] and to get the value, I would poll it like so (from a logistic perspective, I know this doesn't work):
$arr['client1'][$query] or $arr['client1']$query or $arr['client1']{$query}
You can define the query as an array with each level as an element. Then we can iterate through that and check if we find a matching key in the response:
function findInArray(array $query, array $data)
{
foreach ($query as $key) {
if (!array_key_exists($key, $data)) {
// The key was not found, abort and return null
return null;
}
// Since the key was found, move to next level
$data =& $data[$key];
}
return $data;
}
// Example response
$response = [
'client1' => [
'dog' => [
'Jack' => 'Some value',
],
]
];
// Define the query as an array
$query = ['dog', 'Jack'];
$result = findInArray($query, $response['client1']);
Demo: https://3v4l.org/WjXTn
Edit:
So since the array's structure can't be changed this will return the client if the structure remains ['client']['animal']['name'].
$clients = [
'client1' => [
'dog' => [
'Jack' => []
]
],
'client2' => [
'cat' => [
'Stacy' => []
]
]
];
$animal = 'dog';
$name = 'Jack';
foreach ($clients as $client => $options) {
if (
array_key_exists($animal, $options) &&
array_key_exists($name, $options[$animal])
) {
echo $client;
break;
}
}

elements in array is not working with in_array

number 3 should be in array $songsid but when i used in_array method output was null
nuder my function is dd($songsid)
public function index()
{
$songs = Song::latest()->paginate(20);
$songid = Collection::select("song_id")->where("user_id", "=", auth::user()->id)->get();
$songsid = $songid->toArray();
// dd($songsid);
if(in_array(3, $songsid))
{
dd("yes");
}
else
{
dd("no");
}
}
output of $songsid array dd($songsid)
array:2 [▼
0 => array:1 [▼
"song_id" => 3
]
1 => array:1 [▼
"song_id" => 2
]
]
$songsid is not an array of scalar values, but an array of arrays.
You could use array_column() to extract IDs from the array,
in_array(3, array_column($songsid, 'song_id')
Unless you really need to convert to array, you could use collection methods to check that out.
$songid = Collection::select("song_id")->where("user_id", "=", auth::user()->id)->get();
if ($songId->contains('song_id', 3)) ...
In your in_array method, you need an indexed array, ex : $songsid = [3,2]; You can use pluck method :
$songsid = $songid->pluck('id')->toArray();
if(in_array(3, $songsid))
{
dd("yes");
} else {
dd("no");
}
in_array() searches in the array values, that is not nesting.
You may want to use array_culumn() like
in_array(3, array_column($songsid, 'song_id')
or search for ['song_id' => 3] like
in_array(3, array_column($songsid, ['song_id' => 3])

Extract all ids from array of objects

With PHP 7.4, I have associative array with objets :
$array = [
1 => Class {
'id' => 1,
'call' => true,
},
5 => Class {
'id' => 5,
'call' => false,
},
7 => Class {
'id' => 7,
'call' => true,
},
]
I want to extract all the IDs if the call attribute === true.
After searching, I think I should use the array_map function.
$ids = array_map(function($e) {
if (true === $e->call) {
return $e->id;
}
}, $array);
// Return :
array(3) {
[1]=> 1
[5]=> NULL
[7]=> 7
}
But I have two problems with this:
I don't want NULL results
I don't wish to have the associative keys in in my new array. I want a new array ([0=>1, 1=>7])
I know I can do it with a foreach() but I find it interesting to do it with a single PHP function (array_walk or array_map ?)
Create an array which is the call value indexed by the id and then filter it. As the id is the index, then extract the keys for the ids...
$ids = array_keys(array_filter(array_column($array, "call", "id")));
print_r($ids));
Array
(
[0] => 1
[1] => 7
)
Although I think a foreach() is a much more straight forward method.
You probably want array_filter to filter out what you don't want, then you can extract the id:
$ids = array_column(array_filter($array, function($e) {
return $e->call === true;
}), 'id');
You can reduce the array with a callback that conditionally adds each item's id to the "carry" array.
$ids = array_reduce($array, fn($c, $i) => $i->call ? [...$c, $i->id] : $c, []);

Laravel convert database integer to string

I am using Laravel 5.5 & have Items table with more than 50 columns set as Tinynt to store values.
Item::where('id',$id)->first();
Now in my view I want to replace all integer values to corresponding String like
if($item->column1 == 1) { $value = 'String1'); }
if($item->column1 == 2) { $valuee = 'String2'); }
& so on. I know I can use Laravel Mutator but I have more than 50 columns & settings Mutator will not solve my issue. My problem is some related to this post but problem is number of columns.
Any solution please ?
I think 50 is the best way, but you can redefine __get() magic method:
//your Item model class
protected $castMutators = [
//column1 => ['1' => 'string1', 2 => 'string2'],
//column2 => ['1' => 'string1', 2 => 'string2'],
//...
//column50 => ['1' => 'string1', 2 => 'string2'],
];
public function __get($name)
{
if (in_array($name, $this->castMutators)) {
$this->{$name} = $this->castMutators[$name][$this->name]
}
parent::__get($name);
}
You can override the getAttributeValue() or setAttributeValue() function on the Eloquent model like below. Then you can use the same accessor or mutator for multiple attributes.
protected function getAttributeValue($key)
{
$value = parent::getAttributeValue($key);
//if the value has already been mutated, don't modify, else if
//the key is in the array of specified attributes, mutate and return it
if($value === $this->getAttributeFromArray($key) && in_array($key, $this->attributes_to_mutate) ) {
$value = $this->myCustomMutator($value);
}
return $value;
}
Same goes for setAttributeValue($key, $value)
save array to config/your_config.php
<?php
return [
'columns' => [
1 => 'string_1',
2 => 'string_2',
],
];
usage:
config('your_config.columns')[1] // string_1
config('your_config.columns')[2] // string_2

Check if value exists within an array of objects

I am working on an API which receives a PHP object of $POST data. I am trying to check wether the 'smsPhoneNumber' inside customFields exists but not sure how to do this.
I am currently able to check for 'email' using:
if ( property_exists( $data, 'email' ) ) {
return true;
}
Question: How to check if 'smsPhoneNumber' exists?
--
var_dump:
object(stdClass)[1515]
public 'email' => string 'email#email.com'
public 'customFields' =>
array (size=2)
0 =>
object(stdClass)[1512]
public 'name' => string 'Firstname'
public 'value' => string 'james'
1 =>
object(stdClass)[1514]
public 'name' => string 'smsPhoneNumber'
public 'value' => string '077'
You could use an array_filter to get the custom field you want.
$phoneFields = array_filter($data->customFields, function($field) {
return $field->name === 'smsPhoneNumber';
});
This will only return objects in the array that have a name property equal to smsPhoneNumber.
if (!count($phoneFields)) {
// Phone not found
}
// or
if ($phone = current($phoneFields)) {
echo "The first phone number found is " . $phone->value;
}
The drawback of using array_filter() to search for the subarray values is:
array_filter() will not stop once it finds a match; it will keep iterating even after a match is found until it reaches the end of the array.
You should use a technique that allows an early break/return.
I recommend a simple foreach() with a break.
$foundIndex = null;
foreach ($data->customFields as $index => $customFields) {
if ($customFields->name === 'smsPhoneNumber') {
$foundIndex = $index;
// or $wasFound = true;
// or $smsNumber = $customFields->value;
break;
}
}
This will prove to be very efficient and easy to read/maintain.

Categories