SonataAdminBundleでのBootstrap 3 Datepickerのデプロイ

この小さな記事では、 便利な日付ピッカーをSymfony管理パネルに接続する方法について説明します。 デフォルトでは、SonataAdminBundleの日付ピッカーは次のようになります。







そして、便利で美しいコントロールに変えます。







まだ不便なデートピッカーで苦しんでいる人は、猫を歓迎します。



タイミングが必要ない場合は、既製のソリューションを使用できます、 dmkuznetsovに感謝します



SonataAdminBundleのインストール方法については説明しません。 この記事これについて読むことができます。 アプリケーションと管理パネルが既にインストールされていると仮定します。 それでは、始めましょう。



日時フィールドタイプ



最初にすべきことは、ドキュメントに記載されているように新しいフォームフィールドを作成することです。 名前空間<vendor_name> \ <bundle_name> \ Form \ Type \に作成する必要があります。そうしないと、 SensioLabsInsightはテスト中に誓います。



namespace Acme\Bundle\DemoBundle\Form\Type\Field; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormView; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Form\DataTransformerInterface; // Symfony >=2.8 //use Symfony\Component\Form\Extension\Core\Type\TextType; class DateTime extends AbstractType implements DataTransformerInterface { public function buildForm(FormBuilderInterface $builder, array $options) { //           \DateTime $builder->addModelTransformer($this); } public function transform($value) { return $value; //    DataTransformerInterface } public function reverseTransform($value) { //     \DateTime return $value instanceof \DateTime ? $value : new \DateTime($value); } public function buildView(FormView $view, FormInterface $form, array $options) { //       if ($form->getData() instanceof \DateTime) { $view->vars['value'] = $form->getData()->format('Ymd H:i'); } // css   bootstrap  $view->vars['attr']['class'] = 'form-control'; } public function configureOptions(OptionsResolver $resolver) { //   data_class   DataTransformer $resolver->setDefaults([ 'data_class' => \DateTime::class ]); } public function getParent() { // Symfony >=2.8 //return TextType::class; // Symfony <2.8 return 'text'; } public function getName() { return 'datetime'; //     datetime } }
      
      





標準の日時オプションを不要として新しいクラスに転送しませんでしたが、必要な場合はこれを行うことができます。 [時間]フィールドの [ タイプ]セクションで、例としてwith_secondsオプションを使用してこれを行う方法を説明します。



プログラムの次の項目は、共通のフォームテンプレート(フォームのテーマ)を作成することです。 その中で、Sonataテーマを継承し、日付テンプレートを再定義します。 テンプレートは、 Resources / views / Form / fields.html.twigファイルに保存されます。 別の方法を選択することもできますが、私はよく知っています。



 {% extends 'SonataAdminBundle:Form:form_admin_fields.html.twig' %} {% block datetime_widget %} {% spaceless %} <div class="input-group date form-field-datetime"> <input type="text" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/> <span class="input-group-addon"> <span class="glyphicon glyphicon-calendar"></span> </span> </div> {% endspaceless %} {% endblock datetime_widget %}
      
      





JavaScriptをハングさせるには、後でform-field-datetimeクラスが必要になります。 ここでapp / config / config.yml configに次の行を記述することで、フォームに別のテーマを使用する必要があることをSonataに伝えます。



 sonata_doctrine_orm_admin: templates: form: [ AcmeDemoBundle:Form:fields.html.twig ]
      
      





新しいフォームフィールドのサービスを作成することを忘れないでください。



  acme.demo.form.type.datetime: class: Acme\Bundle\DemoBundle\Form\Type\Field\DateTime public: false
      
      





新しいフィールドを作成せず、古いフィールドをオーバーロードするため、 ここで説明するサービスのラベルは作成しません。 同じ理由で、パブリックドメインでは必要ありません。 それでは、標準のフォームフィールドの上書きを始めましょう。 DIコンテナー用のコンパイラーを作成します。



 namespace Acme\Bundle\DemoBundle\DependencyInjection\Compiler; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; class FormTypePass implements CompilerPassInterface { public function process(ContainerBuilder $container) { $container->setAlias('form.type.datetime', 'acme.demo.form.type.datetime'); } }
      
      





ここでは、 form.type.datetimeが新しく作成されたシリーズacme.demo.form.type.datetimeのエイリアスであることを示します。 したがって、フォームにdatetime型のフィールドを作成すると、サービスが使用されます。 したがって、プロジェクトコードを変更せずにコントロールを変更します。 次に、コンパイラをバンドルに接続します。



 namespace Acme\Bundle\DemoBundle use Symfony\Component\HttpKernel\Bundle\Bundle; use Symfony\Component\DependencyInjection\ContainerBuilder; use Acme\BundleDemoBundle\DependencyInjection\Compiler\FormTypePass; class AcmeDemoBundle extends Bundle { public function build(ContainerBuilder $container) { parent::build($container); $container->addCompilerPass(new FormTypePass()); } }
      
      





現在、datepickerは既に美しく便利な形状になっています。JavaScriptをハングさせて、日付を選択できるポップアップウィンドウを開くだけです。







packagist.orgにあるBootstrap 3 Datepickerをインストールします。 composer.jsonに依存関係を書きましょう:



 { "require": { … "eonasdan/bootstrap-datetimepicker": "~4.17.37", … } }
      
      





このパッケージのインストールでは、 asseticを介して接続する方が便利です。 app / config / config.ymlに次の行を書きます:



 assetic: assets: admin-js: inputs: - '%kernel.root_dir%/../vendor/eonasdan/bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js' - '@AcmeDemoBundle/Resources/public/js/admin.js' output: js/admin.js sonata_admin: templates: layout: AcmeDemoBundle:Admin:standard_layout.html.twig
      
      





