Comments (4)
FYI I managed to make it work even without adding a custom form type, just extending datetime:
<?php
declare(strict_types=1);
namespace App\Form\Extension;
use App\Form\DataTransformer\CarbonImmutableToDateTimeTransformer;
use App\Form\DataTransformer\CarbonToDateTimeTransformer;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\TimeType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class CarbonExtension extends AbstractTypeExtension
{
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->addAllowedValues('input', ['carbon', 'carbon_immutable']);
$resolver->setDefault('input', 'carbon');
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options): void
{
if ('carbon_immutable' === $options['input']) {
$builder->addModelTransformer(new CarbonImmutableToDateTimeTransformer());
} elseif ('carbon' === $options['input']) {
$builder->addModelTransformer(new CarbonToDateTimeTransformer());
}
}
/**
* {@inheritdoc}
*/
public static function getExtendedTypes(): iterable
{
return [
DateType::class,
DateTimeType::class,
TimeType::class,
];
}
}
<?php
declare(strict_types=1);
namespace App\Form\DataTransformer;
use Carbon\CarbonImmutable;
use DateTime;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
/**
* @implements DataTransformerInterface<CarbonImmutable, DateTime>
*/
final class CarbonImmutableToDateTimeTransformer implements DataTransformerInterface
{
/**
* Transforms a CarbonImmutable into a DateTime object.
*
* @param CarbonImmutable|null $value A CarbonImmutable object
*
* @throws TransformationFailedException If the given value is not a \DateTimeImmutable
*/
public function transform(mixed $value): ?DateTime
{
if (null === $value) {
return null;
}
if (!$value instanceof CarbonImmutable) {
throw new TransformationFailedException('Expected a CarbonImmutable.');
}
return $value->toDateTime();
}
/**
* Transforms a DateTime object into a CarbonImmutable object.
*
* @param DateTime|null $value A DateTime object
*
* @throws TransformationFailedException If the given value is not a \DateTime
*/
public function reverseTransform(mixed $value): ?CarbonImmutable
{
if (null === $value) {
return null;
}
if (!$value instanceof DateTime) {
throw new TransformationFailedException('Expected a \DateTime.');
}
return CarbonImmutable::createFromMutable($value);
}
}
<?php
declare(strict_types=1);
namespace App\Form\DataTransformer;
use Carbon\Carbon;
use DateTime;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
/**
* @implements DataTransformerInterface<Carbon, DateTime>
*/
final class CarbonToDateTimeTransformer implements DataTransformerInterface
{
/**
* Transforms a Carbon into a DateTime object.
*
* @param Carbon|null $value A Carbon object
*
* @throws TransformationFailedException If the given value is not a \DateTimeImmutable
*/
public function transform(mixed $value): ?DateTime
{
if (null === $value) {
return null;
}
if (!$value instanceof Carbon) {
throw new TransformationFailedException('Expected a Carbon.');
}
return $value->toDateTime();
}
/**
* Transforms a DateTime object into a Carbon object.
*
* @param DateTime|null $value A DateTime object
*
* @throws TransformationFailedException If the given value is not a \DateTime
*/
public function reverseTransform(mixed $value): ?Carbon
{
if (null === $value) {
return null;
}
if (!$value instanceof DateTime) {
throw new TransformationFailedException('Expected a \DateTime.');
}
return Carbon::instance($value);
}
}
This will add the option to use carbon as model data for symfony forms. I think it should be implemented so that others can use Carbon in Symfony forms easily.
from carbon.
Hello,
I would have to dig deeper in symfony/form but as Carbon
extends DateTime
and CarbonImmutable
extends DateTimeImmutable
I would expect that you can pass:
- any
Carbon
object whereDateTime
is expected by Symfony - any
CarbonImmutable
object whereDateTimeImmutable
is expected by Symfony
Without needing any override/custom extension.
I would also expect that Symfony would provide types that just are compatible with DateTimeInterface
and so they would be compatible with all of those classes.
However converting CarbonImmutable
to DateTime
(or Carbon
to DateTimeImmutable
) feels wrong, and I hope it could be avoidable.
from carbon.
Side note, it's still very early for 4.x plans, but I think we'll rather move to less things embedded by default (so to releases constraints for those who don't need it), and for instance carbon would be installable without the doctrine type.
So I think it might also be better to have symfony-form-carbon-type as a separated bridge package.
BTW if this mutable vs. immutable question could be investigated and understood and that you would be up to provide the code above as a package and publish it under your own name, I would definitely promote it in the documentation under Symfony section.
from carbon.
I would have to dig deeper in symfony/form but as Carbon extends DateTime and CarbonImmutable extends DateTimeImmutable I would expect that you can pass:
- any Carbon object where DateTime is expected by Symfony
- any CarbonImmutable object where DateTimeImmutable is expected by Symfony
no, this is not true, you should read more in the docs here. It explains nicely the concept of Model/Norm/View data in Symfony forms.
The issue stems from the Model Data being of DateTime
type (not DateTimeInterface
). Note that the Norm data for all DateTimeType
related types (including TimeType
and DateType
) is DateTime
. There is a form option for all these form types called input
, which specified the Model data type and by default is datetime
(meaning DateTime
is used), but can be set to various other options, including datetime_immutable
(as expected, then DateTimeImmutable
is used) <- but this affects ONLY the Model data, not the Norm data.
This is fine however, if you look at my code, I mimic exactly what Symfony does natively for datetime_immutable
type, as can be seen here.
However converting CarbonImmutable to DateTime (or Carbon to DateTimeImmutable) feels wrong, and I hope it could be avoidable.
So, since this is only about the model data (as we dont want to change symfony internals that do work with DateTime anyways in the norm layer), I think my solution is the best, as it allows you to use the default Symfony types with all their rich features. Recoding a totally custom CarbonType would result in tons of code repetition and there would be 0 benefit added.
I do agree this should be part of a symfony bundle package and not core carbon package. Similarly, I dont understand why current carbon composer.json requires carbonphp/carbon-doctrine-types
, and its not an optional dependency that one would use only if Doctrine is in the project.
BTW if this mutable vs. immutable question could be investigated and understood and that you would be up to provide the code above as a package and publish it under your own name, I would definitely promote it in the documentation under Symfony section.
I am happy to help with the development, however I think the code above really does provide 100% of the functionality needed, all we need to do is wrap it in the bundle. I would also prefer if this were under carbonphp package and repos, and not under my name.
from carbon.
Related Issues (20)
- File existence should be checked before attempting include HOT 3
- Compile Error: Enum case value must be compile-time evaluatable -- Error v3 HOT 3
- Proposal to remove hard dependency on carbonphp/carbon-doctrine-types HOT 4
- Deprecation: Implicit conversion from float to int loses precision HOT 1
- PHPDoc on `CarbonImmutable::createFromFormat` incompatible with actual return type HOT 2
- Carbon 3 createFromTimestamp undocumented timezone change HOT 3
- Bug: CarbonImmutable::createFromTimeString('first day of this year 00:00:00') returning February 1st instead of January 1st HOT 2
- [Translation tool] bg HOT 1
- Method isFuture returns an incorrect result HOT 3
- Wrong issue! HOT 1
- Format "2024-02-29" to Buddhist Era so to obtain "2567-02-29" HOT 4
- Taiwan is NOT the Province of China HOT 9
- [Removed]
- Can't get the UTC+0 timestamp HOT 1
- Both Hong Kong and Macao are the Special Administrative Regions of China HOT 5
- isSameUnit not working like in previous versions and accepting "null" as argument HOT 8
- createFromTimestamp does not respect the default timezone HOT 4
- Can no longer use `createFromFormat` with an non-string value as time input HOT 5
- Error addRealSeconds HOT 4
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 carbon.