Setting an array of related models in Yii from form input - php

In Yii, the following doesn't work (the relation array remains empty) and doesn't return an error:
foreach ($data as $k => $relatedModelData){
//construct the related model from the data passed in
...
$model->arrayOfRelatedModels[] = $relatedModel;
}
Instead, I have to do this:
foreach ($data as $k => $relatedModelData){
//construct the related model from the data passed in
...
$tempArray[] = $relatedModel;
}
$model->arrayOfRelatedModels = $tempArray;
I am wondering why this is the case, or whether I have got something slightly wrong in the first example?

#o_nix is right, you should be getting the:
Indirect modification of overloaded property error. It's something i've come across a lot recently.
It means that Yii is returning you a magic attribute via the __get function, the object doesn't really exist on the class, and when you set this object it goes through the magic __set function. This means if you try and change something inside the object itself (inner array values for example) it has no idea what to do with them and so it throws up that notice and leaves it alone.
To get round this you did the right thing, modify a new local variable and set the whole object to this once you're done.
P.S
You might have your PHP configuration set to hide notices, which is why it's silent.
Hope that clears it up

Related

PHP - Getting Indirect modification of overload property has no effect when modifying object

I am loosing my mind here!
I'm getting this error when trying to do the following:
$adGroups = $adSet->getAdGroups($fields)->getArrayCopy();
BioCommandController::log("Syncing '{$adSet->{AdSetFields::NAME}}' groups: " . count($adGroups));
foreach($adGroups as $adGroup) {
echo "<pre>";
if($adGroup->conversion_specs[0]){
$adGroup->conversion_specs[0]['action_type'] = $adGroup->conversion_specs[0]['action.type'];
unset($adGroup->conversion_specs[0]['action.type']);
I have the object $adGroups, this object comes from facebook.
I need to modify the $key $adGroup->conversion_specs[0]['action.type'] to
$adGroup->conversion_specs[0]['action_type']
The reason is because i need to save this object on a mongoDB database, and it doesn't accept this key format!
I've tried to do the obivious, create the right key for the object and insert the content inside it, and then unset the key that i don't want, but it throws that error.
I'm really lost here, any solutions????
I've read several issues on this error but none of them helped me!
The extend ArrayObject solution doesn't work for me, because my classes already extend others (and it's from a framework, yii). So i don't want to do a huge jerry rick to extend it.
And i don't understand why this is not working, i've always done that and it used to work just fine, it's so off putting.
Thanks
I'm still not sure why that was not working, but i've changed my approach and at leat was able to do what i needed:
//We recreate the peace of the object that needs to be modified
$newKey = $adGroup->conversion_specs[0];
$data = $adGroup->conversion_specs[0]['action.type'];
unset ($newKey['action.type']);
$newKey['action_type'] = $data;
$adGroup->conversion_specs = $newKey;

Message "You should never see this warning." in Extbase-based Typo3 extension

I have an Extbase-based extension for Typo3, which has a hierarchical data model. I had to insert an additional layer to this model, ie the original structure was Project contains multiple items. Now, I have Project contains multiple sub-projects and Sub-project contains multiple items. Everything is modelled using MM-relation tables and works in the backend. I can add, remove, sort the sub-projects and items.
However, the fluid template does not show anything and if I pass eg the sub-Project to t3lib_utilities_debug::Debug, I get
You should never see this warning. If you do, you probably used PHP
array functions like current() on the
Tx_Extbase_Persistence_ObjectStorage. To retrieve the first result,
you can use the rewind() and current() methods.
when printing the ObjectStorage for the items. I assume that the MM-relation I added is somehow broken, but I cannot figure out how. Furthermore, it seems that the __construct method of the domain model is not called (I have added a debug output, which is not printed).
The enumeration works if I pass the result of a call to findAll of the repository, but it does not work for my filtered calls (which worked before I added the additional layer). The filtering method looks like eg for the item
public function findBySubProject(SubProject $p) {
$query = $this->createQuery();
$query->getQuerySettings()->setRespectStoragePage(false);
$query->matching($query->equals('subproject', $p));
return $query->execute();
}
As I said, the query yields results, but they are somehow broken wrt. their relations.
Any ideas how to fix that?
I don't know on which version of Extbase you're developing on.
But on TYPO3 4.6+ you should be aware of the object and reflection caching. During development you can disable this caching by:
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['extbase_reflection']['backend'] = 't3lib_cache_backend_NullBackend';
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['extbase_object']['backend'] = 't3lib_cache_backend_NullBackend';
Since your problem has something to do with modifications in your model you should try to truncate the tables cf_extbase_object, cf_extbase_object_tags, cf_extbase_reflection and cf_extbase_reflection_tags after any change.
If this doesn't help you to resolve your problem then you should give us more insight about your configuration (especially the TCA configuration because Extbase rely on it).
How to test a Extbase QueryResult
$items = $this->itemRepository->findAll();
echo count($items);
if ($items) {
echo '<pre>';
foreach ($items as $item) {
print_r($item);
}
echo '</pre>';
}
-- edit --
Did you define the field subproject in your TCA? It should be atleast available as type passtrough:
'subproject' => array(
'config' => array(
'type' => 'passthrough',
),
),
I case someone else encounters the same issue: I accidentally used an object without items as test object. If you try to enumerate/debug/display an empty ObjectStorage, the warning is printed.

Need to access associative array data created inside a class by json_decode from outside the class

I've been using procedural php for a long time but am still learning OOP. I was able to find a bit of code online that is in the form of a class and I am able to call a new instance of the class and use var_dump on a string to have it print JSON data to a web page. I can look at the results of the var_dump and see that it's returning exactly what I want. I'm then able to use json_decode on the same string to turn it into and associative array and then I can echo the values from within the class. The problem is, I need to use the array values in more code - it's great that I can confirm it by printing it to a web page but I need to use it... but I'm getting errors that state the array is undefined once I try to access it outside of the class.
I'm using this line to convert the data into an array:
$response_array = json_decode($body, true);
I've already confirmed that this works within the class by using this code to print some of the data:
echo $response_array['amount'];
and it works - I see it on the web page.
I've been using this code to create the new instance of the class:
$fdata = new FData();
$fdata->request($order_total, $cc_exp, $cc_number, $cc_name, $order_id, $customer_id);
(the function named 'request' is defined as a public function inside the class)
After that, I want to grab the $response_array so that I can store the returned data into a transactions table, i.e something like this:
$r = mysqli_query($dbc, "CALL add_transaction($order_id, $response_array['transaction_type'], $response_array['amount'], $response_array['exact_resp_code'], $response_array['exact_message'], $response_array['bank_resp_code'], $response_array['bank_message'], $response_array['sequence_no'], $response_array['retrieval_ref_no'], $response_array['transaction_tag'], $response_array['authorization_num'])");
but I keep getting an error saying that the array values are undefined.
Things I have already tried (and which failed) include:
Defining the variables as public inside the class, setting their value in the class, and then calling them outside the class...
public $amount = $response_array['amount'];
then using $amount in my procedure CALL --- I still get the error saying that $amount is undefined.
Using 'return', as in
return $response_array;
and still the error saying the values are undefined.
I tried embedding the entire rest of my code within the class, just copy/paste it in right after the json_decode... but for some reason it can't seem to then make the database calls and other things it needs to do.
I've been reading about __construct but I'm not sure if it applies or how to use it in this case...
I want to stress that I AM able to see the results I want when I use var_dump and echo from within the class.. I need to access the array created by json_decode OUTSIDE of the instance of the class.
Any advice would be greatly appreciated. Thanks.
Assuming your FData::request method ends with something like this...
$response_array = json_decode($body, true);
return $response_array;
and you call it like this...
$response_array = $fdata->request(...);
You should then be able to use $response_array in the calling scope.
Extra note; you should be using prepared statements with parameter binding instead of injecting values directly into your SQL statements.

set models based on condition in cakephp queries

This is probably very easy to do, but I can't seem to get my head around it right now. Let's say in a component in a cakephp application, I have a variable my_model, which contains the model of the corresponding controller that is currently using the component like:
function TestComponent extend Object
{
var $my_model; // can be either User, or Person
function test()
{
$myModelTemp = $this->my_model;
$model = $myModelTemp != 'User' ? $myModelTemp.'->User' : 'User';
$this->$model->find('all');
}
}
As you can see above in my function test() what I'm trying to do is call the correct model based on the value of my_model. So based on the condition, my query will be either:
$this->Person->User->find('all');
Or
$this->User->find('all');
When I do it like I did above, I get an error saying Fatal error: Call to a member function find() on a non-object. In order words, that error means Person->User is not an object (so, it is considered as a string).
What you're saying could be true, however, it can refer to any part of the call.
So either Person or User could be invalid, or together they causes the error. Hard to say.
Try dumping the individual objects using var_dump();
So try:
<?php
echo "<pre>";
var_dump(is_object($this->Person));
var_dump(is_object($this->User));
echo "</pre>";
?>
to determine where you're code goes wrong.
To be clear, that return value needs to be true for it to be an object.
The one that returns false is the likely culprit.
Should your question refer to the correct way to reference an object, an object is basically an array. For example:
<?php
$obj = (object) array("this", "my_function");
?>
The above example casts the array as an object. However, using multiple layers might prove to be more difficult than you'd expect.
Generally, it looks like you might be going about this all wrong. Obviously you want the models to be dynamic, but then you're hard-coding things which defeats the whole point of it being dynamic in the first place.
It also seems like you might be violating the principals of CakePHP and MVC by doing all this in a component. I'm not sure this component should really be manipulating models or assuming which models are currently in use.
However, if you want to evaluate a string as an actual object, you can wrap it in { ... } (this is valid standard PHP syntax, not Cake-specific code).
Try this:
$modelName = $this->my_model;
$model = ($modelName != 'User') ? $this->{$modelName}->User : $this->User;
$model->find('all');
Now, if this doesn't work or you get an error saying it can't find the model(s) you need to ensure the models are actually loaded and initialised in the current scope.

foreach $key=>$value to set ZF form values / OOP PHP

I currently have the following code in a ZF application, to set the values of a Form based on a rowset retrieved from a Db-Table.
$form->forename->setValue($footerContactDetails->forename);
$form->surname->setValue($footerContactDetails->surname);
$form->telephone->setValue($footerContactDetails->telephone);
$form->mobile->setValue($footerContactDetails->mobile);
$form->fax->setValue($footerContactDetails->fax);
$form->email->setValue($footerContactDetails->emailAddress);
$form->address1->setValue($footerContactDetails->address1);
$form->address2->setValue($footerContactDetails->address2);
$form->address3->setValue($footerContactDetails->address3);
$form->townCity->setValue($footerContactDetails->townCity);
$form->region->setValue($footerContactDetails->region);
As the object element names from the rowset match the form elements, what I'd like to do is the following:
foreach ($footerContactDetails as $key=>$value) {
$form->$key->setValue($value);
}
However this provides the following error message:
Fatal error: Call to a member function setValue() on a non-object
I expect this question is more related to OOP PHP in general and not the just ZF.
So how can I set these form values using a foreach?
Many thanks
The foreach is fine, but the names dont match:
$form->email->setValue($footerContactDetails->emailAddress);
So, when iterating over $footerContactDetails, your code will eventually try to
$form->emailAddress->setValue()
but since there is no element of that name in the Zend_Form (it's called email instead), you'll get the error. So change it accordingly and it will work.
On a sidenote, Zend_Form has a method for bulk setting:
$form->populate((array) $footerContactDetails);
It expects an array though, hence the typecast.
Try this:
foreach($footerContactDetails as $key=>$value){
$form->{$key}->setValue($value);
}
Foreach over object variables takes all variables. That means primitive types too. Since primitive type is not an object, you cannot call method on it.
I suggest you use is_object() to check if variable is an object before calling a method, or maybe even think of a different approach.
Did you try something like this?
foreach ($footerContactDetails as $key=>$value) {
$form->${$key}->setValue($value);
}

Categories