gabordemooij / redbean

ORM layer that creates models, config and database on the fly
https://www.redbeanphp.com
2.31k stars 279 forks source link

"R::useJSONFeatures(true);" json decode #591

Closed flip111 closed 6 years ago

flip111 commented 7 years ago

I use R::useJSONFeatures(true); i was expecting that it would also decode json from the database, have i done something wrong or have i suppose to put json_decode on all the json fields? I also tried to do this with open method from FUSE, but i couldn't get this to work.

gabordemooij commented 7 years ago

At this moment only JSON column creation and json encoding are supported. JSON decoding is not supported yet (due to thje nature of RedBeanPHP this is also quite a challenge, since it either has to scan the text to determine whether it's JSON which is impossible or it has to query the table structure, which is very expensive).

flip111 commented 7 years ago

How can i use json_decode on some fields in FUSE methods? I tried

public function open() {
  $this->bean->field = json_decode($this->bean->field, true);
}

i wasn't very successful, but maybe i rushed it

flip111 commented 7 years ago

Took some more time to verify this problem

<?php

use RedBeanPHP\OODB;
use RedBeanPHP\R;
use RedBeanPHP\SimpleModel;

require_once __DIR__.'/../vendor/autoload.php';

class Testbean extends SimpleModel {
  private $hello;

  public function open() {
    echo $this->bean->info . PHP_EOL; // "[1, 2]"
    $this->bean->info = json_decode($this->bean->info, true);
  }
}

define('REDBEAN_MODEL_PREFIX', '');
R::setup('sqlite::memory:');
R::setAutoResolve(true);
R::useJSONFeatures(true);
R::usePartialBeans(true);
OODB::autoClearHistoryAfterStore(true);  // https://redbeanphp.com/index.php?p=/meta_data

$bean = R::dispense('testbean');
$bean->info = [1,2];
R::store($bean);

$first_bean = R::load('testbean', 1);

// Not getting a model from load() getting a bean instead, don't know why
echo get_class($first_bean) . PHP_EOL; // RedBeanPHP\OODBBean

// getting the info field
var_dump($first_bean->info); // still the string "[1, 2]" instead of an array

Two problems occur here

flip111 commented 7 years ago

I think i will not use this feature for now and handle the encode and decode in my model, this way the usage is symmetrical (instead of having to remember to put json_decode everywhere).

Lynesth commented 6 years ago

Just a note on this:

Redbean does not give back the model class instead if have to box() it explicitly.

This is intended.

Deserializing the json field in the open() method doesn't have any effect it seems.

Actually, this is working. But since you're using R::useJSONFeatures(true);, when you try to assign an array to the property (which is what your json_decode is returning), it converts it back to JSON. You would need to deactivate it at the start of the open() function and then reactivate it at the end.

In the end I think you made the right choice manually encoding and decoding your JSON.

Lyn.

flip111 commented 6 years ago

Thanks for the explanation @Lynesth

One other assumption i did (incorrectly as it appears) is that serialization would happen on persisting (UPDATE / INSERT) not on assignment. These behaviours should be made explicit imo. it's not mentioned here

I don't understand the design decision to require explicit box(). Isn't it so that if you have an empty model (that is a class without implementation) that it remains the same behaviour of a bean? If so it could be just a drop in replacement for the bean parent class. On this page it doesn't actually say so explicitly that this is what happens. Actually from all the wording like RedBeanPHP automatically connects beans with models using a naming convention (i.e. Model_{TYPE OF BEAN}). Makes me belief i don't have to do anything else for this to work. Maybe there could be a configuration to box automatically?

One other thing is that i think redbean should save some information in the freeze stage so things like json_encode can be supported (my preferred format would be a generated php file that loads quickly). I would make this an optional thing that can be used to build additional features which are not possible now.

I will close this now as the original question has been answered.