Find difference between sets of objects - php

I have 2 objects and would like to find the difference between them. Return an array or object of the differences only. The two objects look as following.
{
"new": {
"crc_code": "00",
"serial_number": "239-03",
"reason": "Ir/b4c - no center rib",
"project_id": 9,
"wafer_id": 1,
"equipment_status_code_id": 7,
"plate_container_id": null,
"supplier_id": 1,
"container_slot_id": null,
"plate_quality_id": 1
},
"old": {
"crc_code": "00",
"serial_number": "239-03",
"reason": "Ir/b4c - no center rib",
"project_id": 9,
"wafer_id": 1,
"equipment_status_code_id": 2,
"plate_container_id": null,
"supplier_id": 1,
"container_slot_id": null,
"plate_quality_id": 2
}
}
What's the best way to go about this?
Update People asking what I have tried already?
Something along these lines.
array_udiff($new, $old, function ($obj_a, $obj_b) {
return strcmp($obj_a, $obj_b);
}
);
But not getting there..

Use array_diff_assoc:
return array_diff_assoc($obj->new, $obj->old);

// convert object to array
$arr = json_decode(json_encode($obj), true);
// get the diff
$diff = array_diff($arr['new'], $arr['old']);
// result
array:1 [
"equipment_status_code_id" => 7
]

Related

Reset value on map / transform fucntion failed - Laravel

