TYPO3 Extbase: How to store NULL in DB for empty numeric fields? - typo3

In a form Viewhelper I have lots of numeric fields, which should be empty by default, not filled with '0' or '0.00'.
I need this, because there should be a different handling of the data in the saveAction, depending on left empty fields or filled in values (including 0).
For this reason I set the field properties in the database table to NULL by default, like:
CREATE TABLE IF NOT EXISTS `tx_myext_domain_model_result` (
mw double (10,2) DEFAULT NULL,
mw2 double (10,2) DEFAULT NULL,
....
);
TCA looks like this:
'mw' => array(
...
'config' => array(
'type' => 'input',
'size' => 30,
'eval' => 'double2,null'
)
),
Also, in the Result model class, the corresponding properties are initialized with NULL;
/**
* mw
*
* #var float
*/
protected $mw = null;
I did this check to assure that NULL is handled over to the getter for empty form fields:
public function setMw($mw) {
if ($mw == NULL)
$this->mw = 999;
else
$this->mw = $mw;
}
This did what I excepted: The mw field DB was set to '999' for a empty form field.
But now, switched back to normal setter,
public function setMw($mw) {
$this->mw = $mw;
}
fields in the DB table are only left NULL when all other form fields are left empty, too. I.e. as soon as I enter a value in one of the form fields, all other empty form fields are set to '0' on save.
Adding null to the TCA eval field didn't do the trick, neither.
How can I change this behaviour? I'm using TYPO3 6.2.x

step 1: in initializeAction set null for the property
step 2: the idea with checking $mw is null is preaty good idea. TYPO3 not always do what you can assume using logical thinking :) So check if(is_null($mw)) $this->mw = null
this two things should do the trick
you can also set a default value in setter param
setMw($mw = null)

Related

Eloquent use default value if column is null

