Laravel cast json to array - collections

The client attribute is a json filed in the database, which I caste as array in my model. However by retuning the Model to an array, the client attribute remains as json string:
$provider = TokenCacheProvider::all([
'name', 'auth_url', 'token_url', 'auth_endpoint', 'client'
])
->keyBy('name')
->toArray();
output:
Array
(
[name] => azure_ad
[auth_url] => /oauth2/v2.0/authorize
[token_url] => /oauth2/v2.0/token
[auth_endpoint] => https://login.microsoftonline.com/
[client] => {"tenant":"some value","client_id":"some value","client_secret":"some value"}
)
I would expect and output like this:
Array
(
[name] => azure_ad
[auth_url] => /oauth2/v2.0/authorize
[token_url] => /oauth2/v2.0/token
[auth_endpoint] => https://login.microsoftonline.com/
[client] => Array
(
[tenant] => 'some value'
[client_id] => 'some value'
[client_secret] => 'some value'
[scope] => 'some value'
)
)
My Model has the corresponding $casts:
protected $casts = [
'client' => 'array',
];
Edit
This comes a little bit closer to what I need, but it returns only the clients attribute 😵‍💫
$provider = TokenCacheProvider::all([
'name', 'auth_url', 'token_url', 'auth_endpoint', 'client'
])
->keyBy('name')
->map(function ($item) {
return json_decode($item->client);
})
->toArray();

Resolved 😎
$provider = TokenCacheProvider::all([
'name', 'auth_url', 'token_url', 'auth_endpoint', 'client'
])
->keyBy('name')
->map(function ($item) {
return collect([
'auth_url' =>$item->auth_url,
'token_url' =>$item->token_url,
'auth_endpoint' =>$item->auth_endpoint,
'client' =>json_decode($item->client,true)
]);
})
->toArray();
Not sure if this is the most beautiful solution but it does exactly what I want.
Output:
Array
(
[auth_url] => /oauth2/v2.0/authorize
[token_url] => /oauth2/v2.0/token
[auth_endpoint] => https://login.microsoftonline.com/
[client] => Array
(
[tenant] => some values
[client_id] => some values
[client_secret] => some values
[scope] => https://graph.microsoft.com/.default
)
)
Feedback and enhancements are highly welcome!
Cheers

Related

Parsing cybersourse Response in PHP