When i tried to change the value of id to encrypted Id is using map function and transform function, it get zero value no string value or alpha numeric getting replaced .
but it is mandatory to encrypt all id's for API
Please Help me .
Function
function getLatestArticle($profileId)
{
$data = Article::wherehas('articleTrans',function($query){
$query->where('status', ApiConstants::PUBLISHED_STATUS);
})->with(['articleTrans'=>function($q){
$q->select('id','article_id','language_id','title','short_description','description','main_image');
$q->where('status', ApiConstants::PUBLISHED_STATUS);
}])->latest()->paginate(ApiConstants::D_PAGE_C);
$data->getCollection()->transform(function ($value) {
$value->id = encrypt($value->id);
return $value;
});
return $data;
}
Collection
"latest_data": [
{
"id": 0,
"profile_id": 3,
"name": "Test",
"trending": 0,
"new_arrived": 0,
"featured": 0,
"reading_time": null,
"has_series": 0,
"status": 0,
"created_by": 1,
"updated_by": 1,
"deleted_at": null,
"created_at": "2022-03-24T10:27:16.000000Z",
"updated_at": "2022-03-31T11:41:14.000000Z",
"created_from": 1,
"article_trans": {
"id": 8,
"article_id": 12,
"language_id": 1,
"title": "Test",
"short_description": "Test",
"description": "<p><strong>TestTestTestTestTestTestTest </strong></p>\r\n\r\n<p><strong>TestTestTestTestTestTestTestTestTestTestTestTestTest</strong></p>",
"main_image": "1648117636_AXwwVY6JSmNTxmXIiRqGlXiePTl70chCkmMDlehp.jpeg",
"image_url": "http://127.0.0.1:8000/storage/admin/article/image/1648117636_AXwwVY6JSmNTxmXIiRqGlXiePTl70chCkmMDlehp.jpeg"
}
}
Its not good solution to temporarily modify entity objects only for change API response format.
Better solution is using DTO/Transformer classes. Good example of transformers implementation is https://fractal.thephpleague.com/transformers/
In this way you can split presentation and model.
Using any packages is optional, you can write simple transformer classes like this:
// app/Transformers/ArticleTransformer.php
final class ArticleTransformer
{
public static function transform(Article $article): array
{
return [
'id' => encrypt($article->id),
// any fields
];
/*
// or if you need change only one property
return array_replace(
$article->toArray(), // or $article->jsonSerialize()
[
'id' => encrypt($article->id),
],
);
*/
}
public static function transformCollection(Collection $articles): Collection
{
return $collection->map(fn (Article $article): array => self::transform($article));
}
}
Then use this transformer:
return [
'latest_data' => ArticleTransformer::transformCollection($latestArticles),
];
Not very good, but should work:
Override jsonSerialize/toArray method of model, in returning modify your id.

Merge multiple CodeIgniter result sets into one array

Data queried from the database.
year 2021 = [
{
"month": 1,
"total": "1,482"
},
{
"month": 2,
"total": "5,422"
},
]
and
year 2020 = [
{
"month": 1,
"total": "2,482"
},
{
"month": 2,
"total": "6,422"
},
{
"month": 3,
"total": "7,422"
},
.........
{
"month": 12,
"total": "20,422"
},
]
Here I create a method called `GetData(), I create a loop from 1-12 based on the months in a year. Next I want to combine data in an array, but how do I combine the data?
Below is my controller model which calls the same model method over and over with different parameters:
public function GetData(){
$thn_now = 2021;
$thn_before = 2020;
$bulan = array();
for ($bul = 1; $bul <= 12; $bul++) {
$sql = $this->My_model->model_month($bul,$thn_now)->result(); // Here I make the current year parameter
// $sql2 = $this->My_model->model_month($bul,$thn_before)->result(); //here are the parameters of the previous year
foreach($sql as $row) {
$bulan[] = array(
'bulan' => $bul,
'total_now' => $row->hasil,
// how to display the previous year's total in an array ?
// 'total_before' => $row->hasil,
);
}
}
$this->set_response($bulan,200);
}
I want an output like this:
[
{
"month": 1,
"total_now": "1,482"
"total_before": "2,482"
},
{
"month": 2,
"total_now": "5,522"
"total_before": "6,422"
},
{
"month": 3,
"total_now": null
"total_before": "7,422"
},
.........
{
"month": 12,
"total_now": null,
"total_before": "20,422"
},
]
In 2021, the total is only until the month of 02, while in 2020 the total is until month 12.
If 2021 is only up to month 02 then the next array is total null.
I don't recommend that you make 24 trips to the database to collect individual totals; I'll urge you to create a new model method which delivers all of the monthly totals in a single trip.
I don't recommend allowing your controller to dictate the type of result set that is created from the active record in the model. The model should be consistently returning the same data in the same structure throughout your application.
It seems to me that your inner loop is only collecting one row anyhow, so instead of result() which creates an array of objects, just call row() which creates null or an object then immediately access the hasil property. Using the null coalescing operator, you can fall back to null when hasil is not a property of non-object null.
Professional programmers around the world (including ones that don't use English as their first language will recommend writing variables using English words. This allows a more consistent language for other developers to review and maintain your code. After all, you are using English in the rest of your php syntax, just keep it all in English.
For future flexibility, allow the "current year" to be passed in as a controller method argument. This will allow you to seamlessly view historic data (should the need ever arise). If there is no passed in argument, then default to the current year.
Hard coding the number of each month is acceptable because it will never change. However, as a general rule, try to avoid using hardcoded numbers/values in your script so that it is more flexible, easier to maintain, and more intuitive to read.
Suggested code (tolerating that you are passing up to 24 active record objects back to the controller):
public function GetMonthlyTotalsSincePreviousYear($year = null): void
{
$thisYear = $year ?? date('Y');
$lastYear = $thisYear - 1;
$result = [];
for ($month = 1; $month <= 12; ++$month) {
$result[] = [
'month' => $month,
'total_now' => $this->My_model->model_month($month, $thisYear)->row()->hasil ?? null,
'total_before' => $this->My_model->model_month($month, $lastYear)->row()->hasil ?? null,
];
}
$this->set_response($result, 200);
}
In my own application, I would have a model method that collects all of the data and a controller like this:
public function getMonthlyTotalsSincePreviousYear(int $year = null): void
{
$this->set_response(
$this->My_model->getMonthlyTotalsSincePreviousYear($year ?? date('Y')),
200
);
}
This, I believe, will assist you in developing the solution. I haven't included the entire array of $year_2020, but I hope you get the idea -
$year_2021 = [
[
"month" => 1,
"total_now" => "1,482"
],
[
"month" => 2,
"total_now" => "5,422"
]
];
$year_2020 = [
[
"month" => 1,
"total_before" => "2,482"
],
[
"month" => 2,
"total_before" => "6,422"
],
[
"month" => 3,
"total_before" => "7,422"
]
];
$output = [];
foreach ($year_2021 as $obj) {
$key = $obj['month'];
$output[$key] = $obj;
}
foreach ($year_2020 as $obj) {
$key = $obj['month'];
if (isset($output[$key])) {
$output[$key]['total_before'] = $obj['total_before'];
} else {
$obj['total_now'] = null;
$output[$key] = $obj;
}
}
$output = array_values($output);
error_log(json_encode($output));
Output
[{"month":1,"total_now":"1,482","total_before":"2,482"},{"month":2,"total_now":"5,422","total_before":"6,422"},{"month":3,"total_before":"7,422","total_now":null}]

Complicated JSON with Cakephp 3

I am working on a project which involves passing data "profiles" via JSON to a web application. I am using Cakephp 3.0 and am very new to it. I store the profiles in a mysql database and can easily query for the data and put it into a basic JSON format with each row being a separate value in the JSON:
Controller.php:
....
public function getProfileData()
{
$uid = $this->Auth->user('id');
$this->loadComponent('RequestHandler');
$this->set('profile', $this->MapDisplay->find(
'all',
['conditions' =>
['MapDisplay.user_id =' => $uid]
]
)
);
$this->set('_serialize', ['profile']);
}
....
get_profile_data.ctp:
<?= json_encode($profile); ?>
Which returns something like this:
{
"profile": [
{
"alert_id": 1,
"alert_name": "Test",
"user_id": 85,
"initialized_time": "2017-03-24T00:00:00",
"forecasted_time": "2017-03-24T00:10:00",
"minimum_dbz_forecast": 0,
"maximum_dbz_forecast": 10,
"average_dbz_forecast": 5,
"confidence_in_forecast": 0.99,
"alert_lat": 44.3876,
"alert_lon": -68.2039
},
{
"alert_id": 1,
"alert_name": "Test",
"user_id": 85,
"initialized_time": "2017-03-24T00:00:00",
"forecasted_time": "2017-03-24T00:20:00",
"minimum_dbz_forecast": 5,
"maximum_dbz_forecast": 15,
"average_dbz_forecast": 10,
"confidence_in_forecast": 0.99,
"alert_lat": 44.3876,
"alert_lon": -68.2039
},
{
"alert_id": 2,
"alert_name": "Test2",
"user_id": 85,
"initialized_time": "2017-03-24T00:00:00",
"forecasted_time": "2017-03-24T00:10:00",
"minimum_dbz_forecast": 10,
"maximum_dbz_forecast": 20,
"average_dbz_forecast": 15,
"confidence_in_forecast": 0.99,
"alert_lat": 44.5876,
"alert_lon": -68.1039
},
{
"alert_id": 2,
"alert_name": "Test2",
"user_id": 85,
"initialized_time": "2017-03-24T00:00:00",
"forecasted_time": "2017-03-24T00:20:00",
"minimum_dbz_forecast": 15,
"maximum_dbz_forecast": 25,
"average_dbz_forecast": 35,
"confidence_in_forecast": 0.99,
"alert_lat": 44.5876,
"alert_lon": -68.1039
]
}
I am hoping to A) Easily call individual profiles instead of searching for unique profile ids and B) Only have to load one JSON file to get all profile contents. An output of something like this would be more ideal:
{
"profile": [
{
"alert_id": 1,
"alert_name": "Test",
"initialized_time":"2017-03-24T00:00:00",
"alert_lat": 44.3876,
"alert_lon": -68.2039,
"profile_data": [
{
"forecasted_time": "2017-03-24T00:10:00",
"minimum_dbz_forecast": 0,
"maximum_dbz_forecast": 10,
"average_dbz_forecast": 5,
"confidence_in_forecast": 0.99
},
{
"forecasted_time": "2017-03-24T00:20:00",
"minimum_dbz_forecast": 5,
"maximum_dbz_forecast": 15,
"average_dbz_forecast": 10,
"confidence_in_forecast": 0.99
}
]
},
{
"alert_id": 2,
"alert_name": "Test2",
"initialized_time": "2017-03-24T00:00:00",
"alert_lat": 44.5876,
"alert_lon": -68.1039,
"profile_data": [
{
"forecasted_time": "2017-03-24T00:10:00",
"minimum_dbz_forecast": 10,
"maximum_dbz_forecast": 20,
"average_dbz_forecast": 15,
"confidence_in_forecast": 0.99
},
{
"forecasted_time": "2017-03-24T00:20:00",
"minimum_dbz_forecast": 15,
"maximum_dbz_forecast": 25,
"average_dbz_forecast": 35,
"confidence_in_forecast": 0.99
}
]
}
]
}
How would I go about querying my database and populating this JSON structure? Are there any Cakephp tools that help do this? Does reframing the JSON into this structure seem to make sense?
Thanks in advance!
Thanks to user ndm, I realized there were a few problems with my approach. I thought having all data in one table would simplify things, but in reality it would make things more complicated and require redundant data storage (eg, a latitude and longitude value stored for every profile entry, instead of just once in a separate table).
ndm also mentioned
You'd just have to set up the associations properly, and contain the associated >table in your find, and in case the property name for the association would be >profile_data, you wouldn't even have to modify the results at all.
After altering the Table Model file, I had this for a new "ProfileDataTable.php" file:
class ProfileDataTable extends Table
{
/**
* Initialize method
*
* #param array $config The configuration for the Table.
* #return void
*/
public function initialize(array $config)
{
parent::initialize($config);
$this->setTable('profile_data');
$this->setDisplayField('title');
$this->setPrimaryKey('alert_id');
$this->addBehavior('Timestamp');
$this->belongsTo('AlertData', [
'foreignKey' => 'alert_id'
]);
}
}
And this for a new "AlertDataTable.php" file:
class AlertDataTable extends Table
{
/**
* Initialize method
*
* #param array $config The configuration for the Table.
* #return void
*/
public function initialize(array $config)
{
parent::initialize($config);
$this->setTable('alert_data');
$this->setDisplayField('title');
$this->setPrimaryKey('alert_id');
$this->addBehavior('Timestamp');
$this->hasMany('ProfileData', [
'foreignKey' => 'alert_id'
]);
}
}
The important lines here being "belongsTo" and "hasMany".
I then was able to alter my query and use "contain" to easily link the two tables together and get the JSON formatted exactly how I wanted:
$this->AlertData->find(
'all',
['conditions' =>
['AlertData.user_id =' => $uid],
'contain' =>
['ProfileData']
]
);

PHP Mongo aggregate match regex

Performing a query that simulates a 'like/mysql' searching for teams on the name of the team
Team document structure
{
"_id": 9,
"name": "azerty",
"tag": "dsfds",
"desc": "ggdfgsdfgdfgdf",
"captain": 8,
"coach": 8,
"members": [{
"date_joined": "2016-03-31 15:22:09",
"user_id": 8
}, {
"date_joined": "2016-03-31 19:22:35",
"user_id": 9
}],
"current_invites": [{
"invite_id": 21,
"username": "Nikki",
"user_id": "9",
"status": 1,
"date_invited": "2016-03-31 18:32:40"
}, {
"invite_id": 22,
"username": "Nikki",
"user_id": "9",
"status": 2,
"date_invited": "2016-03-31 18:33:16"
}]
}
PHP Code =
$q = '/.*'.$q.'*./';
$result = $this->coll->aggregate(
array('$match' => array('name' => $q)),
array('$project' => array('name' => 1,'members' => array('$size' => '$members'))));
Feels like I'm going mad not knowing how to fix this.
Have used regex before after migrating to mongo but not with the combination of agg-match.
in my case i am finding the aggregated result in which you can not set the where clause so use the aggregated functions like $sort $unwind $orderby and so on i am using the all of the above mention and have the problem with the like stuff to match the string like %str% here my code in which i implement the like using $match with MongoRegex
public function getRecords($table,$where = array(),$like_key = false,$like_value = false,$offset = 1,$limit = 10,$order_column = false,$order_type = false, $isAggregate=false,$pipeline=array()){
$temp = $this->getMongoDb()->where($where);
if($like_key && $like_value){
$temp = $temp->like($like_key,$like_value);
// this like filter is for aggregated result work both on normal get record or by aggregated result
$pipeline[]=array(
'$match' => array( $like_key => new MongoRegex( "/$like_value/i" ) )
);
}
if($order_column && $order_type){
$order_by = array();
$order_by[$order_column] = $order_type;
$temp = $temp->order_by($order_by);
$pipeline[]=array(
'$sort'=>array($order_column => ($order_type =="desc")? -1 : 1)
);
}
I got the solution when I read the following aggregation framework go the aggregation framework
I hope you will get your solution to resolve your issue.

return multiple array through json in codeigniter

I want to return multiple array using json in codeigniter like this :
{
"countData"
[
{"flag":1,"count":3}
{"flag":0,"count":0}
{"flag":1,"count":2}
]
}
I already tried :
$faqdata=array(
'count' => $faqdata['countdata']['resultdata']['count'],
)
$listfaqcount['count_Data'][]=$faqdata;
$listfaqcount['flag'] =1;
$j_r=json_encode($listfaqcount);
echo $j_r;
Like this way for two more array .flag would be zero in else condition which I didn't mention here.
How can I do this? Please help.
Thanks in advance
You can do something like this
$listfaqcount['countData'][0] = array(
'flag' => 'flagValue',
'count' => 'countValue'
);
While you looping you change the index with your key like that
$listfaqcount['countData'][1] = array(
'flag' => 'flagValue',
'count' => 'countValue'
);
and so on and while you encoding you can do like this
echo json_encode($listfaqcount);
You need something like array_push
$array['countdata'] = [];
create our sample array sets
$somearray1 = ['flag'=>9,"count"=>5];
$somearray2 = ['flag'=>6,"count"=>6];
$somearray3 = ['flag'=>5,"count"=>7];
$somearray4 = ['flag'=>4,"count"=>8];
Basically what happens here is everytime you loop you push the array inside $array['countdata']
array_push($array['countdata'], $somearray1); //loop 1 format and push
array_push($array['countdata'], $somearray2); //loop 2 format and push
array_push($array['countdata'], $somearray3); //loop 3 format and push
array_push($array['countdata'], $somearray4); //loop 4 format and push
Print the result beautifully or prettily
print_r(json_encode($array,JSON_PRETTY_PRINT));
result would be
{
"countdata": [
{
"flag": 9,
"count": 5
},
{
"flag": 6,
"count": 6
},
{
"flag": 5,
"count": 7
},
{
"flag": 4,
"count": 8
}
]
}
this is just an example you could push your own formatted array.

Categories