Skip to content

3.x FormHelper:: Allow to specify the source of injected form field values#9127

Merged
markstory merged 19 commits intocakephp:3.nextfrom
ionas:formhelper-values
Aug 30, 2016
Merged

3.x FormHelper:: Allow to specify the source of injected form field values#9127
markstory merged 19 commits intocakephp:3.nextfrom
ionas:formhelper-values

Conversation

@ionas
Copy link
Copy Markdown
Contributor

@ionas ionas commented Jul 17, 2016

This PR implements what has been suggested here: #8093 (comment)

In case there is a general consensus that this is a good approach, then I will add:

  • unit tests
  • doc blocks Done.

I did test this on a simple baked Article edit form:

  • Example URL: https://cakephp.dev/articles/edit/1?title=foo&body=bar
  • Example Code:
<?= $this->Form->create($article, ['values' => 'query']) ?>
// or
<?= $this->Form->create($article, ['values' => ['query', 'context']]) ?>

This would take data from query and then from context. It respects order. E.g. this would also work:

<?= $this->Form->create($article, ['values' => ['data', 'query', 'context']]) ?>
// or
<?= $this->Form->create($article, ['values' => ['data', 'query']]) ?>

Note

Initially I wanted to let Contexts handle this. However FormHelper::_addDefaultContextProviders() is being called when the FormHelper is being constructed, not when FormHelper::create() is being called. As far as I can see Construction time would be the only place to pass down data such as $this->request->query or $this->request->data

Concerns

Maybe the option flag values should be named valuesSources for the FormHelper::create() options interface, too? Done.

Extensibility

This could also be made configurable when FormHelper is being setup via ::loadHelper().
In case this makes it through I can add support for this.

return [];
}

public function getValuesSources()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing function doc comment

Missing blank line before return statement
Comment thread src/View/Helper/FormHelper.php Outdated
return $this;
}

public function getSourceValue($fieldname)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing function doc comment

Comment thread src/View/Helper/FormHelper.php Outdated
}