I Need to parse the below array and retrieve values;status,id.
Below is the PHP Array
Array ( [0] => CyberSource\Model\PtsV2PaymentsPost201Response Object ( [container:protected] =>
Array ( [links] => CyberSource\Model\PtsV2PaymentsPost201ResponseLinks Object ( [container:protected] =>
Array ( [self] => CyberSource\Model\PtsV2PaymentsPost201ResponseLinksSelf
Object ( [container:protected] => Array ( [href] => /pts/v2/payments/621258854395 [method] => GET ) )
[reversal] => [capture] => [customer] => [paymentInstrument] => [shippingAddress] => [instrumentIdentifier] => ) )
[id] => 621258854395
[submitTimeUtc] => 2021-05-17T13:40:55Z
[status] => AUTHORIZED
[reconciliationId] => 621258854395
[errorInformation] =>...............
Below is my php code
$parseApiResponse = new CyberSource\Model\PtsV2PaymentsPost201Response($apiResponse);
print_r("Status"." ".$parseApiResponse->getStatus());
Please assist in resolving this.
Want to do a similar thing as I am able to do in java as below
String status = result.getStatus();
I hope this helps someone. It took me a while to figure this out. The original poster was so close. It's just...
print_r("Status"." ".$apiResponse[0]->getStatus());
No need to instantiate a new "PtsV2PaymentsPost201Response()". The response element ([0]) has already done that when you call, "createPayment()", etc.
lib/Model/PtsV2PaymentsPost201Response.php lists all the available getters. getId(), getStatus(), getLinks(),etc.
$parseApiResponse = new CyberSource\Model\PtsV2PaymentsPost201Response($apiResponse);
$result = \GuzzleHttp\json_decode( $parseApiResponse[0] , true );
return = $result['links'];

CakePHP deep (multiple related models) validation?

I have a model structure that is:
Organization belongsTo Address belongsTo CountryCode
So, Organization has foreign keys: mailing_address_id and physical_address_id
Address has foreign key: country_code_id
In the Organization model, relationship is defined as:
public $belongsTo = array(
'MailingAddress' => array('className'=>'Address', 'foreignKey'=>'mailing_address_id')
, 'PhysicalAddress' => array('className'=>'Address', 'foreignKey'=>'physical_address_id')
);
This appears to be working great - validation is functioning properly, etc.
In the Address model, relationship is defined as:
public $belongsTo = array(
'CountryCode' => array('className'=>'CountryCode', 'foreignKey'=>'country_code_id')
);
In my OrganizationsController, in a function to create a new organization, I'm testing validation using this code:
if($this->Organization->saveAll(
$data, array('validate'=>'only')
)) {
// Validates
$this->DBG('Org validated.');
} else {
// does not validate
$this->DBG('Org NOT NOT NOT validated.'.print_r($this->Organization->invalidFields(),true));
}
The $data array looks like this going into validation.
2015-06-08 21:03:38 Debug: Array
(
[Organization] => Array
(
[name] => Test Organization
)
[MailingAddress] => Array
(
[line1] => 100 Main Street
[line2] =>
[city] => Houston
[state] => TX
[postal_code] => 77002
[CountryCode] => Array
(
[name] => United St
)
)
[PhysicalAddress] => Array
(
[line1] => 100 Main Street
[line2] =>
[city] => Houston
[state] => TX
[postal_code] => 77002
[CountryCode] => Array
(
[name] => United St
)
)
)
The country code SHOULD NOT validate with the rules I have set in the CountryCode model:
public $validate = array(
'name' => array(
'nonemptyRule' => array(
'rule' => 'notEmpty'
,'required' => 'create'
,'message' => 'Must be provided.'
)
,'dupeRule' => array(
'rule' => array('isUnique', array('name','code'), false)
,'message' => 'Duplicate'
)
)
,'code' => array(
'rule' => 'notEmpty'
,'required' => 'create'
,'message' => 'Must be provided.'
)
);
However, validation PASSES on Organization->saveAll.
Also, if I attempt to access the CountryCode model from the OrganizationController, it's not loaded.
As in:
$this->Organization->MailingAddress->CountryCode->invalidate('name','Invalid!');
In that case, I get an error that CountryCode is null.
Any ideas why CountryCode wouldn't be validating or loaded?
Is validation supposed to work two steps away?
It turns out, there IS a deep option when validating (and saving). It's documented here with the saveAll options:
http://book.cakephp.org/2.0/en/models/saving-your-data.html
So, the validation block in the question works perfectly well if you include the deep option like so:
if($this->Organization->saveAll(
$data, array('validate'=>'only', 'deep'=>true)
)) {
// Validates
$this->DBG('Org validated.');
} else {
// does not validate
$this->DBG('Org NOT NOT NOT validated.'.print_r($this->Organization->invalidFields(),true));
}

Why is the invoice page different for another user?

When I go to admin/store/orders/50457/invoice as the administrator, I see the following:
Notice how it has a payment method of "Free order" and the total at the bottom is $0.00.
When I go to the same page as a non-administrator, I see the following:
Notice how Payment Method is empty and the total for the order is $8.21.
The correct one is what the administrator sees, so what is going on that makes the two behave differently?
EDIT: It turns out in a module I created (a long time ago) called tf_store_credit.module, I have the following:
function tf_store_credit_line_item(){
global $user;
$total_credit= uc_store_credit_f_get_user_credit($user->uid);
if ($total_credit>0){
$items[] = array
(
'id' => 'store-credit', // You will use this ID in the javascript
'title' => t('Store Credit'), // This is the text that will be displayed on the line item in the subtotal
'callback' => 'tf_store_credit_line_item_callback', // This is the callback function
'stored' => TRUE,
'default' => FALSE,
'calculated' => TRUE,
'display_only' => FALSE,
'weight' => 15,
);
}
return $items;
}
The problem is that it is getting the currently logged in user's store credit instead of the user who placed the order. So how would I go about getting the correct user?
In tf_store_credit.module, I modified it like this:
function tf_store_credit_line_item(){
global $user;
$total_credit= uc_store_credit_f_get_user_credit($user->uid);
if ($total_credit>0 || in_array("view_orders", $user->roles)){
$items[] = array
(
'id' => 'store-credit', // You will use this ID in the javascript
'title' => t('Store Credit'), // This is the text that will be displayed on the line item in the subtotal
'callback' => 'tf_store_credit_line_item_callback', // This is the callback function
'stored' => TRUE,
'default' => FALSE,
'calculated' => TRUE,
'display_only' => FALSE,
'weight' => 15,
);
}
return $items;
}
In uc_free_order.module, I did a similar thing so that "Payment method" showed up:
function uc_free_order_payment_method() {
global $user;
if ($user->name=='blah' || $user->name=='blah2' || in_array("view_orders", $user->roles)){
$methods[] = array(
'id' => 'free_order',
'name' => t('Free order'),
'title' => t('Free order - payment not necessary.'),
'desc' => t('Allow customers with $0 order totals to checkout without paying.'),
'callback' => 'uc_payment_method_free_order',
'checkout' => TRUE,
'no_gateway' => TRUE,
'weight' => 10,
);
return $methods;
}
}

cannot get checkboxes value using drupal form api

i have form in drupal which uploads images and has got few checkboxes in it.
Here is the form:
$form['checklist_fieldset'] = array(
'#type' => 'fieldset',
'#title' => t('Check List'),
'#collapsible' => FALSE,
'#collapsed' => FALSE,
);
$form['checklist_fieldset']['heating'] = array(
'#type' => 'checkboxes',
'#title' => t('Heating options'),
'#options' => array(
'0' => t('Yes'),
'1' => t('No')
),
'#description' => t('Heating details.')
);
and here is my submit function where i am processing image upload and grabbing the checkboxes value as well. I am getting the success message and image is getting uploaded but not getting the value of check boxes.
function property_add_view_submit($form,&$form_state){
$validators = array();
if($file = file_save_upload('p_file1',$validators,file_direcotry_path)){
$heating = array_keys($form_state['values']['heating']);
drupal_set_message(t('Property Saved! '.$heating));
dpm( $form_state['values']['heating']);
}
When you use #options on a FAPI element the value passed to the $form_state is the array key, so you don't need to use array_keys().
I'm not sure why you're using checkboxes for a yes/no, usually one would use a simple checkbox element. However if that's really what you want to do:
Your #options can't contain on option with 0 as the array key, it will be automatically filtered out and you'll never know if that option has been checked.
You should use $heating_options_chosen = array_filter($form_state['values']['heating'] to get the selected checkbox options.
I honestly think your code should look like this though:
$form['checklist_fieldset']['heating'] = array(
'#type' => 'checkbox',
'#title' => t('Heating options'),
'#options' => array(
'1' => t('Yes'),
'0' => t('No')
),
'#description' => t('Heating details.')
);
$heating_checked = $form_state['values']['heating'] == 1;
If I have checkbox Friends and options are like
[ ] abc
[ ] def
[ ] ghi
[ ] jkl
And I want to know which options user have marked, then use below function.
if ($form_state->getValue('friends') != NULL) {
foreach ($form_state->getValue('friends') as $key => $value) {
if ($value != 0) {
$friends = $friends . ", " . $key;
$friends = substr_replace($friends, "", 0, 1);
}
}
}
If user has chosen abc and ghi then you will get 1,3 as result in $friends
If you wanted to know the value then use $friends = $friends.", ".$value;
it worked for me..hope it will help you as well :)

Why are Symfony2 validation propertyPath valus in square brackets?

I am validating some values:
$collectionConstraint = new Collection(array(
'email' => array(
new NotBlank(),
new Email(),
),
'password' => array(
new NotBlank(),
new MinLength(array('limit' => 6)),
new MaxLength(array('limit' => 25)),
),
));
$data = array('email' => $this->getRequest()->get('email'), 'password' => $this->getRequest()->get('password'));
$errors = $this->get('validator')->validateValue($data, $collectionConstraint);
But for some reason the fields (propertyPath) are stored with square brackets - I'd like to understand why Sf does that. I have to manually remove all the brackets which seems absurd so I think I am missing some functionality somewhere.
Dump of $errors:
Symfony\Component\Validator\ConstraintViolationList Object
(
[violations:protected] => Array
(
[0] => Symfony\Component\Validator\ConstraintViolation Object
(
[messageTemplate:protected] => This value should not be blank
[messageParameters:protected] => Array
(
)
[root:protected] => Array
(
[email] =>
[password] =>
)
[propertyPath:protected] => [email]
[invalidValue:protected] =>
)
[1] => Symfony\Component\Validator\ConstraintViolation Object
(
[messageTemplate:protected] => This value should not be blank
[messageParameters:protected] => Array
(
)
[root:protected] => Array
(
[email] =>
[password] =>
)
[propertyPath:protected] => [password]
[invalidValue:protected] =>
)
)
)
Even the toString function is useless.
"[email]: This value should not be blank","[password]: This value should not be blank"
Property paths can map either to properties or to indices. Consider a class OptionBag which implements \ArrayAccess and a method getSize().
The property path size refers to $optionBag->getSize()
The property path [size] refers to $optionBag['size']
In your case, you validate an array. Since array elements are also accessed by index, the resulting property path in the violation contains squared brackets.
Update:
You don't have to manually remove the squared brackets. You can use Symfony's PropertyAccess component to map errors to an array with the same structure as your data, for example:
$collectionConstraint = new Collection(array(
'email' => array(
new NotBlank(),
new Email(),
),
'password' => array(
new NotBlank(),
new MinLength(array('limit' => 6)),
new MaxLength(array('limit' => 25)),
),
));
$data = array(
'email' => $this->getRequest()->get('email'),
'password' => $this->getRequest()->get('password')
);
$violations = $this->get('validator')->validateValue($data, $collectionConstraint);
$errors = array();
$accessor = $this->get('property_accessor');
foreach ($violations as $violation) {
$accessor->setValue($errors, $violation->getPropertyPath(), $violation->getMessage());
}
=> array(
'email' => 'This value should not be blank.',
'password' => 'This value should have 6 characters or more.',
)
This also works with multi-dimensional data arrays. There the property paths will be something like [author][name]. The PropertyAccessor will insert the error messages in the same location in the $errors array, i.e. $errors['author']['name'] = 'Message'.
PropertyAccessor's setValue is no real help because it cannot handle multiple violations for a single field. For instance, a field might be shorter than a constraint length and also contain illegal characters. For this, we would have two error messages.
I had to create my own code:
$messages = [];
foreach ($violations as $violation) {
$field = substr($violation->getPropertyPath(), 1, -1);
$messages[] = [$field => $violation->getMessage()];
}
$output = [
'name' => array_unique(array_column($messages, 'name')),
'email' => array_unique(array_column($messages, 'email')),
];
return $output;
We manually strip the [] characters from the property path and create an
array of arrays of fields and corresponding messages. Later we transform the
array to group the messages by fields.
$session = $request->getSession();
$session->getFlashBag()->setAll($messages);
In the controller, we add the messages to the flash bag.

Resources