CoderFunda
  • Home
  • About us
    • Contact Us
    • Disclaimer
    • Privacy Policy
    • About us
  • Home
  • Php
  • HTML
  • CSS
  • JavaScript
    • JavaScript
    • Jquery
    • JqueryUI
    • Stock
  • SQL
  • Vue.Js
  • Python
  • Wordpress
  • C++
    • C++
    • C
  • Laravel
    • Laravel
      • Overview
      • Namespaces
      • Middleware
      • Routing
      • Configuration
      • Application Structure
      • Installation
    • Overview
  • DBMS
    • DBMS
      • PL/SQL
      • SQLite
      • MongoDB
      • Cassandra
      • MySQL
      • Oracle
      • CouchDB
      • Neo4j
      • DB2
      • Quiz
    • Overview
  • Entertainment
    • TV Series Update
    • Movie Review
    • Movie Review
  • More
    • Vue. Js
    • Php Question
    • Php Interview Question
    • Laravel Interview Question
    • SQL Interview Question
    • IAS Interview Question
    • PCS Interview Question
    • Technology
    • Other

05 April, 2024

Symfony custom field type with data transformer not working properly when in an embedded collection form

 Programing Coderfunda     April 05, 2024     No comments   

I am having a problem in Symfony with a custom data transformer on a custom form field - but only when this is used in a collection/embedded form within my main form. If I use the same custom field type and transformer for field directly in the main form, then it works perfectly.
Basically I have an app that is a database of all of my music/films/etc. Each item is stored in an entity called AVItem. For each of these items I can have zero or more tracks and I do this with a CollectionType. Within this embedded form/collection I have simple text fields and also a Collection of EntityType and they all work perfectly when submitting the main form; however, only the one field that uses my custom field type and transformer does not.
My custom field is for a "duration". In the database I save any lengths of time purely as an integer of seconds; however, I display it and want it entered as a string in the form [HH:]mm:ss. When displaying, the custom field and transformer works, it reads the number of seconds from the entity and then the "transform" method correctly displays that as HH:mm:ss. However, when I submit the main form and one of those tracks has something entered into it, when the "reverseTransform" method is called, the value it receives is always null!
However, in my main entity, where I also have a filled called "totalRunningTime" which also uses the same custom field type and transformer, the transform and reverseTransform always work perfectly.
This seems to be an issue purely within the Collection/embedded form.
Does anyone have an ideas?
Here are some code snippets.


This is my custom data transformer:
class TimeDurationTransformer implements DataTransformerInterface
{
private ?string $invalidMessage = null;

public function __construct( ?string $invalidMessage = null )
{
$this->invalidMessage = $invalidMessage;
}

/**
* Transform an integer (number of seconds) into a string of the form HH:mm:ss.
*
* @param mixed $value
* @return mixed
*/
public function transform( mixed $value ) : mixed
{
if ( ( null === $value ) || ( intval( $value ) == 0 ) ):
return null;
endif;

return sprintf( '%02d:%02d:%02d', ( $value/ 3600 ), ( $value / 60 % 60 ), ( $value% 60 ) );
}

/**
* Transform a string of the form HH:mm:ss into a number of seconds as an integer.
*
* @param mixed $value
* @return mixed
*/
public function reverseTransform( mixed $value ) : mixed
{
if ( ( null === $value ) || empty( $value ) || ( strlen( $value ) < 1 ) ) :
return null;
endif;

$matchResult = preg_match( pattern: '/^((\d{1,3}):)?(\d{1,2}):(\d{1,2})$/', subject: $value, matches: $matches, flags: PREG_UNMATCHED_AS_NULL );
// If the string entered does not match the pattern, throw an exception
if ( ( false === $matchResult) || ( 0 === $matchResult ) ) :
throw new TransformationFailedException( message: $this->invalidMessage, invalidMessage: $this->invalidMessage );
else:
if ( $matchResult === 1 && ( count( $matches ) == 5 ) ) :
if ( round( $matches[4] ) != null ):
return( round( $matches[4] ) + ( $matches[3] ? ( $matches[3] * 60 ) : 0 ) + ( $matches[3] ? ( $matches[2] * 3600 ) : 0 ) );
endif;
endif;
throw new TransformationFailedException( message: $this->invalidMessage, invalidMessage: $this->invalidMessage );
endif;
}
}



This is my custom field type:
class TimeDurationType extends AbstractType
{
private $translator;

public function __construct( TranslatorInterface $translator ) {
$this->translator = $translator;
}

public function buildForm( FormBuilderInterface $builder, array $options ) : void
{
$builder->addModelTransformer( new StuggiBearTimeDurationTransformer( invalidMessage: $options[ 'invalid_message' ] ) );
}

public function configureOptions( OptionsResolver $resolver ): void
{
$resolver->setDefaults( [
'data_class' => null,
'required' => false,
'constraints' => [
new PositiveOrZero(),
],
'invalid_message' => $this->translator->trans( 'message.assert.time_duration_format' ),
'attr' => [
'placeholer' => '',
],
] );
}

public function getParent(): string
{
return TextType::class;
}
}



Within my main form for my entity AVItem, I have one field that uses this custom field type - and it works fine:
public function buildForm( FormBuilderInterface $builder, array $options ): void
{
$this->editType = $options['edit_type'];
$this->isWishlistItem = $options[ 'isWishlistItem' ];

$builder
...
->add( 'totalRunningTime', TimeDurationType::class, [
'required' => false,
'label' => $this->translator->trans( 'form.field.label.total_running_time' ),
'label_html' => true,
'attr' => [
'placeholder' => 'HH:mm:ss',
],
'empty_data' => null,
] )
...



Within this form I then have the collection of Tracks:
$builder
...

->add( 'tracks', CollectionType::class, [
'label' => $this->translator->trans( 'form.field.label.tracks' ),
'label_html' => true,
'entry_type' => TrackEmbeddedFormType::class,
'entry_options' => [
'label' => false,
],
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'empty_data' => [],
] )
...



...and then the embedded form type for the tracks:
$builder
->add( 'seriesEpisodeNumber', null, [
'required' => false,
'label' => $this->translator->trans( 'form.field.label.atce_series_episode_number' ),
] )
->add( 'title', null, [
'required' => ( $this->editType == FormEditType::SEARCH ) ? false : true,
'label' => $this->translator->trans( 'form.field.label.atce_title' ),
'label_html' => true,
] )
->add( 'additionalArtistsActors', EntityType::class, [
'required' => false,
'label' => $this->translator->trans( 'form.field.label.atce_additional_artists_actors' ),
'mapped' => true,
'class' => PersonGroup::class,
'by_reference' => true,
'multiple' => true,
'expanded' => false,
'choices' => [],
] )
->add( 'comment', null, [
'required' => false,
'mapped' => true,
'label' => $this->translator->trans( 'form.field.label.atce_comment' ),
'label_html' => true,
] )
->add( 'trackChapterNumber', null, [
'required' => true,
'label' => $this->translator->trans( 'form.field.label.atce_number' ),
'label_html' => true,
] )
->add( 'duration', TimeDurationType::class, [
'required' => false,
'label' => $this->translator->trans( 'form.field.label.atce_duration' ),
'label_html' => true,
'attr' => [
'placeholder' => 'HH:mm:ss',
],
'empty_data' => null,
] );
...



So, as I mentioned, the field "totalRunningTime" works perfectly with the data transformer, converting between integer seconds and a HH:mm:ss string and back.
However, the "duration" field within my collection/embedded tracks form only works reading from the database (the "transform" function works), but when I go to submit the form, the "reverseTransform" function always receives null.


If I change this field to be one of the standard types such as TextType or the like, then the value from the field seems to get passed.


Any help would be greatly appreciated.
  • Share This:  
  •  Facebook
  •  Twitter
  •  Google+
  •  Stumble
  •  Digg
Email ThisBlogThis!Share to XShare to Facebook
Newer Post Older Post Home

0 comments:

Post a Comment

Thanks

Meta

Popular Posts

  • Sitaare Zameen Par Full Movie Review
     Here’s a  complete Vue.js tutorial for beginners to master level , structured in a progressive and simple way. It covers all essential topi...
  • AI foot tracking model
    I am a student doing a graduation project. I urgently need to deal with this model (I am attaching a link). I've never worked with pytho...
  • Laravel Search String
      Laravel Search String is a package by   Loris Leiva   that generates database queries based on one unique string using a simple and custom...
  • Writing and debugging Eloquent queries with Tinkerwell
    In this article, let's look into the options that you can use with Tinkerwell to write and debug Eloquent queries easier. The post Wr...
  • Laravel - Installation
    For managing dependencies, Laravel uses   composer . Make sure you have a Composer installed on your system before you install Laravel. In t...

Categories

  • Ajax (26)
  • Bootstrap (30)
  • DBMS (42)
  • HTML (12)
  • HTML5 (45)
  • JavaScript (10)
  • Jquery (34)
  • Jquery UI (2)
  • JqueryUI (32)
  • Laravel (1017)
  • Laravel Tutorials (23)
  • Laravel-Question (6)
  • Magento (9)
  • Magento 2 (95)
  • MariaDB (1)
  • MySql Tutorial (2)
  • PHP-Interview-Questions (3)
  • Php Question (13)
  • Python (36)
  • RDBMS (13)
  • SQL Tutorial (79)
  • Vue.js Tutorial (69)
  • Wordpress (150)
  • Wordpress Theme (3)
  • codeigniter (108)
  • oops (4)
  • php (853)

Social Media Links

  • Follow on Twitter
  • Like on Facebook
  • Subscribe on Youtube
  • Follow on Instagram

Pages

  • Home
  • Contact Us
  • Privacy Policy
  • About us

Blog Archive

  • July (4)
  • September (100)
  • August (50)
  • July (56)
  • June (46)
  • May (59)
  • April (50)
  • March (60)
  • February (42)
  • January (53)
  • December (58)
  • November (61)
  • October (39)
  • September (36)
  • August (36)
  • July (34)
  • June (34)
  • May (36)
  • April (29)
  • March (82)
  • February (1)
  • January (8)
  • December (14)
  • November (41)
  • October (13)
  • September (5)
  • August (48)
  • July (9)
  • June (6)
  • May (119)
  • April (259)
  • March (122)
  • February (368)
  • January (33)
  • October (2)
  • July (11)
  • June (29)
  • May (25)
  • April (168)
  • March (93)
  • February (60)
  • January (28)
  • December (195)
  • November (24)
  • October (40)
  • September (55)
  • August (6)
  • July (48)
  • May (2)
  • January (2)
  • July (6)
  • June (6)
  • February (17)
  • January (69)
  • December (122)
  • November (56)
  • October (92)
  • September (76)
  • August (6)

Loading...

Laravel News

Loading...

Copyright © CoderFunda | Powered by Blogger
Design by Coderfunda | Blogger Theme by Coderfunda | Distributed By Coderfunda