I want to use the default value if the column is null. For example:
Settings (Table):
id | website_id | column1 | column2
1 | 1 | null | null
Website.php:
<?php
namespace App\Models;
class Website extends Model
{
public function Setting(): HasOne
{
return $this->hasOne(IvendiFinanceCalculatorSetting::class)->withDefault([
'column1' => 'Default',
'column2' => 0,
The above is a hypothetical example, but you can see what I'm attempting to achieve. If I add a row to my table with a matching website id, but leave the other columns as null I want to return the defaults.
Currently if query the Website model with the settings relationship I get back the row but column1 and column2 is null rather than Default and 0.
dd(Website::query()->with('Setting')->find(1));
withDefault works when the relationship is null, not the field values. See Null Object Pattern for more information.
You might be better served by model events, specifically creating for when new IvendiFinanceCalculatorSetting records are inserted.
Then in the model's boot method or an observer class, you can set default setting values:
// IvendiFinanceCalculatorSettingObserver.php example
public function creating (IvendiFinanceCalculatorSetting $setting) {
$setting->setAttribute('column1', 'Default');
$setting->setAttribute('column2', 0);
}
Another approach is setting the default values directly in the model's attribute property:
/**
* The model's default values for attributes.
*
* #var array
*/
protected $attributes = [
'column1' => 'Default',
'column2' => 0
];

Accessing normalized form data in a controller in Symofny 2

I had to add a form event listener (PRE_SUBMIT) to my FormType in order to set a default value of a field based on the value of another field submitted by the user:
//In my FormType:
public function onPreSubmit(FormEvent $event)
{
$formData = $event->getData();
if (empty($formData['time_until'])) {
$date = new \DateTime($formData['time_from']);
$date->add(new \DateInterval('PT1H'));
$formData['time_until'] = $date->format('Y-m-d H:i');
}
$event->setData($formData);
}
time_unti key is set and later its value is mapped onto the form's time_until field which is of datetime type:
->add('time_until', datetime, [
'required' => false,
'input' => 'datetime',
'widget' => 'single_text',
'format' => 'yyyy-MM-dd HH:mm',
'label' => false,
])
No problem so far. However, I need to have access to the normalized values of the form fields in my controller, and not DateTime objects that are present on the form after the call to $form->handleRequest($request);
By "normalized", I mean I want to be able to do:
$form->get('time_until') and have a string in the form 'yyyy-MM-dd HH:mm' returned, and not the DateTime object stored in the form under time_until key.
Advice would be much appreciated. Thank you!
you could just add some attribute $normalizedTimeUntil in your form type class + add getter getNormalizedTimeUntil() that would return this value. Then in Form event you can set this attribute and in controller you can pull it out of form type object with the getter function
or you can add non-mapped string form field timeUntilString (http://symfony.com/doc/current/reference/forms/types/form.html#mapped) and fill it in form event
or you can add transformer (http://symfony.com/doc/current/cookbook/form/data_transformers.html) to transform this Datetime object into string. This would be convienent if you for example need to store date in string form in the database). Then form field getter would return string in controller (and would get stored in the db in string also)

Empty text field set to null in symfony2 form

I've a form with a text field. This field maps to a not nullable field in my DB (is a legacy DB and I can't change this)
The problem is that Symfony2 always set empty text field to NULL and, this make the insert fails.
Is there a way to tell Symfony2 to not set empty text fields to NULL ?
Start by setting a blank value by default in the entity
/**
* #ORM\Column(name="example", type="string", length=255, nullable=false)
*/
private $example = '';
As for your issue, unfortunately you are describing a known issue/bug with Symfony, so you'll have to override the value being set to the setter function:
public function setExample($example = null) {
if (empty($example)) {
$example = '';
}
$this->example = $example;
}
The code below works for me. I tune the form definition.
$builder->add('comment', TextareaType::class, [
'empty_data' => '',
'required' => false,
]);

A set of fields for one property entity in Symfony 2

My Product entity has the following structure:
private $id;
private $title;
/**
* #ManyToOne(targetEntity="Category")
* #JoinColumn(name="cat_id", referencedColumnName="id")
*/
private $category;
Category have nested structure. And each level of nesting is shown in 5 separate fields:
In class form code, I solve it in this way:
$builder
->add('cat_1', 'entity', array(
...
'query_builder' => function() { return someSelectLogic1(); }
))
->add('cat_2', 'entity', array(
...
'query_builder' => function() { return someSelectLogic2(); }
))
->add('cat_3', 'entity', array(
...
'query_builder' => function() { return someSelectLogic3(); }
))
->add('cat_4', 'entity', array(
...
'query_builder' => function() { return someSelectLogic4(); }
))
->add('cat_5', 'entity', array(
...
'query_builder' => function() { return someSelectLogic5(); }
))
Now I need to know which field is filled in the last turn and pass the value of that field in the entity property.
In all that I do not like:
complex logic to determine which field with category was filled at the end
each of these fields is not tied to the entity 'mapped' => false
1) What the right way to organize code of my form?
2) And is there a way to bring these fields into a separate class which will deal with the logic of determining which category was chosen in the end?
I would suggest the following:
1) Create a new custom form field type and put all those entity in there.
This process is not much different from ordinary creation of form type. Just enclose those fields in it's own buildForm() and that should do the trick. Docs.
2) Mark all those entity fields with property "property_path => false".
Clearly you wont be storing these values inside your model.
3) Add two more fields: chosen and lastOne.
Now, this might be tricky: I would either set the chosen to text type (basically, generic type) or would use entity as well. If you go for entity you would need to include all possible answers from all entity fields. As for the lastOne set it to text as it will reflect which field (by name) was selected last.
Either way, those two fields will be invisible. Don't forget to set property_path to false for lastOne field.
4) Finally, add ValueTransformer (docs) which will contain logic to "see" which field was selected last.
Now, I dealt with it only once and don't understand it just quite yet, so your best bet would be trial and error with examples from official docs, unfortunately.
What basically you should do is to, within value-transformer, read the value of field lastOne. This will give you the name of field which was selected last. Then, using that value, read the actual last value selected. Last, set that value (object, if you've went for entity type, or it's ID otherwise) to chosen field.
That should basically do the thing.
As for the JS, I don't know if you're using any framework but I will assume jQuery. You will need to set lastOne field as your selecting items in your form.
$(function(){
$('#myform').find('select').on('change', function(){
var $this = $(this);
$this.closest('form').find('#__ID_OF_YOUR_LASTONE_FIELD').val($this.attr('name'));
});
});
I'm sorry I cannot provide you with code samples for PHP right now. It's a bit late here and will do my best to further update this answer tomorrow.

Does the symfony form fields initialize to null if not visible

I have few fields on the form like name, description, timestamp.
Now in the form I am only displaying name and description but not timestamp.
public function __construct()
{
$this->setTimestamp(new \DateTime());
}
Now in my database, it is coming as null.
Either doctrine is not executing constructor or those fields are set to null when displayed in form.
Even though I am not displaying them.
You need put the timestamp field in your FormType.
If you don't need to show it, just hide the field and set default value.
Something like that:
$builder->add('timestamp', 'hidden', array(
'data' => new \DateTime(),
));
Don't forget {{form_rest(form)}} at end of the twig template to send all hidden fields.