Rounded decimal in edit form Symfony2 + Doctrine2 - symfony

How do I set the decimal precision and scale within the symfony2 entity? I've defined latitude in longitude fields using decimal data type in my entity like this:
/**
* #ORM\Column(type="decimal", precision="10", scale="6", nullable=true)
*/
protected $latitude;
When persisting new object it saves decimal correctly (I can see 52.406374 in phpMyAdmin). However when displaying edit form the number is rounded to 52,406 and after updating it is stored in mysql as 52.406000. Probably something is wrong with my Doctrine configuration, but I don't know what.
Why is the latitude and longitude getting rounded?
Found a solution:
Symfony's Form component renders decimal form field as type="text". When using:
->add('latitude', 'number', array(
'precision' => 6,
))
It is rendered properly. The thread from comment doesn't describe my problem.
I guess they have already fixed bug with 'convert to float' precision.
When I was displaying latitude in twig template it was showing proper (not rounded) value.

How to set the symfony decimal type precision and scale:
Set it in your entity, like this:
protected $mycolumn;
/**
* #ORM\Column(type="decimal", precision=14, scale=8, nullable=true)
*/
This sets the datatype in the MySQL database:
mycolumn decimal(14,8)
What do scale and precision mean when specifying a decimal field type in Doctrine 2?

Maybe the problem is not due to your doctrine mapping.
Look at this reference documentation for NumberType.
It is what you use? You probably have to change the precision.

In Symfony3.2 you should use scale:
$builder->add('lat', NumberType::class, array('scale' => 8));
This specifies how many decimals will be allowed until the field
rounds the submitted value (via rounding_mode). For example, if scale
is set to 2, a submitted value of 20.123 will be rounded to, for
example, 20.12 (depending on your rounding_mode).

Related

Show decimal percent type field

I'm trying to show a form which has a percent type field that can show values like 3.03% for exemple. But it seems to be rounding to integers, e.g 3% in this case.
Entity field :
/**
* #var float
* #ORM\Column(type="float")
*/
private $penaltyRate;
Form builder :
...
->add('penaltyRate', PercentType::class, ['label' => 'create.form.penalty'])
Is this a limitation of percentType and should I just use another type and add manually the '%' indicator ?
EDIT
For future googler, while #Emanuel Oster was right for just pointing to the official symfony documentation, as it wasn't obvious for me the first time I read it here is an example if you want to allow two decimals :
Form builder :
...
->add('penaltyRate', PercentType::class, [
'label' => 'create.form.penalty',
'scale' => 2
])
From the symfony documentation:
scale
type: integer default: 0
By default, the input numbers are rounded. To allow for more decimal
places, use this option.
Try This
->add('penaltyRate', PercentType::class,[
'label_format' => 'penaltyRate',
'scale'=>1, // or 'scale'=>2
'type'=>'integer'
])

What is the difference b/w setting default value by the options attribute and setting it through the variable directly?

If you want to know how to set default value in symfony2, look here.
I can set it through both ways. For example, I can set it through the variable directly like this.
/**
* #var string $variable
*
* #ORM\Column(name="variable", type="string", nullable=true)
*/
private $variable = "default_value";
or i can use the options attribute
/**
* #var string $variable
*
* #ORM\Column(name="variable", type="string", nullable=true,options={"default" = "default_value"})
*/
private $variable = "default_value";
I want to know what is the difference b/w each of these two. More importantly what are the cases when the first way won't suffice , and options attribute has to be used.
From what i've come to know so far, setting the variable directly sets default value on a symfony2 level , and the options attribute sets it for doctrine. What difference does it make to set default value on ORM level, and when does it clash with symfony2 defaults? What happens if i only use one of the two.
You're right, the difference is that the value is being set on different levels. To elaborate, if you create a default value using:
/**
* #var string $variable
*
* #ORM\Column(name="variable", type="string", nullable=true)
*/
private $variable = "default_value";
When do you create a new object with the default value.
$a = new MyClass();
$a->getVariable(); // -> 'default_value'
So the actual default value is accessible immediately. If you use the second approach:
/**
* #var string $variable
*
* #ORM\Column(name="variable", type="string", nullable=true,options={"default" = "default_value"})
*/
private $variable;
This will cause that the schema in DB will contain default value for the column so the value will be accessible after you save the entity
$a = new MyClass();
$a->getVariable(); // -> null
$em->perist($a);
$em->flush();
$a->getVariable(); // -> 'default_value'
I would say this is the basic difference. It really depends of where you want to control your default values and when you want to have them.
In my opinion, in most of the cases the assignment in the entity itself is better, since if you want to change the value later in the system, all you need to do is update the value on the entity.
If you will be using the default in the database, then updating to a different value will need to update the annotation and then create a migration to alter the default value in the DB field
UPDATE (Migration question):
In case you use default value specified in Doctrine annotation and you're using Doctrine migrations bundle for the Symfony project and you will write your migration for this class manually (not by using php app/console doctrine:migrations:diff), you need to specify manually the default as an option. The annotation itself just tells how the column definition should look like.
If the default value is set only in PHP, i.e. private $variable = 'default_value'; migration bundle will not be affected by it at all. That means that if you run php app/console doctrine:migrations:diff the DEFAULT value for the field won't be filled in. Of course if you write the migration yourself, the default value in the database will be there only if you fill it automatically in.
To sum the migration budle functionality - the automatically generated migrations are affected only by default value in #ORM\Column annotation.