日付ピッカーとJavaScriptコードをビルドするjs / admin.jsファイルを定義し、それを初期化して、対応するフォームフィールドでハングさせます。 このファイルはweb / js / admin.jsにあります。 また、Sonataレイアウトを再定義して、JavaScriptを有効にしました。 これをやってみましょう:



 {% extends 'SonataAdminBundle::standard_layout.html.twig' %} {% block javascripts %} {{ parent() }} <script src="{{ asset('js/admin.js') }}" type="text/javascript"></script> {% endblock %}
      
      





次に、 Resources / public / js / admin.jsというファイルを作成します。このファイルにフォームフィールドをJavaScriptでバインドします。

 $(function(){ $('.form-field-datetime').datetimepicker({ format: 'YYYY-MM-DD HH:mm', locale: 'ru' }); });
      
      





それだけです。 資産収集を実行し、人生を楽しみます:



 app/console assetic:dump web --no-debug
      
      





フィールドタイプの日付



同様に、わずかな違いのある日付フィールドを作成します。 フォームフィールドのクラス:



 namespace Acme\Bundle\DemoBundle\Form\Type\Field; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormView; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Form\DataTransformerInterface; // Symfony >=2.8 //use Symfony\Component\Form\Extension\Core\Type\TextType; class Date extends AbstractType implements DataTransformerInterface { public function buildForm(FormBuilderInterface $builder, array $options) { $builder->addModelTransformer($this); } public function transform($value) { return $value; } public function reverseTransform($value) { return $value instanceof \DateTime ? $value : new \DateTime($value); } public function buildView(FormView $view, FormInterface $form, array $options) { if ($form->getData() instanceof \DateTime) { $view->vars['value'] = $form->getData()->format('Ym-d'); } $view->vars['attr']['class'] = 'form-control'; } public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'data_class' => \DateTime::class ]); } public function getParent() { // Symfony >=2.8 //return TextType::class; // Symfony <2.8 return 'text'; } public function getName() { return 'date'; } }
      
      





テンプレート:



 {% block date_widget %} {% spaceless %} <div class="input-group date form-field-date"> <input type="text" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/> <span class="input-group-addon"> <span class="glyphicon glyphicon-calendar"></span> </span> </div> {% endspaceless %} {% endblock date_widget %}
      
      





サービス:



  acme.demo.form.type.date: class: Acme\Bundle\DemoBundle\Form\Type\Field\Date public: false
      
      





エイリアスを追加します。



 // .. class FormTypePass implements CompilerPassInterface { public function process(ContainerBuilder $container) { // .. $container->setAlias('form.type.date', 'acme.demo.form.type.date'); } }
      
      





さて、JavaScript:



 $(function(){ // .. $('.form-field-date').datetimepicker({ format: 'YYYY-MM-DD', locale: 'ru' }); });
      
      





フィールドタイプ時間



前のものとの類推によるが、わずかな違いがあります。 私たちのプロジェクトでは、ビデオクリップが公開されており、管理パネルでそれらの長さを示す必要があります。 これを行うには、時間フィールドを使用してwith_secondsオプションをtrueに設定します 。 新しいフォームフィールドでは、この機能を維持する必要がありました。



 namespace Acme\Bundle\DemoBundle\Form\Type\Field; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormView; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Form\DataTransformerInterface; // Symfony >=2.8 //use Symfony\Component\Form\Extension\Core\Type\TextType; class Time extends AbstractType implements DataTransformerInterface { public function buildForm(FormBuilderInterface $builder, array $options) { $builder->addModelTransformer($this); } public function transform($value) { return $value; } public function reverseTransform($value) { return $value instanceof \DateTime ? $value : new \DateTime($value); } public function buildView(FormView $view, FormInterface $form, array $options) { if ($form->getData() instanceof \DateTime) { //     $view->vars['value'] = $form->getData()->format($options['with_seconds'] ? 'H:i:s' : 'H:i'); } $view->vars['attr']['class'] = 'form-control'; //     $view->vars['with_seconds'] = $options['with_seconds']; } public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'data_class' => \DateTime::class, 'with_seconds' => false //     ]); } public function getParent() { // Symfony >=2.8 //return TextType::class; // Symfony <2.8 return 'text'; } public function getName() { return 'time'; } }
      
      





テンプレート:



 {% block time_widget %} {% spaceless %} <div class="input-group date form-field-time" data-with-seconds="{{ with_seconds == true ? 1 : 0 }}"> <input type="text" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/> <span class="input-group-addon"> <span class="glyphicon glyphicon-time"></span> </span> </div> {% endspaceless %} {% endblock time_widget %}
      
      





サービス:



  acme.demo.form.type.time: class: Acme\Bundle\DemoBundle\Form\Type\Field\Time public: false
      
      





エイリアスを追加します。



 // .. class FormTypePass implements CompilerPassInterface { public function process(ContainerBuilder $container) { // .. $container->setAlias('form.type.time', 'acme.demo.form.type.time'); } }
      
      





JavaScriptは少し異なります。



 $(function(){ // .. $('.form-field-time') .each(function () { var el = $(this), options = {locale: 'ru'}; if (el.data('with-seconds') == 1) { options.format = 'HH:mm:ss'; } else { options.format = 'HH:mm'; } el.datetimepicker(options); });
      
      





おわりに



拘禁場所には、タイミングに関する非常に興味深いClockPickerライブラリがあると言います。 興味があれば、私の例に従って簡単に接続できます。



All Articles