Cakephp how can I fetch same table association data - cakephp

I have a database table called miles, miles data looks like after fetch and return in Json.
"userMiles": [
{
"id": 278,
"gain_miles": 0.02,
"start_time": "2022-07-06T15:40:47+09:00",
"end_time": "2022-07-06T15:45:08+09:00",
},
{
"id": 279,
"gain_miles": 0.02,
"start_time": "2022-08-06T15:40:47+09:00",
"end_time": "2022-08-06T15:45:08+09:00",
},
]
I have written code to fetch data looks
$milesTable = TableRegistry::getTableLocator()->get( 'Miles' );
$query = $milesTable->find('all'));
try{
$userMiles = $this->paginate($query);
}
catch (NotFoundException $e){
$userMiles = [];
}
Now I'm trying to change this Json structure like below
"userMiles": [
{
"start_date": "06-July",
"miles":[
{
"id": 278,
"gain_miles": 0.02,
"start_time": "2022-07-06T15:40:47+09:00",
"end_time": "2022-07-06T15:45:08+09:00",
},
...
]
},
{
"start_date": "01-Mar",
"miles":[
{
"id": 281,
"gain_miles": 0.20,
"start_time": "2022-03-01T15:40:47+09:00",
"end_time": "2022-03-01T15:45:08+09:00",
},
...
]
},
]
For change Json Structure like above I have tried below codes , but don't know what is the procedure I will follow to get this output.
$query = $milesTable->find();
->select(["start_date" => "TO_CHAR(start_time,'DD-Mon')"])
->contain('Miles')
;
In `milesTable.php`
$this->hasMany('Miles',[
'foreignKey' => 'start_time',
'joinType' => 'LEFT',
]);
For this query getting error " "Unable to load Miles association. Ensure foreign key in Miles is selected."
My first query is Am I in right track ? Which procedure I can follow to get my desire output Json ?
I have tried by group by and order
$query = $milesTable
->find()
->select([
"start_date" => "TO_CHAR(start_time,'DD-Mon')",
"gain_miles",
"start_time",
"end_time",
])
->group(['start_date','id'])
->order(['start_time' => 'DESC'])
;
Output That I'm getting
"query": [
{
"start_date": "05-Jul",
"gain_miles": 400,
"start_time": "2022-07-05T14:14:23+06:00",
"end_time": "2022-07-06T14:14:23+06:00",
},
....
];
No if I use Collection
$collection = new Collection($query);
$miles = $collection->groupBy('start_date');
I'm getting my desire result, but problem is pagination, can I use pagination on collection $query data ? Or how can I implement pagination here ?

First you can select your group by start_date, then you can write a method in your Miles Entity. (Solution for postgresql)
$query = $this->paginate($milesTable
->find()
->select([
"start_date" => "TO_CHAR(start_time,'DD-Mon')",
])
->group(['start_date'])
);
then in your entity
public function _getMilesByStartTime()
{
return \Cake\ORM\TableRegistry::getTableLocator()->get('Miles')
->find()
->where([
"TO_CHAR(start_time,'DD-Mon') = '$this->start_date'"
]);
}
Now In controller
foreach ($query as $entity) {
$userMiles[] = [
'start_time' => $entity->start_date,
'miles' => $entity->milesByStartTime
];
}
$userMiles array should contain your data ! Have n't test but think it will help !

Related

How would I write a WordPress function to run a json_encode and file_put_contents whenever a specific CPT post is saved

