Comments (21)
@sergeyklay can we reopen this until it's fixed?
from phalcon.
What is type of ours field? Is a MySQL BIT?
if ($this->request->isPost() && $form->isValid($_POST, $customer)) {
$customer->ours = isset($_POST['ours']) ? true : false;
$customer->save();
}
from phalcon.
It is MYSQL TINYINT. The problem is not in ORM. It is form component that doesn't set 'ours' property to anything if checkbox is not checked. I understand that if checkbox is not checked, it's not in the $_POST. That will leave 'ours' property unchanged.
from phalcon.
if ($this->request->isPost() && $form->isValid($_POST, $customer)) {
$customer->ours = empty($_POST['ours']) ? 0 : 1;
$customer->save();
}
I changed isset
to empty
because there is a different behavior between isset
and empty
.
$fields = array('our' => '');
if (isset($fields['our']) == empty($fields['our']) {
echo 'both isset and empty';
}
from phalcon.
When form with unchecked checkbox is submitted, $_POST will not contain 'ours' at all. That is standard behavior for any browser. Problem is that Form component is not aware of that. It would not set field to anything if it is not present in $_POST. The corrent behavior for checkboxes (as I think) would be to set corresponding field ('ours' in example) to zero.
from phalcon.
Example that shows that issue:
<?php
use Phalcon\Forms\Element\Check;
use Phalcon\Forms\Form;
use Phalcon\Tag;
class Entity
{
public $field;
}
$di = new \Phalcon\DI\FactoryDefault();
$form = new Form();
$form->add(new Check('field', ['value' => 1]));
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$entity = new Entity();
$entity->field = 1;
$form->bind($_POST, $entity);
var_dump($_POST);
echo '<br>';
var_dump($entity);
}
echo Tag::form();
echo $form->render('field');
echo Tag::submitButton('Submit');
echo Tag::endForm();
$entity->field is unchanged when checkbox is not checked.
Just to be clear, I didn't use controllers and other things just to show the issue in one file.
from phalcon.
No solution, until now? This Problem should affect everyone who uses Checkboxes, not?
Most Frameworks solve this by adding a hidden input with the default/unchecked value.
<input type="hidden" name="my_field" value="0" />
<input type="checkbox" name="my_field" value="1" />
from phalcon.
Not sure if it's helpful to someone or not, but i come up with this:
<?php
namespace Application\Forms\Element;
use Phalcon\Forms\Element\Check as PhalconCheck;
class Check extends PhalconCheck
{
/**
* Renders the element widget returning html
*
* @param array|null $attributes Element attributes
*
* @return string
*/
public function render($attributes = null)
{
$attrs = array();
foreach ($attributes as $attrName => $attrVal) {
if (is_numeric($attrName) || in_array($attrName, array('id', 'name', 'placeholder'))) {
continue;
}
$attrs[] = $attrName .'="'. $attrVal .'"';
}
$attrs = ' '. implode(' ', $attrs);
$id = $this->getAttribute('id', $this->getName());
$name = $this->getName();
$checked = '';
if ($this->getValue()) {
$checked = ' checked';
}
return <<<HTML
<input type="hidden" name="{$name}" value="0" />
<input type="checkbox" id="{$id}" name="{$name}" value="1"{$attrs}{$checked} />
HTML;
}
}
Seems to be working ok for me, but i might've missed something.
P. S.: I'm using this element with model and 'bind' form method
from phalcon.
Thanks for that solution!
But only thing I would like to mention to add condition if $attributes is not null than do foreach in other case do nothing.
<?php
namespace Application\Forms\Element;
use Phalcon\Forms\Element\Check as PhalconCheck;
class Check extends PhalconCheck
{
/**
* Renders the element widget returning html
*
* @param array|null $attributes Element attributes
*
* @return string
*/
public function render($attributes = null)
{
$attrs = array();
if (!empty($attributes)) {
foreach ($attributes as $attrName => $attrVal) {
if (is_numeric($attrName) || in_array($attrName, array('id', 'name', 'placeholder'))) {
continue;
}
$attrs[] = $attrName .'="'. $attrVal .'"';
}
}
$attrs = ' '. implode(' ', $attrs);
$id = $this->getAttribute('id', $this->getName());
$name = $this->getName();
$checked = '';
if ($this->getValue()) {
$checked = ' checked';
}
return <<<HTML
<input type="hidden" name="{$name}" value="0" />
<input type="checkbox" id="{$id}" name="{$name}" value="1"{$attrs}{$checked} />
HTML;
}
}
from phalcon.
@valVk Good catch, thank you!
from phalcon.
I think this issue has to have label BUG.
Because this is not obvious and very confusing behaviour.
from phalcon.
Yes, I confirm this as a bug, your fix seems to work fine for now.
from phalcon.
Just stumbled over that, I solved it a bit different than others and for me it took several workarounds here. Maybe someone finds this helpful since no fix seems available yet.
Two things I have done in my project that helped me to create a workaround.
First I've overwritten all Form Elements (because I needed some additional functionality). This allowed me to make a function to return the type of the element e.g. "Text" or "Check".
Second I've created a base form for all my other forms and have overwritten the bind method. I loop through all form elements and check for type "Check".
If I find a check element and it is not set in data, I set it to 0.
But that was only half of the fix because if a checkbox is rendered and was not checked before, it gets the value 0 assigned to it. So even if the checkbox is checked the browser transmits 0 and it can never be activated. So I need some javascript event handler too. It simply checks if the checkbox is checked and changes the value to 1.
Hope this helps.
from phalcon.
Thank you for contributing to this issue. As it has been 90 days since the last activity, we are automatically closing the issue. This is often because the request was already solved in some way and it just wasn't updated or it's no longer applicable. If that's not the case, please feel free to either reopen this issue or open a new one. We will be more than happy to look at it again! You can read more here: https://blog.phalconphp.com/post/github-closing-old-issues
from phalcon.
C'mon is that fixed?
from phalcon.
Thank you for contributing to this issue. As it has been 90 days since the last activity, we are automatically closing the issue. This is often because the request was already solved in some way and it just wasn't updated or it's no longer applicable. If that's not the case, please feel free to either reopen this issue or open a new one. We will be more than happy to look at it again! You can read more here: https://blog.phalconphp.com/post/github-closing-old-issues
from phalcon.
This hasn't been fixed yet.
Most "solutions" here are actually opinionated hacks. Why on earth would we need frontend logic (JavaScript) or hidden inputs. Plus, value of checkbox can be anything, not just 1
or 0
. Therefore, assuming that lack of value for a checkbox field equals to 0
is wrong to begin with. We need additional option passed to Check
, something similar to Select
, something like:
$element = new Check(
'myField',
[
'emptyValue' => 'nope'
]
);
But I suppose this would require almost complete rewrite of Phalcon\Form::bind
method.
In the meantime, for those looking for a quick fix:
1. Extend Phalcon\Forms\Form
and override it's bind
method
This is native bind
method translated to PHP and changed to allow behavior described above
public function bind(array $data, $entity, $whitelist = null) : Form
{
if (empty($this->_elements)) {
throw new \Exception("There are no elements in the form");
}
$filter = null;
foreach ($this->_elements as $field => $element) {
/**
* If value is not present for current element and element is not a checkbox with defined emptyValue, skip
*/
if (!isset($data[$field])) {
if (is_a($element, \Phalcon\Forms\Element\Check::class) && $element->getUserOption('useEmpty', false)) {
$data[$field] = $element->getUserOption('emptyValue', null);
} else {
continue;
}
}
/**
* Get value for the element
*/
$value = $data[$field];
/**
* Check if the item is in the whitelist
*/
if (is_array($whitelist) && !in_array($field, $whitelist)) {
continue;
}
/**
* Check if the element has filters
*/
$filters = $element->getFilters();
if ($filters) {
if ($filter == null) {
$dependencyInjector = $this->getDI();
$filter = $dependencyInjector->getShared("filter");
}
/**
* Sanitize the filters
*/
$filteredValue = $filter->sanitize($value, $filters);
} else {
$filteredValue = $value;
}
/**
* Use the setter if any available
*/
$method = "set" . \Phalcon\Text::camelize($field);
if (method_exists($entity, $method)) {
$entity->{$method}($filteredValue);
continue;
}
/**
* Use the public property if it doesn't have a setter
*/
$entity->{$field} = $filteredValue;
}
$this->_data = $data;
return $this;
}
2. Extend Phalcon\Forms\Element\Check
This is optional. You can just change getUserOption
calls with getAttribute
in the bind
method above and use Phalcon's native Check
. The downside is that useEmpty
and emptyValue
will be rendered as HTML element's attributes.
<?php
namespace My\Forms\Element;
use Phalcon\Forms\Element\Check as PhCheck;
class Check extends PhCheck
{
/**
* Phalcon\Forms\Element constructor
*
* @param string name
* @param array attributes
*/
public function __construct(string $name, $attributes = null)
{
if (array_key_exists('useEmpty', $attributes)) {
$this->setUserOption('useEmpty', $attributes['useEmpty']);
unset($attributes['useEmpty']);
}
if (array_key_exists('emptyValue', $attributes)) {
$this->setUserOption('emptyValue', $attributes['emptyValue']);
unset($attributes['emptyValue']);
}
parent::__construct($name, $attributes);
}
}
3. Use familiar syntax
You can use 0
's and 1
's or whatever you want
// status field
$status = new Check(
'status',
[
'useEmpty' => true,
'emptyValue' => 'unpublished',
'value' => 'published'
]
);
$status->setLabel('Status');
$this->add($status);
from phalcon.
Thank you for contributing to this issue. As it has been 90 days since the last activity, we are automatically closing the issue. This is often because the request was already solved in some way and it just wasn't updated or it's no longer applicable. If that's not the case, please feel free to either reopen this issue or open a new one. We will be more than happy to look at it again! You can read more here: https://blog.phalconphp.com/post/github-closing-old-issues
from phalcon.
Thank you for contributing to this issue. As it has been 90 days since the last activity, we are automatically closing the issue. This is often because the request was already solved in some way and it just wasn't updated or it's no longer applicable. If that's not the case, please feel free to either reopen this issue or open a new one. We will be more than happy to look at it again! You can read more here: https://blog.phalcon.io/post/github-closing-old-issues
from phalcon.
Thank you for contributing to this issue. As it has been 90 days since the last activity, we are automatically closing the issue. This is often because the request was already solved in some way and it just wasn't updated or it's no longer applicable. If that's not the case, please feel free to either reopen this issue or open a new one. We will be more than happy to look at it again! You can read more here: https://blog.phalcon.io/post/github-closing-old-issues
from phalcon.
Still relevant
from phalcon.
Related Issues (20)
- [NFR]: Replace regexp in the router with arrays for extra performance
- Can't access page, 404 FORBIDDEN
- Can I use `$this->getRelated` on already cached data?
- [BUG]: Scrutinizer Fixes HOT 1
- [NFR]: ADD sticky for read write connection
- [NFR]: removeBehavior method in Model
- [NFR]:returnedValue not updated after dispatcher->forward
- [NFR]: No way to add html attributes to Select Tag. documentation inadequate HOT 1
- [BUG]: The "setDefault" method does not work for forms of type "text" with name "value" HOT 5
- update src folder links
- How to use cookie in phalcon 4.x ? HOT 1
- update tests folder links
- [NFR]: Complete rework of ORM HOT 3
- [BUG]: \Phalcon\Encryption\Crypt + named parameters/arguments throw fatal error. HOT 1
- [NFR]: Refactor Phalcon\Mvc\Router/Route HOT 1
- [NFR]: Refactor Phalcon\Mvc\Model\MetaData
- phalcon 3,4 webhook problem HOT 2
- [NFR]: What is the purpose of this library? HOT 3
- [NFR]: Add a getResult() or fetchAll() method to Resultset\Simple
- [BUG]: when i use JWT Builder , api returns blank HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from phalcon.