spotorm / spot2

Spot v2.x DataMapper built on top of Doctrine's Database Abstraction Layer
http://phpdatamapper.com
BSD 3-Clause "New" or "Revised" License
601 stars 101 forks source link

Not overwrite some fields in entity when updating (put, patch) #240

Closed manelj closed 6 years ago

manelj commented 7 years ago

Is the any solution to load data into entity excluding the fields that you don't allow to be overwritten? ` $body = $request->getParsedBody();

$tarea->clear();

$tarea->data($body);

$resultadoSave = $this->container["spot"]->mapper("App\Modelos\Tarea")->save($tarea);

` After this code, i don't want that fields 'tar_id' and 'tar_uuid' can be overwritten if user has send it via json post method.

willemwollebrants commented 7 years ago

I think it's a bad idea to just pass the userdata to the object without any checks. A more defensive approach would be to explicitly define what keys can be set (along with some validation probably). Could be quite simple:

$body = $request->getParsedBody();

$allowedKeys = ['title', 'content'];

foreach (array_keys($body) as $key) {
    if (!in_array($key, $allowedKeys)) {
        unset($body[$key]);
    }
}
FlipEverything commented 7 years ago

You can do what @willemwollebrants recommended or you can define rules using the integrated Event Emitters. Put something like this in the Entity definition:

// untested code
public static function events(EventEmitter $eventEmitter)
  {
      $eventEmitter->on('beforeSave', function (Entity $entity, Mapper $mapper) {
          $oldUUID = $entity->dataUnmodified('tar_uuid');
          $newUUID = $entity->tar_uuid;
          if ($oldUUID !== null) { 
            $entity->tar_uuid = $oldUUID;
          }
      });
  }

This way the user cannot change the tar_uuid after it was first set.

willemwollebrants commented 7 years ago

Or ... :) you can define a setter for the fields in your Entity class, something like:

public function setTarUuid($value){
  if (is_null($this->tar_uuid){
    this->tar_uuid = $value;
  }
}

The upside here is that you don't have to wait for the beforeSave event. The tar_uuid becomes fixed after it was first set, whether or not or not the object has been saved.

Getters/setters are not that well documented, but the rules are pretty simple. If there's a function called set + the camel case version of the variable name, it will be called when you set the value for this variable (even if you use the data() method)

FlipEverything commented 6 years ago

Closing this issue, because of the inactivity. Feel free to reopen this if you have more questions regarding this subject.