I need to generate a custom JSON file from custom fields in a custom post type. But I'm not sure what the proper function is for accomplishing this, or if my syntax is anywhere close to correct in the first place. I haven't worked much with JSON, and have never attempted to create one from dynamic content before.
I'm using an example json file for the mapping plugin I'm using as my model, but I suspect that I'm not writing the array in the right format by using this other JSON file.
In any case, embarrassingly, here's what I've got so far (and it's definitely not working):
function wpdocs_retailers_json($post_id) {
$maplocations = Array( ?>
{
"mapwidth": "1000",
"mapheight": "500",
"categories": [ {
"id": "food",
"title": "Fast-foods & Restaurants",
"color": "#a5a5a2",
"show": "false"
},
{
"id": "dep",
"title": "Department Stores",
"color": "#a5a5a2",
"show": "true"
},
{
"id": "clothing",
"title": "Clothing & Accessories",
"color": "#a5a5a2",
"show": "true"
},
{
"id": "health",
"title": "Health & Cosmetics",
"color": "#a5a5a2",
"show": "true"
},
{
"id": "misc",
"title": "Miscellaneous",
"color": "#a5a5a2",
"show": "true"
} ],
<?php if(have_rows('mall_levels', 'option')) { ?>
"levels": [ {
<?php while(have_rows('mall_levels', 'option')) {
the_row();
$level_svg = get_sub_field('svg_mall_level');
$level = get_sub_field('what_level_is_this');
?>
"id": "<?php echo esc_html($level->slug); ?>",
"title": "<?php echo esc_html($level->name); ?>",
"map": "<?php echo $level_svg; ?>",
<?php $locargs = array(
'post_type' => 'retailers',
'post_status' => 'publish',
'posts_per_page' => 0,
'orderby' => 'title',
'order' => 'ASC'
);
$locloop = new WP_Query($locargs);
if($locloop->have_posts()) { ?>
"locations": [
<?php while($locloop->have_posts()) {
$locloop->the_post();
$space = get_field('space_id'); ?>
{
"id": "space-<?php echo $space; ?>",
"title": "<?php the_title(); ?>",
"about": "Lorem ipsum",
"description": "<?php the_content(); ?>",
<?php $cats = get_the_terms($post->ID, 'dir_cats');
$catsCount = count($cats);
if($catsCount = 0) { ?>
"category": "<?php echo $cat->name; ?>"
<?php }
if($catsCount > 0) { ?>
"category": [<?php echo '"' . __($cat->name) . '"'; ?>]
<?php } ?>
"link": "<?php the_permalink(); ?>",
"x": "0.3721",
"y": "0.4296"
},
<?php } //endwhile; ?>
]
<?php } //endif;
} //endwhile; ?>
},
]
<?php } //endif; ?>
}
<?php );
$json = json_encode($maplocations);
$bytes = file_put_contents('mall.json', $json);
}
add_action('save_post_retailers', 'wpdocs_retailers_json');
I think, at least in part, the array needs to be written more like this? But I'm not sure:
"mapwidth" => "1000",
"mapheight" =>"500",
"categories" => Array(
array(
"id" => "food",
"title" => "Fast-foods & Restaurants",
"color" => "#a5a5a2",
"show" =>"false"
),
array(
"id" => "dep",
"title" => "Department Stores",
"color" => "#a5a5a2",
"show" => "true"
),
...etc.
Thanks in advance for any guidance you can provide. I apologize for my utter lack of knowledge to begin with on this one. Please be kind.
(...) the array needs to be written more like this?
Yes, you want to use that array syntax to make your life easier in the long run (IMO at least).
Here are some changes to your code. Untested though so let me know how it goes and/or if you have any further comments/questions.
function wpdocs_retailers_json($post_id) {
$maplocations = array(
"mapwidth" => 1000,
"mapheight" => 500,
"categories" => array(
array(
"id" => "food",
"title" => "Fast-foods & Restaurants",
"color" => "#a5a5a2",
"show" => "false"
),
array(
"id" => "dep",
"title" => "Department Stores",
"color" => "#a5a5a2",
"show" => "false"
),
array(
"id" => "clothing",
"title" => "Clothing & Accessories",
"color" => "#a5a5a2",
"show" => "false"
),
array(
"id" => "health",
"title" => "Health & Cosmetics",
"color" => "#a5a5a2",
"show" => "false"
),
array(
"id" => "misc",
"title" => "Miscellaneous",
"color" => "#a5a5a2",
"show" => "false"
)
)
);
// We have map levels, save them to
// our json file
if(have_rows('mall_levels', 'option')) {
$maplocations['levels'] = array();
while(have_rows('mall_levels', 'option')) {
the_row();
$level_svg = get_sub_field('svg_mall_level');
$level = get_sub_field('what_level_is_this');
$level_data = array(
"id" => esc_html($level->slug),
"title" => esc_html($level->name),
"map" => $level_svg,
)
$locargs = array(
'post_type' => 'retailers',
'post_status' => 'publish',
'posts_per_page' => 0,
'orderby' => 'title',
'order' => 'ASC'
);
$locloop = new WP_Query($locargs);
// We have some locations, save them as well
if($locloop->have_posts()) {
$level_data['locations'] = array();
while($locloop->have_posts()) {
$locloop->the_post();
$space = get_field('space_id');
$title = get_the_title();
$content = get_the_content();
$cats = get_the_terms(get_the_ID(), 'dir_cats');
$permalink = get_permalink();
$level_data['locations']['id'] = 'space-' . esc_attr($space);
$level_data['locations']['title'] = esc_html($title);
$level_data['locations']['about'] = 'Lorem Ipsum';
$level_data['locations']['description'] = $content;
if ( count($cats) ) {
$level_data['category'] = join(', ', wp_list_pluck($cats, 'name'));
}
$level_data['locations']['link'] = esc_url( $permalink );
$level_data['locations']['x'] = '0.3721';
$level_data['locations']['y'] = '0.4296';
}
// Restore original post data
wp_reset_postdata();
}
// Add our $level_data array to $maplocations
$maplocations['levels'][] = $level_data;
}
}
// Convert PHP array into JSON string
$json = json_encode($maplocations);
// Save json string to mall.json
$bytes = file_put_contents('mall.json', $json);
}
add_action('save_post_retailers', 'wpdocs_retailers_json');
Note that file_put_contents('mall.json', $json); probably should use a full path to the folder where you want to store your mall.json file.
#cabrerahector Got me super close. After a little more trial and error, the last part of the above needs to go like this:
$mapjson = json_encode($maplocations);
$j_dir = get_stylesheet_directory();
$mapdata = '/json/mall.json';
file_put_contents($j_dir . $mapdata, $mapjson, LOCK_EX);
update_post_meta($post_id, 'mall, $date);
}
add_action('save_post_retailers', 'retailers_map_json', 20);
(note, I did change the name of the function to "retailers_map_json" instead of "wpdocs_retailers_json".

Cakephp How Can I add virtual field in select query?

In front end I have to display all favorites icon green depend on is_fav status true.
So, I'm trying to create an API, Where I want to add is_fav with all product entity. My expected json will looks like
{
"id": 14,
"title": "Orange",
"price": 600,
"is_fav" : true
}
So, I'm trying to add is_fav with product entities , where is_fav is a virtual function.
In entity I have tried like below
protected function _getIsFav()
{
//to DO : I will write a query here
return true;
}
In query I have tried to add in query in select like below
$favorites = TableRegistry::getTableLocator()
->get( 'Products' )
->find()
->select([
'id',
'Products.id',
'Products.title',
'Products.price',
'is_fav' => $this->is_fav, //getting error
])
;
I'm getting error, How can I add is_fav with product entities. Is it possible ? If not how can I add is_fav like my json ?
This worked for me. CakePHP 4.3
In the Entity
protected $_virtual = ['label'];
protected function _getLabel()
{
return $this->name . ' - (' . $this->company. ')';
}
The query does not mention the virtual field
$customers = $this->Users->find()
->select(['id', 'name', 'company'])
->contain(['Roles' => function ($q) {
return $q->select(['id','name','level','price_level'])
->where(['Roles.level' => 50]);
}])
->order('Users.name');
and then the JSON that output
[
{
"id": 1019,
"name": "Abby xxxx",
"company": "Abby yyy",
"role": {
"id": 4,
"name": "Practitioner",
"level": 50,
"price_level": 2
},
"label": "Abby xxxx - (Abby yyy)"
}
]

how to convert it in array while returnung in laravel

while creating an API I am having some issues while returning the data at response please help to resolve it
$user_role = [
'user_id' => $data,
'role_id' => 1,
];
my result
"user_role": {
"user_id": 191,
"role_id": 1
}
I want it in an array-like below
"user_role": [{
"user_id": 191,
"role_id": 1
}]
Try this
$user_role = [[
'user_id' => $data,
'role_id' => 1,
]];
return response()->json(["user_role" => $user_role], 200);

laravel array groupBy specific column value

I'm working with arrays in laravel and I have a result like this:
$datesArr = [ {
"day": "monday",
"date": "2021-05-03"
},
{
"day": "monday",
"date": "2021-05-10"
},
{
"day": "monday",
"date": "2021-05-17"
}
]
what I want is this:
{
"day": "monday",
"dates" : [
{"date": "2021-05-03"},
{"date": "2021-05-10"},
{"date": "2021-05-17"},
]
}
Hope to help you (should convert all to array)
public static function buildArrayGroupBy($key, $data , $lockKey = null) {
$result = array();
foreach($data as $val) {
if(array_key_exists($key, $val)){
if(!is_null($lockKey)){
$result[$val[$key]][] = $val[$lockKey];
}else{
$result[$val[$key]][] = $val;
}
}else{
$result[""][] = $val;
}
}
return $result;
}
You can use Laravel Collection's groupBy function.
The output will be in the format below but it'll do the job.
$datesArr = [
"monday" => [
{
"day": "monday",
"date": "2021-05-03"
},
{
"day": "monday",
"date": "2021-05-10"
},
{
"day": "monday",
"date": "2021-05-17"
}
]
]
For exact output like mentioned, You can use mapToGroups.
$data->mapToGroups(function($i) {
return ['day' => $i['day'],
'dates' => [
'date' => $i['date']
]];
});
P.S: You might have to change it a little bit according to your requirements.
Thank you to all that tried to help me. I came with an idea how to solv it.
I will try to explain it here.
First I got all days that I have stored. then:
$daysArr = array();
foreach($days as $key => $day){
$datesArr = array();
for($i = 0;$i< 8;$i++){
$newDate['date'] = now()->next($key)->addWeeks($i)->toDateString();
array_push($datesArr,$newDate);
}
$test['day'] = $key;
$test['dates'] = $datesArr;
array_push($daysArr,$test);
unset($datesArr);
}
return $daysArr;
I did double array_push and foreach "new day" , I unset $datesArr to get empty array for pushing new dates of "new day".
Hope I was clear enough!
Let's generate some dummy data based on your requirements:
foreach(range(1,100) as $rangeTbs){
$carbon = \Carbon\Carbon::now()
->addDays(rand(1,20))
->addMonths(rand(1,2));
$dateArrayTbs[] = [
'day' => $carbon->format('l'),
'date' => $carbon->format('Y-m-d'),
];
}
Now we can convert array into collection:
$collection = collect($dateArrayTbs)
//Grouping By day
->groupBy('day')
//Now Converting into Desired Format
->map(function(Collection $collection,$day){
return [
'day' => $day,
'dates' => $collection->sortBy('date')->toArray(),
];
});

Laravel how to return object into JSON Arrays data type without keys

I have DB query in the Controller like this:
$query = User::all('id','name','email')->take(2);
$users = ["data" => $query];
return $users;
And get the result:
{
"data": [
{
"id": 1,
"name": "Peter",
"email": "peter#peter.com"
},
{
"id": 2,
"name": "John",
"email": "john#john.com"
}
]
}
But i'm expecting to get JSON Arrays data type without keys like this:
{
"data": [
[
"1",
"Peter",
"peter#peter.com"
],
[
"2",
"John",
"john#john.com"
]
]
}
I need to get this type for DataTables JSONP data source for remote domains.
https://datatables.net/examples/server_side/jsonp.html
How to do this?
Thanks.
You can try array_values like so:
$query = User::all('id', 'name', 'email')->take(2);
$users = ["data" => $query->map(function (User $user) {
return array_values($user->attributesToArray());
})];
return $users;
How about something like this?
$query = User::all('id', 'name', 'email')->take(2);
$userValues = $query->map(function($item, $key) {
return [
$item['id'],
$item['name'],
$item['email']
];
})
$users = ["data" => $userValues];
return $users;
// result
{
"data": [
[
1,
"Amy Wilderman",
"vrau#example.net",
],
[
2,
"Bria Lindgren PhD",
"trevor.armstrong#example.org",
],
]
}

Resources