I have 2 or more php objects that have the same sections. Each section has objects in it. I want to combine these objects together. Since each section has the same title I remove the title of the new object before merging them. My code isn't keeping the proper structure and is adding an unwanted level 'component' to the primary object. Feels like I am missing something obvious but I Can't figure out how to add the new object without the 'component' level.
Object 1 Example
stdClass Object(
[section_1] => stdClass Object
(
[title] => Production
[component_name_68] => stdClass Object
(
[title] => custom component title
[id] => 68
[type] => component_name_68
[subtotal] => 1127.50
[desc] => custom description
)
)
)
Object 2 Example
stdClass Object(
[section_2] => stdClass Object
(
[title] => Production
[component_name_69] => stdClass Object
(
[title] => custom component title2
[id] => 69
[type] => component_name_69
[subtotal] => 1985.50
[desc] => custom description2
)
)
)
Current Code
foreach($this->Details as $section1){
foreach($newinfo as $section2){
if($section1->title == $section2->title){
unset($section2->title);
$section1->{"component"} = $section2;
}
}
}
Current Result
stdClass Object(
[section_1] => stdClass Object
(
[title] => Production
[component_name_68] => stdClass Object
(
[title] => custom component title
[id] => 68
[type] => component_name_68
[subtotal] => 1127.50
[desc] => custom description
)
[component] => stdClass Object (
[component_name_69] => stdClass Object
(
[title] => custom component title2
[id] => 69
[type] => component_name_69
[subtotal] => 1985.50
[desc] => custom description2
)
)
)
Desired Result
stdClass Object(
[section_1] => stdClass Object
(
[title] => Production
[component_name_68] => stdClass Object
(
[title] => custom component title
[id] => 68
[type] => component_name_68
[subtotal] => 1127.50
[desc] => custom description
)
[component_name_69] => stdClass Object
(
[title] => custom component title2
[id] => 69
[type] => component_name_69
[subtotal] => 1985.50
[desc] => custom description2
)
)
)
Might something like this work?
foreach($this->Details as $section1){
foreach($newinfo as $section2){
if($section1->title == $section2->title){
unset($section2->title);
$components = get_object_vars($section2);
// Check to see that only one key is present. Skip if more than one.
if (count($components) > 1) {
continue;
}
$component_keys = array_keys($components);
$component_key = reset($component_keys);
$section1->{$component_key} = $section2->{$component_key};
}
}
}
Basically it seems the issue is determining the key name for the subordinate component. You would have to add your own error checking. For example, I assume the second component will only have the one object, but that may not be true. Perhaps you need to ensure the key begins with the string "component_name", perhaps that is just a placeholder. You would just need to adapt this to your data structure.
Combining Objects sometime is hectic job because we want to keep the object definintion after merging them into single object(parent)
Check this link for more information.
Related
We have installed another plugin for WooCommerce called Booster Plus for WooCommerce and this plugin can modify the checkout page by paying for an order by invoice number.
I am customizing our thank you page by displaying the invoice number too. Currently, I am not able to do that because I don't know how can I properly get the value of the nested $order->get_data() result.
<?php
$order_data = $order->get_data();
print_r($order_data);
?>
The result of order_data above looks like below:
(
[id] => 7403
[discount_total] => 0
[discount_tax] => 0
[shipping_total] => 0.00
[shipping_tax] => 0
[cart_tax] => 2.47
[total] => 21.47
[total_tax] => 2.47
[customer_id] => 20
[order_key] => wc_order_8pt3q7T79
[billing] => Array
(
[first_name] => John
[last_name] => Done
[company] => g2x
[address_1] => 3134 James Street
[address_2] =>
[city] => Moose Factory
[state] => ON
[postcode] => P0L 1W0
[country] => CA
[email] => testjohndoe123#gmail.com
[phone] => 705-658-2112
)
[cart_hash] => 087347d19dff4677dc8kaeb2b2c653c6
[number] => 7403
[meta_data] => Array
(
[0] => WC_Meta_Data Object
(
[current_data:protected] => Array
(
[id] => 102652
[key] => mailchimp_woocommerce_campaign_id
[value] =>
)
[data:protected] => Array
(
[id] => 102652
[key] => mailchimp_woocommerce_campaign_id
[value] =>
)
)
[1] => WC_Meta_Data Object
[2] => WC_Meta_Data Object
[3] => WC_Meta_Data Object
[4] => WC_Meta_Data Object
[5] => WC_Meta_Data Object
(
[current_data:protected] => Array
(
[id] => 102694
[key] => _wcj_custom_payment_gateway_input_fields
[value] => Array
(
[pay_by_po] => 123456789
)
)
[data:protected] => Array
(
[id] => 102694
[key] => _wcj_custom_payment_gateway_input_fields
[value] => Array
(
[pay_by_po] => 123456789
)
)
)
[coupon_lines] => Array
()
)
Do you know how can I get the value of [pay_by_po] which is 123456789? Any help is greatly appreciated. Thank you.
You can get and unprotect this nested meta data using WC_data method get_meta_data(), which gives an array of WC_Meta_Data Objects:
$meta_data = $order->get_meta_data();
print_r($order_data);
Then on each WC_Meta_Data Object, you can use WC_Meta_Data available methods like get_data() that gives an unprotected data array:
foreach( $order->get_meta_data() as $meta_data_obj ) {
$meta_data_array = meta_data_obj->get_data();
print_r($meta_data_array);
$meta_key = $meta_data_array['key']; // The meta key
$meta_value = $meta_data_array['value']; // The meta value
}
You can also get directly any nested meta data from the order using WC_Data method get_meta() from aspecific meta key as follow:
$meta_value = $order->get_meta('_wcj_custom_payment_gateway_input_fields');
print_r($meta_value);
Note This nested meta data exist since WooCommerce version 3.
About Abstract WC_Data Class
Its Implemented by classes using the same CRUD(s) pattern.
Direct known subclasses:
WC_Abstract_Legacy_Order, WC_Abstract_Legacy_Product, WC_Customer_Download, WC_Customer_Download_Log, WC_Legacy_Coupon, WC_Legacy_Customer, WC_Legacy_Payment_Token, WC_Legacy_Shipping_Zone, WC_Legacy_Webhook, WC_Order_Item
Indirect known subclasses:
WC_Abstract_Order, WC_Coupon, WC_Payment_Token, WC_Payment_Token_CC, WC_Payment_Token_ECheck, WC_Product, WC_Product_External, WC_Product_Grouped, WC_Product_Simple, WC_Product_Variable, WC_Product_Variation, WC_Shipping_Zone, WC_Customer, WC_Webhook, WC_Order, WC_Order_Item_Coupon, WC_Order_Item_Fee, WC_Order_Item_Product, WC_Order_Item_Shipping, WC_Order_Item_Tax, WC_Order_Refund
See: Developing using WooCommerce CRUD objects
I am trying to create a wordpress shortcode which returns the price of a book from an API.
Ideally, I would like to be able to create a shortcode with this format [currency_isbn13] but for the moment I'd be happy to just create a fixed shortcode for each book and currency.
After various attempts, I was able to put together the following php code, but it is not working as it should
function Price() {
$isbn13 = 9783899735215;
$url = 'https://api.bookdepository.com/search/lookup?isbn13='.$isbn13.'&clientId={redact}&authenticationKey={redact}&IP={redact}¤cies=GBP';
$sxml = simplexml_load_file($url);
print_r($sxml);
return $sxml->price;
}
add_shortcode('isbn13', 'Price');
I would expect the shortcode to return the price of the book, but I get the following:
How can I fix this? I'm sure it is very simple but can't figure it out
SimpleXMLElement Object ( [resultset] => SimpleXMLElement Object ( [status] => Success [results] => 1 [totalResults] => 1 [currentPage] => 1 [totalPages] => 1 ) [items] => SimpleXMLElement Object ( [item] => SimpleXMLElement Object ( [identifiers] => SimpleXMLElement Object ( [isbn13] => 9783899735215 ) [url] => https://www.bookdepository.com/Crocodile-Newts-Axel-Hernandez/9783899735215 [biblio] => SimpleXMLElement Object ( [title] => Crocodile Newts [format] => Hardback ) [availability] => Available - dispatched from the UK in 4 business days [pricing] => SimpleXMLElement Object ( [price] => SimpleXMLElement Object ( [#attributes] => Array ( [currency] => GBP ) [selling] => 50.27 ) ) [contributors] => SimpleXMLElement Object ( [contributor] => SimpleXMLElement Object ( [name] => Axel Hernandez [roleDescription] => By (author) [url] => https://www.bookdepository.com/author/Axel-Hernandez ) ) ) ) )
Looks as though you need to expand
return $sxml->price;
as your structure is more complex. Looks as though
return (string)$sxml->items->item->pricing->price->selling;
The cast to (string) makes the value easier to use elsewhere.
I have a scenario where an API is returning multiple records inside object containing a numeric array like so;
stdClass Object
(
[Event] => Array
(
[0] => stdClass Object
(
[ID] => 111
[Name] => My First Event
[EventType] => stdClass Object
(
[ID] => 1
[Category] => Music
)
)
[1] => stdClass Object
(
[ID] => 222
[Name] => My Second Event
[EventType] => stdClass Object
(
[ID] => 2
[Category] => Sport
)
)
)
[Errors] => stdClass Object
(
[Result] => 0
[Message] =>
)
[RecordCount] => 2
)
I'm current using a foreach loop to iterate through the records. This works fine.
foreach($result->Event as $Event)
But there is a problem here I have a scenario where a single results is returned in the object like so;
stdClass Object
(
[Event] => stdClass Object
(
[ID] => 11
[Name] => My Only Event
[EventType] => stdClass Object
(
[ID] => 2
[Category] => Sport
)
)
[Errors] => stdClass Object
(
[Result] => 0
[Message] =>
)
[RecordCount] => 1
)
Notice there is no [0] array index for the single results.
What's the best way to overcome this keeping in mind that I have no control of the data returned by the API?
Check if Event is an array or an object
if( is_object( $result->Event ) )
{
// ...
}
else
{
foreach( // [....]
}
You may process the object or overwrite it with a 1 item array as suggested by Sam
Btw: very bad API design. I would complain....
The best workaround I have found is to add the single Event to an array with a zero index within the result object. This way the result object matches the same structure as a result containing multiple records.
if(!is_array($result->Event)){
$result->Event = array($result->Event);
}
First, I'm using sugarcrm pro 6.5 and accessing via rest v4, so I have this array that's being returned from printing $results that is working fine:
stdClass Object
(
[result_count] => 2000
[total_count] => 3390
[next_offset] => 2000
[entry_list] => Array
(
[0] => stdClass Object
(
[id] => 77da301b-83dd-4fe6-e38f-53ba151fb084
[module_name] => Leads
[name_value_list] => stdClass Object
(
[id] => stdClass Object
(
[name] => id
[value] => 77da301b-83dd-4fe6-e38f-53ba151fb084
)
[name] => stdClass Object
(
[name] => name
[value] => Jim Beam
)
[status] => stdClass Object
(
[name] => status
[value] => Dead
)
[website] => stdClass Object
(
[name] => website
[value] => website.com
)
[phone_cr] => stdClass Object
(
[name] => phone_cr
[value] => 1-888-888-8888
)
)
)
[1] => stdClass Object
(
[id] => d0ecc069-d556-98f3-41f2-53ba1468327a
[module_name] => Leads
[name_value_list] => stdClass Object
(
[id] => stdClass Object
(
[name] => id
[value] => d0ecc069-d556-98f3-41f2-53ba1468327a
)
[name] => stdClass Object
(
[name] => name
[value] => John Doe
)
[status] => stdClass Object
(
[name] => status
[value] => New
)
[website] => stdClass Object
(
[name] => website
[value] => web.com
)
[phone_cr] => stdClass Object
(
[name] => phone_cr
[value] => 1-888-888-8888
)
)
)
I'm using a query from the api to filter the results for the user I'm targeting:
'query' => "leads.assigned_user_id='user_ID-here'",
'order_by' => "date_entered DESC",
This works fine. So I've ran a foreach () statement to retrieve only one field on a button click, which also works just fine. What I really need to accomplish is before this statement, a foreach() command (or something else?) to filter out and retrieve ONLY the "New" results in the status value, and from that group output an array showing only the website field. Seen in the "desired end result section of this question."
This is the code I'm filtering the field I'm targeting and having a new array created with if that helps bridge the gap:
$results = call('get_entry_list', $params, $url);
$eresult = array();
foreach ($results->entry_list as $index=>$value_list) {
$listed = $value_list->name_value_list->website->value;
$eresult[] = $listed;}
So the desired end result based on this data should be:
Array
(
[1] => web.com
)
I'm unsure what I need to do to filter the "Status" field to only then be ran with the $eresult array I created to achieve this. To be clear, everything is working as it should, and my print from $eresult is outputting exactly as it should by returning all results in the website value area, I just need some help to get it sorted before going to that step by sorting it by the "new" status first without all the extra 'stuff,' then sorting out the array in my desired format with the foreach() statement above. I tried to cut out all the other code, as it's a pretty long project, so this should be all the relevant information for the particular goal I need to accomplish in this segment. Any help is greatly appreciated! Thank you!
I've decided to create a second script for this as a temp solution by adding:
'query' => "(leads.assigned_user_id='user_ID-here') AND (status='New')"
So I guess that works, I was trying to avoid calling another script for just one separate function, but it is working fine.
In our backoffice we have a core-system that generates models from the DB. When returning one object we make an instance of stdClass. All the columns from the query-result are set as proprties and when finished processing the query-result the stdClass-object is converted into a (we call it) Decorator-class. Basically the Decorator-class has one proprty $_oObject where the stdClass is stored into. We do this gain control over dynamically created objects. This works all fine.
However, I'm working on a webserver using SOAP. The webservice returns the whole Decorator-object (could possibly have sub-objects, also being Decorator objects, and sub-sub object.. and so on). This structure works perfectly fine with our internal system because we have control over the Decorator-object but for the outside world I want to revert the Decorator-object-structure into a stdClass instance with sub-classes also being stdClasses. Basically I want to remove all the 'nodes' in the print_r-result containing Decorator.
Any ideas how to achieve what I want (see results below). PHP's get_object_vars doesn't return anything and actually I'm stuck..
My sample data:
Decorator Object
(
[oClass:Decorator:private] => stdClass Object
(
[Id] => 1
[FAQCategoryId] => 1
[TitleId] => 1
[ContentId] => 2
[Views] => 226
[DateCreated] => 2011-10-31 11:17:44
[DateModified] =>
[Title] => My title..
[Content] => My content..
[AttachmentSet] => Array
(
[0] => Decorator Object
(
[oClass:Decorator:private] => stdClass Object
(
[Id] => 1
[LanguageId] => 1
[FAQItemId] => 1
[Attachment] => file1.pdf
)
)
[1] => Decorator Object
(
[oClass:Decorator:private] => stdClass Object
(
[Id] => 2
[LanguageId] => 1
[FAQItemId] => 1
[Attachment] => file2.pdf
)
)
)
)
)
I want to convert it into:
stdClass Object
(
[Id] => 1
[FAQCategoryId] => 1
[TitleId] => 1
[ContentId] => 2
[Views] => 226
[DateCreated] => 2011-10-31 11:17:44
[DateModified] =>
[Title] => My title..
[Content] => My content..
[AttachmentSet] => Array
(
[0] => stdClass Object
(
[Id] => 1
[LanguageId] => 1
[FAQItemId] => 1
[Attachment] => file1.pdf
)
[1] => stdClass Object
(
[Id] => 2
[LanguageId] => 1
[FAQItemId] => 1
[Attachment] => file2.pdf
)
)
)
I've figured it out. In my case I've created a function that returns the stdObject of a Decoarator object. In my Controller_Core-class I've made function that recursively handles a given object and returns the whole structure as one stdClass.
My code, if it is helpful to someone:
/**
* Controller_Core::RevertToStdClass
*
* #params: Decorator $oObject
* #return: stdClass $oObject
**/
public function RevertToStdClass(Decorator $oObject)
{
if(is_a($oObject, "Decorator"))
{
$oObject = $oObject->ReturnStdObject();
}
$aProperties = get_object_vars($oObject);
foreach($aProperties as $sProperty => $mValue)
{
if(is_array($mValue))
{
foreach($mValue as $mIndex => $mSubValue)
{
if(is_a($mSubValue, "Decorator"))
{
$oObject->{$sProperty}[$mIndex] = $this->RevertToStdClass($mSubValue);
}
}
}
else
{
if(is_a($mValue, "Decorator"))
{
$oObject->{$sProperty} = $this->RevertToStdClass($oObject->{$sProperty});
}
}
}
return $oObject;
}