php - Symfony3 – Form submission with clearMissing – nullified properties always – how to fix this? -
i'm using "symfony ~3.3".
if send in request bar
property (without zyx
because don't need change it), error:
type error: argument 1 passed appbundle\entity\foo::setzyx() must of type string, null given, called in /full/path/to/project/vendor/symfony/symfony/src/symfony/component/propertyaccess/propertyaccessor.php on line 636
my question simple: why clearmissing
parameter ignored , how achive editing selected properties?
some code here:
controller:
class foocontroller extends controller { /** * @rest\patch("/foo/{id}", requirements={"id": "\d+"}) * * @rest\requestparam(name="bar", nullable=true) * @rest\requestparam(name="zyx", nullable=true) * * @param int $id * @param paramfetcher $pf * * @return response * * @throws \symfony\component\httpkernel\exception\notfoundhttpexception * @throws \symfony\component\httpkernel\exception\badrequesthttpexception */ public function editaction(int $id, paramfetcher $pf) : response { $foo = $this->repository->find($id); if (!$foo) throw $this->createnotfoundexception(); $form = $this->createform(footype::class, $foo); $form->submit($pf->all(), false); // <––––– here if (!$form->issubmitted() || !$form->isvalid()) throw new badrequesthttpexception($this->view($form->geterrors(true))->getdata()); $foo = $form->getdata(); $this->em->merge($foo); $this->em->flush(); return $this->responder->respond($foo); } }
doctrine entity:
/** * @orm\entity() */ class foo { /** * @assert\notblank() * @assert\length(min="3", max="190") * @orm\column(type="string", length=190) */ private $bar; /** * @assert\notblank() * @assert\length(min="3") * @orm\column(type="text") */ private $zyx; public function __construct(string $bar, string $zyx) { $this->bar = $bar; $this->zyx = $zyx; } public function getbar() : string { return $this->bar; } public function getzyx() : string { return $this->zyx; } public function setbar(string $v) { $this->bar = $v; } public function setzyx(string $v) { $this->zyx = $v; } }
form type:
class footype extends abstracttype { public function buildform(formbuilderinterface $builder, array $options) { $builder ->add('bar', texttype::class) ->add('zyx', texttype::class) ; } public function configureoptions(optionsresolver $resolver) { $resolver->setdefaults([ 'data_class' => foo::class, 'csrf_protection' => false, // todo better way workaround constructor requirements? 'empty_data' => new foo('_', '_'), ]); } }
changing controller solve issue.. but.. that's ugly , decreases maintainability. here other way?
class foocontroller extends controller { public function editaction(int $id, paramfetcher $pf) : response { $foo = ...; $form = $this->createform(footype::class, $foo); $submit = []; $bar = $pf->get('bar'); $zyx = $pf->get('zyx'); if (!empty($bar)) $submit['bar'] = $bar; if (!empty($zyx)) $submit['zyx'] = $zyx; $form->submit($submit, false); ... } }
um doesn't work?
public function __construct(string $bar, string $zyx = ""){ if( strlen( $zyx ) > 0 ) $this->zyx = $zyx; $this->zyx = $zyx; ... }
if felt inclined cheat on setter this
public function __set( $key, $value ){ if( !method_exits( $this, '_'.$key ) ) throw new exception('unknown method' ); if( !empty( $value ) ) $this->'_'.$key( $value ); } protected function _setzyx(string $v) { $this->zyx = $v; }
then when call setzyx() ( undefined ) uses magic set method filters out empty values.... don't use symphony don't know if check method_exists()
etc.. thought fun
update
looking @ update can way too
$submit = []; $submit['bar'] = $pf->get('bar'); $submit['zyx'] = $pf->get('zyx'); $submit = array_filter( $submit ); //you may need custom callback, $form->submit($submit, false);
but may more maintainable way, extend $form
class , override submit function , bake in way.
i not symphony user ( don't know convention overriding stuff ) after extending $form class
public function submit( $submit, $arg1, $filter = false ){ //sorry not sure second arg is, anyway if( $filter ){ if( gettype( $filter ) == 'boolean' ) $submit = array_filter( $submit ); else $submit = array_filter( $submit, $filter ); } parent::submit( $submit, $arg1 ); }
then it's backed class, , can either call true
or give closure use filter, such
$form2->submit( $submit, false, function( $item ){ return strlen( $item ); });
you wrap in function inside base controller or helper class ( , pass $form ), don't need code on place.
Comments
Post a Comment