$winnerBid = Bids::model()->find($criteria);
Model has next relations:
public function relations() {
return array(
'item' => array(self::BELONGS_TO, 'Goods', 'item_id'),
'room' => array(self::BELONGS_TO, 'Rooms', 'room_id'),
'seller' => array(self::BELONGS_TO, 'RoomPlayers', 'seller_id'),
'buyer' => array(self::BELONGS_TO, 'RoomPlayers', 'buyer_id'),
);
}
When I am trying to save:
$this->seller->current_item++;
$this->seller->wins++;
$this->seller->save();
I am getting error:
Indirect modification of overloaded
property Bids::$seller has no effect
(/var/www/auction/www/protected/models/Bids.php:16)
But it was everything fine at another server?
How to fix it? Or override php directives? Any ideas? TNX
The problem here is that $seller is not a "real" property (Yii implements properties on its Models by using the magic __get method), so in effect you are trying to modify the return value of a function (which has no effect). It is as if you tried to do:
function foo() {
return 42;
}
// INVALID CODE FOR ILLUSTRATION
(foo())++;
I 'm not sure about the status of this behavior on different PHP versions, but there is an easy workaround you can use:
$seller = $this->seller;
$seller->current_item++;
$seller->wins++;
$seller->save();
I was also having the error message "Yii Indirect modification of overloaded property" when trying to massively manipulate attributes using the CActiveRecord attributes property.
Then, I discovered another method to overcome this issue, in a case where the magic method is related to an object variable which contains an array take a look: you create an AUXILIARY ARRAY in which you put the original and the new values (sometimes one wants to REPLACE a value related to one of the keys, and these methods are not satisfactory). And AFTERWARDS use an assignation, which works like the reference. For example:
$auxiliary_array = array();
foreach(Object->array_built_with_magic as $key=>$value) {
if(….) {
$auxiliary_array[$key] = Object->array_built_with_magic[$key];
} else if (…) {
$auxiliary_array[$key] = $NEW_VALUE
}
}
//So now we have the array $auxiliary_array with the
// desired MIX (that is, some originals, some modifications)
//So we will do now:
Object->array_built_with_magic =$auxiliary_array;
I had this error on yii when upgrade to php8.1,
it was in createCommand() method.
and it didn't complain in former version of php, that we access a property on model which hasn't been initialized.
the workaround was to change the bindParam() method to the bindValue().
because the former wanted to use corresponding database field which has not been initialized yet.
but the later (bindParam) just insert the value in the sql statement.
Related
I have this function that receives a "user" model by parameter , I want to collect the properties of that object, for this I do it this way, the code works for me but the editor "phpstorm" complained to me with this error and it was to know what would be the best way to do this.
Thank you
public function sendEmail(User $user)
{
$params = [
'name' => "{$user->completeName}",
'language' => "{$user->locale}",
'user_id' => "{$user->id}"
];
}
Field accessed via magic method less... (Ctrl+F1)
Inspection info: Referenced field is not found in subject class. Note: Check is not performed on objects of type "stdClass" or derived.
Thanxs,
maybe this is simpler
$params = $user->toArray();
or
$params = $user->toJson();
That's because in Laravel your model does not actually have the properties defined.
In PHP there is the concept of magic methods though ( http://php.net/manual/en/language.oop5.overloading.php#object.get ), where the __get() method allows you to basically intercept the access to an otherwise inaccessible (or non-existing) property.
This is what happens behind the scenes in Laravel. All your property accesses are "intercepted" and Laravel looks if your database contains a column which is named like the property you are trying to access (very simplified speaking).
In a Laravel context you can savely ignore this warning.
Here's a test file:
class MyTest extends CDbTestCase
{
public $fixtures = array(
'my_data' => 'MyData',
);
public function testMyFunction()
{
$myObjectNotInDefaultScope = $this->my_data('out_of_scope_object');
//Can't do anything with $myObjectNotInDefaultScope since it returns null
// Is it possible to use resetScope?
// I can always set a primary key for the object and use findByPk but that's a hack
}
}
and here's the corresponding fixture:
<?php
return array(
'out_of_scope_object' => array(
'title' => 'This one is out of scope',
'status' => 'archived', // so not in the default scope
),
'in_scope_object' => array(
'title' => 'This one is in scope',
'status' => 'active',
),
);
Both rows in the fixture are added to the db table, so that's not the problem. I can access both rows via the primary keys that they're allocated. But I can't access the out of scope object in this way:
$myObjectNotInDefaultScope = $this->my_data('out_of_scope_object');
which when you're testing is really how you want to access it, I think.
I have a less than satisfactory solution in use for now of allocating the object a primary key value and using findByPk (edit: with resetScope()) to load the object. I would prefer to use the normal way of working with fixtures instead, if that's possible.
Edit: To clarify a little in response to some posts:
It is possible to use fixtures as a method to return an object. This would work:
$myObjectInDefaultScope = $this->my_data('in_scope_object');
but this wouldn't work BECAUSE it's not in the default scope and there's seemingly no way currently of running resetScope() for a fixture method call:
$myObjectNotInDefaultScope = $this->my_data('out_of_scope_object');
Why do I need to do this? Well, I might want to test my unarchive method, for example. Seems reasonable to me. (As mentioned before, I can get round this a little inelegantly by using a primary key to load the object corresponding to the fixture).
Although I can access the fixture data as an array using:
$arrayNotInDefaultScope = $this->my_data['out_of_scope_object'];
it's returning an array not an object, so I can't test the object's methods on an array.
To answer my own question, there is currently no way to use resetScope() with Yii fixtures (v 1.14). It could be implemented with some effort but given that Yii2 is on its way, it's probably not worth the effort of generating a pull request that may never make it in to the source.
For now, IMO, the cleanest workaround is:
1) Define a primary key in the fixture
2) Get the primary key from the fixture array and look up the object using it:
$arrayOutOfScopeObject = $this->my_data['out_of_scope_object'];
$myObjectNotInDefaultScope = MyObject::model()
->resetScope()
->findByPk($arrayOutOfScopeObject['id']);
You could, of course, save yourself the effort of looking up the pk from the fixture by hard-coding the pk value in your test code, but that leaves your test code vulnerable to being broken by changes to a fixture that's shared with other tests.
You are using the fixtures as a method, whilst it is an array of object.
So instead of:
$myObjectNotInDefaultScope = $this->my_data('out_of_scope_object');
You should be doing:
$myObjectNotInDefaultScope = $this->my_data['out_of_scope_object'];
Check the guide for more info
I'm using php activerecord. I need initialize a Order object and then set related objects as show below
$order = new Order();
Order->_plan = Plan::find(1);
I get the error Undefined property: Order->_plan in /var/www/ordenes-web/core/libs/php-activerecord/lib/Model.php on line 428
My class:
class Order extends ActiveRecord\Model{
static $belongs_to = array(
array(
'_plan',
'class_name' => 'Plan',
'foreign_key' => 'plan'
),
);
}
The relationship works fine. If I find an Order with the finder I get the related object _plan:
Order::find(1)->_plan // Works!
What am I doing wrong?
The problem is that ActiveRecord not support this behavior. You can see here
This line
Order->_plan
Really doesn't mean anything. You can find the properties of an object, for instance, your $order object.
This line means you are making an object and then finding the _plan property. Which is good.
Order::find(1)->_plan // Works!
To do this with an object, you should do
$order = Order::find(1);
var_dump($order->_plan;) // should work!
Now you can change stuff in your _plan (if it is there), like
$order->_plan->world = "Hello".
Now you should remember that you set the relationship in you objects, so that's is how they are reached. You're not supposed to created objects like this I think.The example you say that works does something like
find the order with id 1.
get its plan.
But your example that doesn't work does something else
find a new order
assign the plan with id 1 to that order.
The last part doesn't work like that I think, see this link that #Overflow012 posted.
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
My question is a follow up to the following question: What does it mean to start a php function with an ampersand?
The example code used in the question is this:
class FacebookRestClient {
...
public function &users_hasAppPermission($ext_perm, $uid=null) {
return $this->call_method('facebook.users.hasAppPermission',
array('ext_perm' => $ext_perm, 'uid' => $uid));
}
...
}
Why would a reference be necessary when we already have a reference ($this)?
The chosen answer quotes the following from the PHP manual on Returning References
Returning by reference is useful when you want to use a function to find to which variable a reference should be bound. Do not use return-by-reference to increase performance. The engine will automatically optimize this on its own. Only return references when you have a valid technical reason to do so.
The second answer gives a reason why this technique was needed in PHP4. But I don't find the answer for why it is needed in PHP5 very convincing.
Does anybody know of any valid reason(s) for using this technique in PHP5?
Yeah, here's an example from my codebase.
I have a "factory" class for each model, such as UserFactory. When I call UserFactory::findOne() I return a reference to the model, which is stored in an array in UserFactory.
I do this so that if I get the user model and modify something in it, and then get it again later in my code, it is updated with the new information even though I never went back to the database.
For example:
<?php
$user = UserModel::findOne([ '_id' => 151 ]);
$user->status = 'disabled';
// Much later
$user = UserModel::findOne([ '_id' => 151 ]);
if ( $user->status != 'disabled' ) {
// Do stuff
}
Returning by reference is a good way of accomplishing this without making two calls to my database.