symfony2 doctrine decimal precision scale annotations are ignored

i've set up an attribute in my entity like this :
/**
* #var decimal
*
* #ORM\Column(name="latitude", type="decimal", precision=10, scale=7, nullable=true)
*/
private $latitude;
but when i generate the database schema with : doctrine:database:create; doctrine:schema:create
my field is set up to decimal (10,0) in the database (when i look up with phpmyadmin)
and so, when in insert data like 42.123456 with a form, this data is truncated to 42.
how can i resolve this?
Thanks.
Ok, finally get to resolve this.
Simply manually remove the cache (app/cache/..)
removing it by symfony command cache:clear wont revolve the problem

Force type on Doctrine2 #JoinColumn annotation without using ColumnDefinition

I have a legacy database which must be maintained exactly as is in terms of data types, column names and sizes etc. With an extra Column annotation the relations are rendered useless. With columnDefinition like this:
#ORM\JoinColumn(name="user_contact", referencedColumnName="contact_id", nullable=false, columnDefinition="int(11) DEFAULT '0'")
the change script always runs, so it is not a good solution. Is there any way to specify the type, length (size) and default value of a JoinColumn?
JoinColumn annotation is used in the process of creating relationships between entities not for creating new columns. From the docs,
This annotation is used in the context of relations in #ManyToOne,
#OneToOne fields and in the Context of #JoinTable nested inside a
#ManyToMany.
A new column is created using **column** annotation. Look at this:
/**
* #var integer
*
* #ORM\Column(name="user_contact", type="integer", options={"default":0})
*/
private $userContact;
Update
Latest documentation on columns and join columns annotation reference can be found here: https://www.doctrine-project.org/projects/doctrine-orm/en/2.9/reference/annotations-reference.html

Getting multiple rows using ParamConverter

Hi Im trying to use ParamConverter to get multiple rows from DB but profiler show query with limi 1. Is it possible to get it like that
/**
* #Route("/localization/{code}", name="pkt-index")
* #ParamConverter("localizations", class="PriceBundle:Localization")
*/
after entering localization/0003 I should get more than 100 rows.
EDIT:
I have used repository_method option
and
/*
* #Route("/localization/{id}", name="pkt-index")
* #ParamConverter("localizations", class="PriceBundle:Localization", options={
* "repository_method": "getByLocalizationCode"
* })
*/
but funny thing is that when I change {id} in route it does not work it throws and exception
SQLSTATE[HY093]: Invalid parameter number: parameter was not defined
even if variable exists in entity class, if variable dont exist it throws
Unable to guess how to get a Doctrine instance from the request information.
EXPLANATION
when I change {id} in route it does not work it throws and exception
SQLSTATE[HY093]: Invalid parameter number: parameter was not defined
Here I think symfony treads id like primary key and as parameter to repository method it pass string when I changed this id to something else it pass array
Example
/**
* #Route("/localization/{id}", name="pkt-index")
*/
pass string to method
/**
* #Route("/localization/{code}/{name}", name="pkt-index")
*/
pass array to method
array(
'code' => 003
'name' => localization_name
)
and last
/**
* #Route("/localization/{id}/{name}", name="pkt-index")
*/
will pass string id omit the name
Hope this sounds reasonable.
forgottenbas's answer isn't completely right. #ParamConverter will first try to find one entity by id ...
... then try to match the route variables against db columns to find an entity ...
but essentially it will only convert one entity at a time.
If you would still like to use a paramconverter you would need to write a custom one.
or just use a one-liner inside your controller action:
/**
* #Route("/localization/{code}", name="pkt-index")
*/
public function yourAction($code)
{
$localizations = $this->getDoctrine()->getRepository("YourBundle:Localization")->findBy(array("code" => $code));
// ...
ParamConverter currently can only extract id from request and find one entity from db. Look at
DoctrineParamConverter code. But you can specify your own param converter with some extra logic.

Resources