Welcome Guest, Not a member yet? Register   Sign In
Entity with Model finder (custom setters)
#1

(This post was last modified: 10-09-2022, 04:54 AM by ozornick.)

I decided to get rid of dynamic properties in objects and added setters/getters
Now when the Model is executed, my new private properties are not initialized
// Role
private string $role;
private string $title;
private array $rules = [];

I found the reason in generating the result:

// vendor/codeigniter4/framework/system/Database/MySQLi/Result.php
protected function fetchObject(string $className = 'stdClass')
{
if (is_subclass_of($className, Entity::class)) {
return empty($data = $this->fetchAssoc()) ? false : (new $className())->setAttributes($data);
}

return $this->resultID->fetch_object($className);
}

Thus, setters are not used.
How can this behavior be corrected? Overload the setAttributes() method?

I found commit from iRedds https://github.com/codeigniter4/CodeIgni...35814e8dcc
What was the reason for this introduction?

P.S Sorry for the formatting - the post editor on the forum is broken.
Reply
#2

Maybe return solution? And ohter drivers


PHP Code:
        if (is_subclass_of($classNameEntity::class)) {
            return empty($data $this->fetchAssoc()) ? false : (new $className())->fill($data)->syncOriginal();
        

If you completely remove the check on the Entity (and the private class), then fetch_object () does not call setters, it will immediately assign values to private properties. Therefore, the situation needs to be corrected.

If I do fill() then everything works fine - private properties are set and $attributes are filled in my setters
Reply
#3

Entity is a row from a database table.
Therefore, when retrieving data from the database, we put it in the entity in an unchanged state.

Entity setters are needed in order to convert data into the format in which they are stored in the database.
Getters, on the contrary, convert raw data into the required format.

I will give a simple example.

For example, we have a User entity that defines a setter for hashing a password.

PHP Code:
class User extends Entity 
{
    public function 
setPassword(string $value)
    {
        
$this->attributes['password'] = password_hash($value);
    }
}

$user = new User();
$user->password $request->getPost('password'); 

If we do as you suggest, then each time the user data is retrieved from the database, the saved password hash will be changed.
Reply
#4

Yes, that's right, immutable data.
But how do I apply my class properties?
private $password

solved a problem


PHP Code:
    public function getPassword(): string
    
{
        return $this->password;
    }

    public function setPassword(string $password): self
    
{
        $this->password $this->attributes['password'] = $password;

        return $this;
    

or otherwise, but I can't set private class properties - that's the main problem
Reply
#5

The Entity is not what you want.
It just represents a database row and uses dynamic properties.
Reply
#6

Why not go further and use normal entities like Doctrine in the DDD pattern?
Reply
#7

You are just confusing CI4's Entity and Doctrine Entity or DDD Entity.
They are just different things but have the same name.

If you want to use Doctrine, you can freely use it with CI4.
And Doctrine's Entity is NOT Entity in DDD.
Reply
#8

Maybe I didn't put it that way. I like to have a whole entity and work with a domain model. And not just a line of the table. having special behavior is good otherwise why create getters if setters are forbidden? Just need to allow fill() on query, if you want to hard save attributes, do it after setAttibutes().
Reply
#9

@ozornick Sorry, I don't get what you say.

If you want to do DDD, I recommend you do not use the CI4'e Entity as Entity in DDD.
They have nothing to do with each other.

CI4 Entity has some problems because of the design flaw.
But fixing it will be a breaking change. So it is not so easy.

Probably it is better to write your own new Entity class,
or send it as a PR if it can be good for many CI4 users.
Reply
#10

(This post was last modified: 11-13-2022, 12:30 AM by ozornick.)

I understand that you do not review the current state of the Entity. All that is needed for a working version is to add a fill(), allowing the setters.
Other properties/relations can be added in events (now I call afterFind() for each object to call fill() as a workaround)
P.S. I use a translator, some phrases may be incomprehensible, sorry

To create a personal entity, we need to rewrite the system files so that they also distinguish a simple object from a new entity. So I didn't invent anything.

Are there any really serious problems with entities that are being interfered with by fill() + setters? In addition to setting a password - I think the password should not be hashed in the setter. There are events or manually $o->__set(password_hash(...))

Another reason to use it as an object is to have normal properties (not magic). Because of them, there are other problems, for example, if the property contains an array.
Reply




Theme © iAndrew 2016 - Forum software by © MyBB