Questions should go to https://forum.phalconphp.com
Documentation issues should go to https://github.com/phalcon/docs/issues
Describe what you are trying to achieve and what goes wrong.
Setting up a model with a simpleforeach...$this->{$key} = $value;overwrites already set fields.
_Totally messes up recursively._
Provide output if related
// paste output here
// expected:
array (
'id' => NULL,
'name' => 'cottton',
)
array (
'id' => NULL,
'name' => 'Foo',
)
// actual
array (
'id' => NULL,
'name' => 'cottton',
)
array (
'id' => NULL,
'name' => 'shit!',
)
Provide minimal script to reproduce the issue
CREATE TABLE `robots` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(70) NOT NULL,
PRIMARY KEY (`id`)
);
class Robot extends Phalcon\Mvc\Model
{
public function getSource()
{
return 'robots';
}
public function setData($data)
{
foreach ($data as $key => $value) {
$this->{$key} = $value;
}
return $this;
}
}
$robot = new \Robot();
$robot->name = 'cottton';
echo var_export($robot->toArray(), true) . PHP_EOL; // name === cottton
$robot->setData(
[
'name' => 'Foo', // actual name expected to be set.
//problems:
// if providing (on purpose or not) an array ...
// with any offset (numeric, string, w/e)
'any_offset' => [
// and in here is the same offset as on parent (i.e. "name")
// then robot will be named:
'name' => 'FU',
// except another array is given (on purpose or not)
// with any offset EXCEPT the offset before (i.e. "any_offset")
'any_offset_but_"any_offset"' => [
'name' => 'FU2',
],
// ... recursively
'and_so_on ...' => [
'well ...' => [
'name' => 'this is fucked up',
],
],
'and_so_on ... ...' => [
'well 1' => [
'well 2' => [
'well 3' => [
'well 4' => [
'well 5' => [
'well 6' => [
'name' => 'shit!',
],
],
],
],
],
],
],
],
]
);
echo var_export($robot->toArray(), true) . PHP_EOL;// name === shit!
phalcon info)Phalcon DevTools (3.0.3)
Environment::
OS: Linux medev-accounting-app-1 4.4.0-53-generic #74~14.04.1-Ubuntu SMP Fri Dec 2 03:43:31 UTC 2016 x86_64
PHP Version: 7.0.11
PHP SAPI: cli
PHP Bin: /usr/local/bin/php
PHP Extension Dir: /usr/local/lib/php/extensions/no-debug-non-zts-20151012
PHP Bin Dir: /usr/local/bin
Loaded PHP config: /usr/local/etc/php/php.ini
Versions::
Phalcon DevTools Version: 3.0.3
Phalcon Version: 3.0.1
AdminLTE Version: 2.3.6
PHP Version: (php -v)
PHP 7.0.11
Operating System:
Ubuntu 14.04
Server: Nginx | Apache | Other
Nginx
Other related info (Database, table schema):
NA
it happens even without the foreach $robot->random = ['name' => 'cottton']; will result the same
also, the related code
It's known problem and it's expected behaviour. As you see phalcon expects property to be relation if it's provided as a string.
@Jurigag why would it be expected behavior, what if I'm holding a simple array and on save event doing stuff? should it be used with real field?
Just use setter. Magic methods are used for setting relations. As i wrote, it is a bug in my opinion,
but it's expected behavior right now.
Any chance to get a workaround?
As @elibyy mentioned the before -actions would be kind of _useless_: https://docs.phalconphp.com/uk/latest/reference/models.html#initializing-preparing-fetched-records
I dont see any checks if any relations has been set up. Imo it should be checked if the current model has relations (::belongsTo, ...).
If no relations ever set then it should act as expected: property = value where value is array, string, int or w/e.
Looking a the code i see no chance to get this working from our side (PHP).
Because all ends up in the __set method :( .
@cottton i agree too, for now you can override the__set method and pass to parent::__set based on your logic
As i wrote - just use setter.
Just tried that ;)
added
public function __set($key, $value)
{
$this->{$key} = $value;
}
But if im not calling set($key, $value) (which i cant because would get same result)
what could go wrong?
Obviously no relations would work. And what else?
Like this:
$model->setRandom(['name' => 'cottton']);
Will work without any problem :)
Also will give small boost performance. Always set all properties and add getters and setters
@Jurigag with many models and many fields this could take days to add that for every model.
Also wil be a pain in the * on upgrades/updates.
Then use IDE. Im adding setters and getters in 1-2 seconds for all propeties.
@cottton you can use call_user_func_array[$this,"set{$key}"],$value)
So like you saw - not a bug, i guess current behaviour won't change and i'm fine with that. Cause you should ALWAYS set properties and use getters and setters like there is two options:
Other solutions are your mistake(like not setting properties at all) and they are just wrong, in other languages you would have error. Just magic methods are really worst thing which could happen to php. Especially __set and __get.
@Jurigag No offence but you guys added the magic method here https://github.com/phalcon/cphalcon/blob/master/phalcon/mvc/model.zep#L4172
If you think this is the worst thing ever happen to PHP why it found its way into the model?
:)
Anyway - found a solution:
https://github.com/phalcon/cphalcon/blob/master/phalcon/mvc/model.zep#L452
public function setData($data)
{
$this->assign($data);
return $this;
}
Atm seems to do what i expected without overwriting the phalcon model setter.
Beacause it's used for setting relations in framework, it's not supposed to be used by people. I didn't added it, it was from beginning like this. This is not solution. The solution is this as i wrote:
Well other than that i don't know why you need this method. You can just call assign without this method, but this is not a solution. YOU MUST HAVE PROPERTIES IN YOUR CLASSES ANYWAY, as well as setters if they are private/protected. If you don't have then it's your mistake and your code is shit.
it's not supposed to be used by people
oO? _if you meant the __set method then forget the rest below_
Assigns values to a model from an array
Its public function.
I see no relation -related code in there.
This seems to be a very "extended" version of the setData method im using.
Data, mapping, whitelist.
Actually this code https://github.com/phalcon/cphalcon/blob/master/phalcon/mvc/model.zep#L452
does exactly what i need.
Then use it. Just remove this setData and use assign alone :)
I mean you should not use __set or any other magic thing for your app to work. You should have public properties and/or getters/setters anyway. Using __set to setting your properties is just bad architecture and it's mistake.