/**
* T O D O
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whitespace found at end of line

Comment thread src/View/Helper/FormHelper.php Outdated
if ($valuesSource === 'context') {
return $this->_getContext()->val($fieldname);
}
if (isset($this->request->{$valuesSource}[$fieldname])) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to use the methods instead of properties else you won't get values for field names like foo.bar.

Copy link
Copy Markdown
Contributor Author

@ionas ionas Jul 17, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I considered that. Has that feature been merged yet? (thought it was part of the dot syntax for Entity::get()).

@ADmad So how would I differentiate between a legitimate null/false and the method just not finding anything within the path?

Copy link
Copy Markdown
Contributor Author

@ionas ionas Jul 17, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1176: * When reading values you will get null for keys/values that do not exist.
http://api.cakephp.org/3.3/source-class-Cake.Network.Request.html#1166-1203

Due to data() being a getter and setter I cannot even patch it to take a flag to be strict and through exceptions when values are not being found.

@markstory any ideas? New methods like getData(), setData(), getQuery(), setQuery()? where the last is $options and there you could disable throwing of exceptions?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So how would I differentiate between a legitimate null/false and the method just not finding anything within the path?

You don't need to since post data and query string can only have string values.

Copy link
Copy Markdown
Contributor Author

@ionas ionas Jul 17, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For unmodified $_POST and $_GET, yes - for $this->request->data and $this->request->query, not necessarily.

It fails for instance if you do $this->request->data = $this->Articles->get($id) and it does fill some fields with null which you then overwrite via query sourceValues e.g. <?= $this->Form->create(null, ['values' => ['data', 'query']]) ?> - not that I advertise such code.

Jonas Hartmann added 2 commits July 17, 2016 16:17
Comment thread src/View/Helper/FormHelper.php Outdated
'encoding' => strtolower(Configure::read('App.encoding')),
'templates' => null,
'idPrefix' => null,
'valuesSources' => [],
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should default to ['data', 'context'].

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right my mind was broken when I removed it! 'Context' alone would do it. Both or just context?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, just ['context'] would be enough.

@ionas
Copy link
Copy Markdown
Contributor Author

ionas commented Jul 17, 2016

Please let me know if anything is missing/wrong/off. I will probably find time the next weekend to add unit tests so that this PR becomes merge-able.

@michaelze let me know if this would be sufficient for your use cases because it is an alternative implementation to your original PR.

Edit: I'll take a look at why tests are failing ASAP - If you have hints/pointers. Let me know.

Comment thread src/View/Helper/FormHelper.php Outdated
* Gets a single field value from the sources available.
*
* @param string $fieldname The fieldname to fetch the value for.
* @return string Field value derived from sources.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be string|null as the bottom of the method can return a null implicitly.

@markstory
Copy link
Copy Markdown
Member

@ionas The tests are failing because valuesSource is being turned into an HTML attribute from what I can see.

@markstory
Copy link
Copy Markdown
Member

You'll need to resolve the merge conflicts.


/**
* Tests the different input rendering values based on sources values switching while supplying
* an entity (base context) and multiple sources (durch as data, query)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in such.

@ionas ionas force-pushed the formhelper-values branch from 6b41d1b to cb979eb Compare August 22, 2016 10:20
@inoas
Copy link
Copy Markdown
Contributor

inoas commented Aug 22, 2016

I have resolved the merge conflict by adding support for defaults and schemaDefaults for valuesSources.

@markstory markstory modified the milestones: 3.3.2, 3.3.3 Aug 22, 2016
@inoas
Copy link
Copy Markdown
Contributor

inoas commented Aug 25, 2016

Anything else? I don't want it to get out of sync with HEAD/master again ;).

@markstory markstory self-assigned this Aug 25, 2016
Comment thread src/View/Helper/FormHelper.php Outdated
return $this->request->{$valuesSource}($fieldname);
}
}
if ($options['default'] !== null && $options['default'] !== false) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is false a good condition?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need to exclude false? Boolean fields can have a default value of false.

@markstory markstory modified the milestones: 3.4.0, 3.3.3 Aug 26, 2016
Comment thread src/View/Helper/FormHelper.php Outdated
}
if ($options['schemaDefault'] !== null && $options['schemaDefault'] !== false) {
return $options['schemaDefault'];
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could tests be added for this behavior?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I did also remove the false check and hardened the not null test via isset().

return $this->request->{$valuesSource}($fieldname);
}
}
return null;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing blank line before return statement

$this->Form->setValuesSources(['query']);
$result = $this->Form->getSourceValue('title');
$expected = '';
$this->assertEquals($expected, $result);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't the schema defaults apply when the source is 'query'?

Copy link
Copy Markdown
Contributor

@inoas inoas Aug 27, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you want to apply the schema defaults you need to do:

$this->Form->setValuesSources('context'); // The default
// or
$this->Form->setValuesSources(['query', 'context']);
// or
$this->Form->setValuesSources(['context', 'query']);

Without allowing the context, you will get nothing out of it. At least that was the goal.
And yes, usually you want the context, and you can have it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the context is required to get default values, why is this code here? EntityContext:val() already handles providing schema defaults.

Copy link
Copy Markdown
Contributor

@inoas inoas Aug 27, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because you can supply 'schemaDefaults' as an option to FormHelper::create() but not utilise the EntityContext?

You say I should remove:

        if (isset($options['schemaDefault'])) {
              return $options['schemaDefault'];
          }

?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its not in the source anymore anyway - I removed it in the last commit @ above line.
So what is missing from your point of view? What do you want me to change?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't the schema defaults apply when the source is 'query'?

@markstory Because only context instance knows about the schema defaults. So just setting sources to ['query'] wouldn't would apply schema defaults but setting it to ['query', 'context'] would.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ADmad Ok that makes sense to me. The duplicate code I was concerned about has been removed.

@dereuromark
Copy link
Copy Markdown
Member

So is this going into master or the 3.next outlined on the right sidebar?

@markstory
Copy link
Copy Markdown
Member

@dereuromark I'll merge it into 3.next. I'm a little gun-shy on adding potentially disruptive features into master given how rough 3.3.x has been so far.

@inoas
Copy link
Copy Markdown
Contributor

inoas commented Aug 27, 2016

While I don't look forward to updating it again in terms of merge conflicts I am 👍 on going more with semver on non-tiny-features. Updating docs. Let me know if I need to do anything else in before 3.next merge.

@markstory markstory changed the base branch from master to 3.next August 27, 2016 14:32
markstory pushed a commit to cakephp/docs that referenced this pull request Aug 30, 2016
@markstory markstory merged commit 6a509da into cakephp:3.next Aug 30, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants