Skip to content

Commit

Permalink
feature #239 add a custom form field type example (yceruto)
Browse files Browse the repository at this point in the history
This PR was merged into the master branch.

Discussion
----------

add a custom form field type example

**The first purpose** of this PR is to provide a practical example of how to create a custom form field type.

**The second purpose** is to improve the user interface to the field "Published At" on edit a Post,
using a JavaScript date library like bootstrap-datetimepicker for parsing, validating, manipulating, and formatting dates. http://eonasdan.github.io/bootstrap-datetimepicker.

>**Important:** Is not the purpose of this PR create a custom form field type to support all options and features of the datetimepicker plugin.

References:
* http://symfony.com/doc/current/cookbook/create_custom_field_type.html
* http://symfony.com/doc/current/best_practices/forms.html#custom-form-field-types

Main Topics:
* Defining the custom form Field Type.
* Creating your form Field Type as a Service.
* Creating a Template for the custom form field Type
* Configuring the custom form template.
* Initializing datetime picker JavaScript plugin.
* Using the form Field Type into PostType form.

Others Topics (refactor):
* Moving the initialization of the highligth JavaScript plugin for `main.js` file.

**Preview:**
![datetimepicker](https://cloud.githubusercontent.com/assets/2028198/10723013/d1930664-7b8c-11e5-9409-ec8b369a1c2f.png)

Commits
-------

d8376ea add a custom form field type example
  • Loading branch information
javiereguiluz committed Oct 30, 2015
2 parents b4f82a7 + d8376ea commit 4dd93aa
Show file tree
Hide file tree
Showing 13 changed files with 283 additions and 13 deletions.
5 changes: 5 additions & 0 deletions app/Resources/assets/css/bootstrap-datetimepicker.min.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions app/Resources/assets/js/bootstrap-datetimepicker.min.js

Large diffs are not rendered by default.

24 changes: 21 additions & 3 deletions app/Resources/assets/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,28 @@
* file that was distributed with this source code.
*/

/**
* Handling the modal confirmation message.
*/
(function ($) {
$(document).ready(function () {
hljs.initHighlightingOnLoad();

// Datetime picker initialization.
// See http://eonasdan.github.io/bootstrap-datetimepicker/
$('[data-toggle="datetimepicker"]').datetimepicker({
icons: {
time: 'fa fa-clock-o',
date: 'fa fa-calendar',
up: 'fa fa-chevron-up',
down: 'fa fa-chevron-down',
previous: 'fa fa-chevron-left',
next: 'fa fa-chevron-right',
today: 'fa fa-check-circle-o',
clear: 'fa fa-trash',
close: 'fa fa-remove'
}
});
});

// Handling the modal confirmation message.
$(document).on('submit', 'form[data-confirmation]', function (event) {
var $form = $(this),
$confirm = $('#confirmationModal');
Expand Down
80 changes: 80 additions & 0 deletions app/Resources/assets/js/moment.min.js

Large diffs are not rendered by default.

9 changes: 2 additions & 7 deletions app/Resources/views/base.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -143,21 +143,16 @@
{# uncomment the following lines to combine and minimize JavaScript assets with Assetic
{% javascripts filter="?jsqueeze" output="js/app.js"
"%kernel.root_dir%/Resources/assets/js/jquery-2.1.4.js"
"%kernel.root_dir%/Resources/assets/js/moment.min.js"
"%kernel.root_dir%/Resources/assets/js/bootstrap-3.3.4.js"
"%kernel.root_dir%/Resources/assets/js/highlight.pack.js"
"%kernel.root_dir%/Resources/assets/js/bootstrap-datetimepicker.min.js"
"%kernel.root_dir%/Resources/assets/js/main.js" %}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
#}

<script src="{{ asset('js/app.js') }}"></script>

<script>
$(document).ready(function() {
hljs.initHighlightingOnLoad();
});
</script>
{% endblock %}

</body>
</html>
17 changes: 17 additions & 0 deletions app/Resources/views/form/fields.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{#
Each field type is rendered by a template fragment, which is determined
by the value of your getName() method and the suffix _widget.
See http://symfony.com/doc/current/cookbook/form/create_custom_field_type.html#creating-a-template-for-the-field
#}

{% block app_datetimepicker_widget %}
{% spaceless %}
<div class="input-group date" data-toggle="datetimepicker">
{{ block('datetime_widget') }}
<span class="input-group-addon">
<span class="fa fa-calendar"></span>
</span>
</div>
{% endspaceless %}
{% endblock %}
1 change: 1 addition & 0 deletions app/config/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ twig:
strict_variables: "%kernel.debug%"
form_themes:
- "bootstrap_3_layout.html.twig"
- "form/fields.html.twig"

# Assetic Configuration (used for managing web assets: CSS, JavaScript, Sass, etc.)
assetic:
Expand Down
5 changes: 5 additions & 0 deletions app/config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ services:
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }

app.form.type.datetimepicker:
class: AppBundle\Form\Type\DateTimePickerType
tags:
- { name: form.type, alias: app_datetimepicker }

# Uncomment the following lines to define a service for the Post Doctrine repository.
# It's not mandatory to create these services, but if you use repositories a lot,
# these services simplify your code:
Expand Down
3 changes: 1 addition & 2 deletions src/AppBundle/Form/PostType.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
'label' => 'label.content',
))
->add('authorEmail', 'email', array('label' => 'label.author_email'))
->add('publishedAt', 'datetime', array(
'widget' => 'single_text',
->add('publishedAt', 'app_datetimepicker', array(
'label' => 'label.published_at',
))
;
Expand Down
73 changes: 73 additions & 0 deletions src/AppBundle/Form/Type/DateTimePickerType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace AppBundle\Form\Type;

use AppBundle\Utils\MomentFormatConverter;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;

/**
* Defines the custom form field type used to manipulate datetime values across
* Bootstrap Date\Time Picker javascript plugin.
* See http://symfony.com/doc/current/cookbook/create_custom_field_type.html
*
* @author Yonel Ceruto <yonelceruto@gmail.com>
*/
class DateTimePickerType extends AbstractType
{
/**
* @var MomentFormatConverter
*/
private $formatConverter;

public function __construct()
{
$this->formatConverter = new MomentFormatConverter();
}

/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['attr']['data-date-format'] = $this->formatConverter->convert($options['format']);;
$view->vars['attr']['data-date-locale'] = \Locale::getDefault();
}

/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'widget' => 'single_text',
));
}

/**
* {@inheritdoc}
*/
public function getParent()
{
return 'datetime';
}

/**
* {@inheritdoc}
*/
public function getName()
{
return 'app_datetimepicker';
}
}
52 changes: 52 additions & 0 deletions src/AppBundle/Utils/MomentFormatConverter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace AppBundle\Utils;

/**
* This class is used to convert PHP date format to moment.js format
*
* @author Yonel Ceruto <yonelceruto@gmail.com>
*/
class MomentFormatConverter
{
/**
* This defines the mapping between PHP ICU date format (key) and moment.js date format (value)
* For ICU formats see http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Time-Format-Syntax
* For Moment formats see http://momentjs.com/docs/#/displaying/format/
*
* @var array
*/
private static $formatConvertRules = array(
// year
'yyyy' => 'YYYY', 'yy' => 'YY', 'y' => 'YYYY',
// day
'dd' => 'DD', 'd' => 'D',
// day of week
'EE' => 'ddd', 'EEEEEE' => 'dd',
// timezone
'ZZZZZ' => 'Z', 'ZZZ' => 'ZZ',
// letter 'T'
'\'T\'' => 'T',
);

/**
* Returns associated moment.js format.
*
* @param string $format PHP Date format
*
* @return string
*/
public function convert($format)
{
return strtr($format, self::$formatConvertRules);
}
}
5 changes: 5 additions & 0 deletions web/css/app.css

Large diffs are not rendered by default.

Loading

0 comments on commit 4dd93aa

Please sign in to comment.