Ok, so my issue is, my ajax call isn't updating correctly. It's the same as many functions as I have, it's just not updating the values. Although, I can run the query on it's own in mysql and it update ok. Function is below:
/*
* "elerts/quicksave" > Update elert from all screen
*/
public function quicksave($id)
{
$data = (object)Input::get();
$ev = Events::find($id);
$ev->limit = $data->limit;
$ev->EventEnabled = $data->EventEnabled;
$ev->SundayStart = $data->SundayStart;
$ev->MondayStart = $data->MondayStart;
$ev->TuesdayStart = $data->TuesdayStart;
$ev->WednesdayStart = $data->WednesdayStart;
$ev->ThursdayStart = $data->ThursdayStart;
$ev->FridayStart = $data->FridayStart;
$ev->SaturdayStart = $data->SaturdayStart;
$ev->save();
$queries = DB::getQueryLog();
$last_query = end($queries); dd($last_query);
return "Your eLert has been saved!";
}
Below is an example ID getting passed and an example of the $data object that's getting passed.
$id = '107';
object(stdClass)#137 (9) { ["limit"]=> string(3) "400" ["EventEnabled"]=> string(1) "1" ["SundayStart"]=> string(1) "0" ["MondayStart"]=> string(1) "0" ["TuesdayStart"]=> string(1) "0" ["WednesdayStart"]=> string(1) "0" ["ThursdayStart"]=> string(1) "1" ["FridayStart"]=> string(1) "1" ["SaturdayStart"]=> string(1) "1"}
I'm confused as to why nothing is getting updated. Any help?
EDIT: Below I've included the code for my model so people won't have to question it...
<?php
/**
* #author jmadrigal
* Date: 7/2/14
* Time: 10:23 AM
*/
class Events extends Eloquent {
protected $primaryKey = 'eventid';
public $timestamps = false;
protected $fillable = array(
'eventname', 'eventdescription', 'EventEnabled', 'visitcost', 'groupid', 'flagid', 'SundayStart', 'MondayStart', 'TuesdayStart', 'WednesdayStart', 'ThursdayStart', 'FridayStart',
'SaturdayStart', 'limit', 'Vtmpl', 'delayV', 'Etmpl', 'delayE', 'Ttmpl', 'delayT', 'Mtemp', 'delayM', 'Login', 'freqv', 'freqt', 'freqe', 'maxe', 'maxt', 'maxv',
'amtide', 'amtidt', 'amtidv', 'apptinterval'
);
public function aInterval() {
return $this->hasMany('AppointmentInterval');
}
}
More than likely you have not defined the mass-assignment attributes your Events Model.
So in your Events Model try:
protected $fillable = array('limit', 'EventEnabled', 'SundayStart', 'MondayStart', 'TuesdayStart', 'WednesdayStart', 'ThursdayStart', 'FridayStart', 'SaturdayStart');
This is a security feature of Laravel and helps to prevent against blindly allowing any attributes to be updated.
The type being sent "string" for any checkbox wasn't going in because the values needed to be an (int) value or a (bool) value of '1' or '0'. That was the issue. Database was set up a year ago by someone else and I didn't catch that until now. It's fixed though.
Related
all. I am working on a custom-build API built in PHP. I have an array (see below) that has been returned from my database access object. When I use the json_encode function, the int value assigned to phone1Type gets encoded incorrectly. I have tried this with multiple records, and the value in the encoded json object always matches the phone2Type. Any ideas as to what might be going on? (I've included two sample arrays below in addition to their corresponding json object.)
The code that I'm using to check the array and json values is the following:
$responseObject = $userCtrl->selectPersonForUserId($userId);
var_dump($responseObject);
var_dump(json_encode($responseObject));
One example array to encode is as follows. (The phone1Type and phone2Type keys are at the very end, but include the full array here for completeness. Also, as a side note, the other int values in the array are encoding fine.)
object(Adult)#13 (8) {
["person":protected]=>
object(Person)#14 (4) {
["id":protected]=>
int(3)
["firstName":protected]=>
string(7) "William"
["lastName":protected]=>
string(3) "Smith"
["hasVerified":protected]=>
bool(false)
}
["address":protected]=>
object(Address)#17 (4) {
["id":protected]=>
int(2)
["address1":protected]=>
string(15) "520 Hilbert Dr."
["address2":protected]=>
string(0) ""
["city":protected]=>
object(City)#18 (3) {
["zip":protected]=>
string(5) "71342"
["city":protected]=>
string(11) "West Monroe"
["state":protected]=>
string(2) "AL"
}
}
["email":protected]=>
string(14) "wmrmay#spam.com"
["phone1":protected]=>
string(10) "6195080000"
["phone1Type":protected]=>
int(1)
["phone2":protected]=>
string(10) "3188126574"
["phone2Type":protected]=>
int(0)
["teacher":protected]=>
NULL
}
This encodes to the following json object:
{"person":{"id":3,"firstName":"William","lastName":"Smith","hasVerified":false},"address":{"id":2,"address1":"520 Hilbert Dr.","address2":"","city":{"zip":"71342","city":"West Monroe","state":"AL"}},"email":"wmrmay#spam.com","phone1":"6195080000","phone1Type":0,"phone2":"3188126574","phone2Type":0,"teacher":null}
For brevity, here's the last few lines of another array followed by its json counterpart:
["email":protected]=>
string(20) "wltrallen2#gmail.com"
["phone1":protected]=>
string(10) "6192047586"
["phone1Type":protected]=>
int(1)
["phone2":protected]=>
NULL
["phone2Type":protected]=>
NULL
["teacher":protected]=>
NULL
"email":"wltrallen2#gmail.com","phone1":"6192047586","phone1Type":null,"phone2":null,"phone2Type":null,"teacher":null}
Edited to add original Adult.php model class:
class Adult implements JsonSerializable {
protected $person; // Person object
protected $address; // Address object
protected $email;
protected $phone1;
protected $phone1Type; // PhoneType object
protected $phone2;
protected $phone2Type; // PhoneType object
protected $teacher; // Teacher object
public function __construct($person, $address, $email, $phone1, $phone1Type, $phone2, $phone2Type, $teacher)
{
$this->person = $person;
$this->address = $address;
$this->email = $email;
$this->phone1 = $phone1;
$this->phone1Type = $phone1Type;
$this->phone2 = $phone2;
$this->phone2Type = $phone2Type;
$this->teacher = $teacher;
}
... // Getters and Setters removed for brevity
private function getPhoneType($type) {
if(PhoneTypes::isValid($type)) {
return PhoneTypes::StringDict[$type];
}
return '';
}
function jsonSerialize() {
$array = [
'person' => $this->person,
'address' => $this->address,
'email' => $this->email,
'phone1' => $this->phone1,
'phone1Type' => $this->phone2Type,
'phone2' => $this->phone2,
'phone2Type' => $this->phone2Type,
'teacher' => $this->teacher
];
return $array;
}
}
So, embarrassingly, this was just caused by an initial typo and then forgetfulness on my part.
In the Adult.php model class, I has implemented the JsonSerializable interface to make sure that an Adult object could be encoded in Json. When doing so, I made a typographical error when building the array:
'phone1Type' => $this->phone2Type,
which should have been, of course...
'phone1Type' => $this->phone1Type,
This typo was the source of my issue. Ugh!
However, as I've been deeply mired in this project and it had been some time since I originally built those model classes, I had completely forgot that for an object to be encodable by JSON that it had to implement the JsonSerializable interface. So, as I was debugging, it never occurred to me to look back in my model at the very end of the file to examine the jsonSerialize() function. (Insert face palm here.)
Thank you for your responses. This is the first time that I've actually gotten to post a question on stackOverflow, and I appreciate you all taking a look. Sorry that it wasn't an exciting question and merely a silly novice programmer moment.
I'm trying to cast an entity property into an array so that it autoserializes.
The Entity is set up as follows
\App\Entities\Submission.php
<?php
namespace App\Entities;
use CodeIgniter\Entity;
class Submission extends Entity
{
protected $casts =[
'field2' => 'array'
];
}
Then in a controller I create a new entity, filling it using the constructor
<?php
$allowedFromPost = [
'field1'=>'value1',
'field2'=>[0,1],
];
$submission = new \App\Entities\Submission($allowedFromPost);
?>
Dumping the submission at this point (var_dump()) shows field2 being an array, it's not serialised.
["attributes":protected]=>
array(2) {
["field1"]=>
string(6) "value1"
["field2"]=>
array(2) {
[0]=>
int(0)
[1]=>
int(1)
}
}
if I do
$allowedFromPost = [
'field1'=>'value1',
'field2'=>[0,1],
];
$submission = new \App\Entities\Submission($allowedFromPost);
$submission->field2 = $submission->field2;
and then var_dump, field2 is correctly serialised.
["attributes":protected]=>
array(2) {
["field1"]=>
string(6) "value1"
["field2"]=>
string(22) "a:2:{i:0;i:0;i:1;i:1;}"
}
For some reason, it seems like filling using the constructor does not autoserialize, I have to manually set the field. Am I doing something wrong?
The problem this caused is that when I tried inserting that entity into the Database, it threw an error saying
"mysqli_sql_exception Operand should contain 1 column(s)"
which went away when I flattened the array (first by dropping all but one values to test and then by using what I've done above)
================
EDIT 11/05: This turned out to be an issue on the core code. fill() (and the constructor) were not configured to use __set() so autoserialization was not happening. See the PR on Codeigniter's Github page here.
I'll be accepting Kulshreshth K's answer because, for now, this provides an adequate workaround but in the future it will most likely not be needed.
Add this in your Entity:
public function __construct($arr) {
$this->field2 = $arr['field2'];
}
Controller:
$allowedFromPost = [
'field1'=>'value1',
'field2'=>[0,1],
];
$submission = new \App\Entities\Submission($allowedFromPost);
var_dump($submission)
Result:
["attributes":protected]=>
array(2) {
["field1"]=>
string(6) "value1"
["field2"]=>
string(22) "a:2:{i:0;i:0;i:1;i:1;}"
}
As per CI documentation you need to set it after initialize its model anyway:
<?php namespace App\Entities;
use CodeIgniter\Entity;
class User extends Entity
{
protected $casts => [
'options' => 'array',
'options_object' => 'json',
'options_array' => 'json-array'
];
}
$user = $userModel->find(15);
$options = $user->options;
$options['foo'] = 'bar';
$user->options = $options;
$userModel->save($user);
I am developing a web application in laravel 5.3. The problem i am getting is that attributes doesn't add up in stdClass object, however you can see my code where i am explicitly setting/adding a new attributes in a object.
problematic code
1- $sender = Sender::where('id', $this->senderId)->first();
2- if ($sender != null) {
3- var_dump($sender->bundle);
4- $sender->bundle->latitude = $this->lat;
5- $sender->bundle->longitude = $this->long;
6- $sender->bundle->location = $response->formattedAddress();
7- var_dump($sender->bundle);
8- $sender->save();
9- error_log('resolved');
10- } else {
11- error_log('no sender');
12- }
In above code you can clearly see that i am setting some new properties for bundle object.
$sender->bundle->latitude = $this->lat;
$sender->bundle->longitude = $this->long;
$sender->bundle->location = $response->formattedAddress();
but in output you can clearly see that it doesn't get add up. The code basically runs in laravel queue. In above code $sender is laravel eloquent model and the attribute bundle is being json_decode via laravel mutators.
mutator code
public function setBundleAttribute($value) {
$this->attributes['bundle'] = json_encode($value);
}
public function getBundleAttribute($value) {
return json_decode($value);
}
output of above problematic code
object(stdClass)#686 (3) { #output of line 3
["city"]=>
string(0) ""
["province"]=>
string(0) ""
["country"]=>
string(0) ""
}
object(stdClass)#686 (3) { #output of line 7
["city"]=>
string(0) ""
["province"]=>
string(0) ""
["country"]=>
string(0) ""
}
[2017-07-25 16:11:03] Processed: App\Jobs\LocationResolverQueue
resolved
Problem Solved
laravel Accessors & Mutators cause the problem.
Accessor and Mutator get called whenever we get or set property respectively, in my case the mutator was calling whenever i try to access $sender->bundle->property however accessor didn't get called because i was setting a $sender->bundle->property rather than $sender->bundle
i solved problem like
$sender = Sender::where('id', $this->senderId)->first();
if ($sender != null) {
$temp = $sender->bundle;
$temp->latitude = $this->lat;
$temp->longitude = $this->long;
$temp->location = $response->formattedAddress();
$sender->bundle = $temp;
$sender->save();
}
We use Payone with our Magento shop. And we want to show our users warnings in their cart when their total amount is too large for a certain payment method.
That is why I want to check the total amount against each payment method max order value.
But somehow I can not reach the correct data.
When I try to get them by Payones config:
$methods = Mage::helper('payone_core/config')->getConfigPayment($store);
I get an object->array with all methods, but they are protected. So I can not use them in my cart module.
What is a clean way to get Payones payment methods (all active methods with their max_order_value)?
Edit:
I tried following code, but it still says:
Fatal error: Cannot access protected property
Payone_Core_Model_Config_Payment::$methods in
/pathToClass/CtaB2c/Helper/Data.php on line 20
class CtaB2c_Helper_Data extends Payone_Core_Helper_Config {
public function getConfigPayment($store) {
return parent::getConfigPayment($store);
}
public function showPaymentRestrictions() {
$quote = Mage::getSingleton('checkout/session')->getQuote();
$store = $quote->getStoreId();
$total = $quote->getBaseGrandTotal();
$methods = $this->getConfigPayment($store);
$methods = $methods->methods; //error occurs here: member has protected access
$avaibleMethods = array();
foreach ($methods AS $mid => $method) {
$minTotal = $method->minOrderTotal;
$maxTotal = $method->maxOrderTotal;
if($minTotal <= $total && $maxTotal >= $total) {
$avaibleMethods[$mid] = $method->code;
}
}
return $avaibleMethods;
}
}
I know, there is no check if this payment method is avaible, but actually I just want know if maxOrderTotal is bigger than payment methods max_order_total. And of course I do not need this extra function. I could call parent::getConfigPayment($store) in my function as well.
Edit 2
This is the object I get from getConfigPayment():
object(Payone_Core_Model_Config_Payment)#<a number> (1) {
["methods":protected]=>
array(6) {
[<a number>]=>
object(Payone_Core_Model_Config_Payment_Method)#<a number> (38) {
["id":protected]=>
string(1) "a number"
["scope":protected]=>
string(6) "stores"
["scope_id":protected]=>
string(1) "<a number>"
["code":protected]=>
string(15) "advance_payment"
["name":protected]=>
string(8) "Vorkasse"
["sort_order":protected]=>
string(1) "<a number>"
["enabled":protected]=>
string(1) "<a number>"
["fee_config":protected]=>
NULL
["mode":protected]=>
string(4) "test"
["use_global":protected]=>
string(1) "1"
["mid":protected]=>
string(5) "<a number>"
["portalid":protected]=>
string(7) "<a number>"
["aid":protected]=>
string(5) "<a number>"
["key":protected]=>
string(16) "<a key>"
["allowspecific":protected]=>
string(1) "0"
["specificcountry":protected]=>
array(0) {
}
["allowedCountries":protected]=>
array(2) {
[0]=>
string(2) "DE"
[1]=>
string(2) "AT"
}
["request_type":protected]=>
string(16) "preauthorization"
["invoice_transmit":protected]=>
string(1) "0"
["types":protected]=>
NULL
["klarna_config":protected]=>
NULL
["klarna_campaign_code":protected]=>
NULL
["paypal_express_image":protected]=>
NULL
["check_cvc":protected]=>
NULL
["check_bankaccount":protected]=>
NULL
["bankaccountcheck_type":protected]=>
NULL
["message_response_blocked":protected]=>
NULL
["sepa_country":protected]=>
NULL
["sepa_de_show_bank_data":protected]=>
NULL
["sepa_mandate_enabled":protected]=>
NULL
["sepa_mandate_download_enabled":protected]=>
NULL
["customer_form_data_save":protected]=>
NULL
["is_deleted":protected]=>
string(1) "0"
["minValidityPeriod":protected]=>
string(0) ""
["minOrderTotal":protected]=>
string(1) "1"
["maxOrderTotal":protected]=>
string(4) "1000"
["parent":protected]=>
string(1) "<a number>"
["currency_convert":protected]=>
string(1) "0"
}
You can always extend the payone_core/config class YourNameSpace_Module_Helper_Payone extends ThePayOneNamespace_Payone_Core_Config and basically get any method to be public
class YourNameSpace_Module_Helper_Payone extends ThePayOneNamespace_Payone_Core_Config
public function someProtectedParentMethod()
{
return parent::someProtectedParentMethod();
}
}
The above will allow you to use any protected method and get the data you are after.
This is hopefully the Magento way to get information about Payones Payment methods. You should call setPaymentRestrictionNoticeMessage() somewhere in your controller.
class YourModule_Helper_Data extends Mage_Core_Helper_Abstract {
/**
* Returns array of methods that will not work with current max order value.
* #return array
*/
public function getPaymentsWithRestrictions() {
$quote = Mage::getSingleton('checkout/session')->getQuote();
$store = $quote->getStoreId();
$total = $quote->getBaseGrandTotal();
/**
* #var Payone_Core_Model_Config_Payment $model
*/
$model = Mage::helper('payone_core/config')->getConfigPayment($store);
$methods = $model->getMethods();
$restrictedMethods = array();
foreach ($methods AS $mid => $method) {
/**
* #var Payone_Core_Model_Config_Payment_Method $method
*/
$minTotal = $method->getMinOrderTotal();
$maxTotal = $method->getMaxOrderTotal();
$isEnabled = $method->getEnabled();
if($isEnabled && ($minTotal > $total || $maxTotal < $total)) {
$restrictedMethods[$mid] = $method;
}
}
return $restrictedMethods;
}
/**
* Sets notification message with information about payment methods
* that will not work.
*/
public function setPaymentRestrictionNoticeMessage() {
$restrictedMethodModels = $this->getPaymentsWithRestrictions();
$restrictedMethods = array();
foreach ($restrictedMethodModels AS $methodModel) {
/**
* #var Payone_Core_Model_Config_Payment_Method $methodModel
*/
$restrictedMethods[] = $methodModel->getName();
}
Mage::getSingleton('core/session')->addNotice(
Mage::helper('checkout')->__(
'Your order value is too high for following payment methods: ' . implode(', ', $restrictedMethods)
)
);
}
}
Get the Payone config in your function:
$payoneConfig = Mage::helper('payone_core/config')->getConfigPayment($storeId);
In Payone_Core_Model_Config_Payment you can find all methods which you can call on $payoneConfig, e.g. getAvailableMethods(). Overwrite Payone_Core_Model_Config_Payment the Magento way if you want to add more functionality.
I'm trying to get a multi-dimensional array from an Entity.
Symfony Serializer can already convert to XML, JSON, YAML etc. but not to an array.
I need to convert because I want have a clean var_dump. I now have entity with few connections and is totally unreadable.
How can I achieve this?
You can actually convert doctrine entities into an array using the built in serializer. I actually just wrote a blog post about this today:
https://skylar.tech/detect-doctrine-entity-changes-without/
You basically call the normalize function and it will give you what you want:
$entityAsArray = $this->serializer->normalize($entity, null);
I recommend checking my post for more information about some of the quirks but this should do exactly what you want without any additional dependencies or dealing with private/protected fields.
Apparently, it is possible to cast objects to arrays like following:
<?php
class Foo
{
public $bar = 'barValue';
}
$foo = new Foo();
$arrayFoo = (array) $foo;
var_dump($arrayFoo);
This will produce something like:
array(1) {
["bar"]=> string(8) "barValue"
}
If you have got private and protected attributes see this link : https://ocramius.github.io/blog/fast-php-object-to-array-conversion/
Get entity in array format from repository query
In your EntityRepository you can select your entity and specify you want an array with getArrayResult() method.
For more informations see Doctrine query result formats documentation.
public function findByIdThenReturnArray($id){
$query = $this->getEntityManager()
->createQuery("SELECT e FROM YourOwnBundle:Entity e WHERE e.id = :id")
->setParameter('id', $id);
return $query->getArrayResult();
}
If all that doesn't fit you should go see the PHP documentation about ArrayAccess interface.
It retrieves the attributes this way : echo $entity['Attribute'];
PHP 8 allows us to cast object to array:
$var = (array)$someObj;
It is important for object to have only public properties otherwise you will get weird array keys:
<?php
class bag {
function __construct(
public ?bag $par0 = null,
public string $par1 = '',
protected string $par2 = '',
private string $par3 = '')
{
}
}
// Create myBag object
$myBag = new bag(new bag(), "Mobile", "Charger", "Cable");
echo "Before conversion : \n";
var_dump($myBag);
// Converting object to an array
$myBagArray = (array)$myBag;
echo "After conversion : \n";
var_dump($myBagArray);
?>
The output is following:
Before conversion :
object(bag)#1 (4) {
["par0"]=> object(bag)#2 (4) {
["par0"]=> NULL
["par1"]=> string(0) ""
["par2":protected]=> string(0) ""
["par3":"bag":private]=> string(0) ""
}
["par1"]=> string(6) "Mobile"
["par2":protected]=> string(7) "Charger"
["par3":"bag":private]=> string(5) "Cable"
}
After conversion :
array(4) {
["par0"]=> object(bag)#2 (4) {
["par0"]=> NULL
["par1"]=> string(0) ""
["par2":protected]=> string(0) ""
["par3":"bag":private]=> string(0) ""
}
["par1"]=> string(6) "Mobile"
["�*�par2"]=> string(7) "Charger"
["�bag�par3"]=> string(5) "Cable"
}
This method has a benefit comparing to Serialiser normalizing -- this way you can convert Object to array of objects, not array of arrays.
I had the same issue and tried the 2 other answers. Both did not work very smoothly.
The $object = (array) $object; added alot of extra text in my key
names.
The serializer didn't use my active property because it did not have is in front of it and is a boolean. It also changed the sequence of my data and the data itself.
So I created a new function in my entity:
/**
* Converts and returns current user object to an array.
*
* #param $ignores | requires to be an array with string values matching the user object its private property names.
*/
public function convertToArray(array $ignores = [])
{
$user = [
'id' => $this->id,
'username' => $this->username,
'roles' => $this->roles,
'password' => $this->password,
'email' => $this->email,
'amount_of_contracts' => $this->amount_of_contracts,
'contract_start_date' => $this->contract_start_date,
'contract_end_date' => $this->contract_end_date,
'contract_hours' => $this->contract_hours,
'holiday_hours' => $this->holiday_hours,
'created_at' => $this->created_at,
'created_by' => $this->created_by,
'active' => $this->active,
];
// Remove key/value if its in the ignores list.
for ($i = 0; $i < count($ignores); $i++) {
if (array_key_exists($ignores[$i], $user)) {
unset($user[$ignores[$i]]);
}
}
return $user;
}
I basicly added all my properties to the new $user array and made an extra $ignores variable that makes sure properties can be ignored (in case you don't want all of them).
You can use this in your controller as following:
$user = new User();
// Set user data...
// ID and password are being ignored.
$user = $user->convertToArray(["id", "password"]);