SonataAdminBundle + AJAXファイルのダウンロード

みんなのために楽しい時間を過ごしてください。 この記事では、通常のファイルアップロードではなく、自分の義務のために1つのプロジェクトに実装しなければならなかった2つの方法を検討します。 タスクはこれでした:サイトの管理部分にファイルをドラッグアンドドロップでアップロードする必要があり、これはframefork'e Symfony 2.3で実行されました。* + SonataAdminBundle。 いくつかの理由により、ソナタが置かれた部分を省略しています(必要に応じて、このギャップを埋めることができます)。 したがって、Sonataを既にインストールし、Entityフォルダーに少なくとも1つのエンティティを作成していると思います。 そうでない場合は、やってみましょう。 猫へようこそ:



// MyFolder / MyBundle / Entity / Name

<?php namespace MyFolder\MyBundle\Entity; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; /** * Table * * @ORM\Table(name="table") * @ORM\Entity */ class Table { /** * @var integer * * @ORM\Column(name="id", type="integer") * @ORM\Id */ private $id; /** * @var string * * @ORM\Column(name="name", type="string", length=255, nullable=true) */ private $filePath; }     .   /:
      
      







$ app / console doctrine:generate:エンティティMyFolder / MyBundle / Entity / Name



ゲッターとセッターが生成された後、ソナタに進みます。 したがって、ソナタファイルのコードは次のようになります。



// MyFolder / MyBundle / Admin / Name

 <?php namespace MyFolder\MyBundle\Admin; use Sonata\AdminBundle\Admin\Admin; use Sonata\AdminBundle\Datagrid\ListMapper; use Sonata\AdminBundle\Datagrid\DatagridMapper; use Sonata\AdminBundle\Form\FormMapper; use Sonata\AdminBundle\Show\ShowMapper; class NameAdmin extends Admin { protected function configureFormFields(FormMapper $formMapper) { $formMapper ->add('name'); } protected function configureDatagridFilters(DatagridMapper $datagridMapper) { $datagridMapper ->add('name') } protected function configureListFields(ListMapper $listMapper) { $listMapper ->addIdentifier('name') } }
      
      







他に何もする必要はありません。 しばらく停止し、このリンク( github.com/weixiyen/jquery-filedrop)をたどります。 ここではライブラリに興味があります。jsファイルは1つしかないので、お見逃しなく:)。



だから。 ドラッグアンドドロップを実装する必要があるため、楽しみが始まります。実装しましょう。 これを行うには、MyBundle / Resources / view / Adminフォルダーで次の操作を行います(ない場合は、後でさらに混乱を作成します)。次の内容の小枝ファイル-sonata_admin_base_layout.html.twigを作成します。



// MyBundle / Resources / view / Admin / sonata_admin_base_layout.html.twig

 {% extends 'SonataAdminBundle::standard_layout.html.twig' %} {% block stylesheets %} {{ parent() }} <link href="{{ asset('bundles/mybundle/css/admin/style.css') }}" rel="stylesheet" type="text/css" /> {% endblock %} {% block javascripts %} {{ parent() }} <script src="{{ asset('bundles/mybundle/js/admin/jquery.filedrop.js') }}"></script> <script src="{{ asset('bundles/mybundle/js/admin/js.fileDropBlock.js') }}"></script> <script src="{{ asset('bundles/mybundle/js/admin/js.fileLoadByDefault.js') }}"></script> <script src="{{ asset('bundles/mybundle/js/admin/init.js') }}"></script> {% endblock %}
      
      







config.ymlに移動して、メインのソナタテンプレートを再定義した後

// app / config / config.yml

 sonata_admin: title: My Admin Panel templates: ## default global templates layout: MyFolderMyBundle:Admin:sonata_admin_base_layout.html.twig
      
      







そこで、ファイルを埋め込むことができるようにメインソナタテンプレートを再定義しました。 次の4行を自然に置き換えることができます。



 <script src="{{ asset('bundles/mybundle/js/admin/jquery.filedrop.js') }}"></script> <script src="{{ asset('bundles/mybundle/js/admin/js.fileDropBlock.js') }}"></script> <script src="{{ asset('bundles/mybundle/js/admin/js.fileLoadByDefault.js') }}"></script> <script src="{{ asset('bundles/mybundle/js/admin/init.js') }}"></script>
      
      







これらのファイルは、実際には次のように私たちと共に生きています。



MyBundle / Resources / public / js / admin / jquery.filedrop.js

MyBundle / Resources / public / js / admin / js.fileDropBlock.js

MyBundle / Resources / public / js / admin / js.fileLoadByDefault.js

MyBundle / Resources / public / js / admin / js.init.js



すべてが正しいことに注意してください。ファイルを作成するには、パブリックフォルダーにadminフォルダーを作成することを強くお勧めします。



  1. js.fileDropBlock.js
  2. js.fileLoadByDefault.js
  3. init.js。




理解できるように、4の最初のファイルは以前にgitaからダウンロードしたものなので、恥ずかしがらずにadminフォルダーに入れてから、アセットを実行します。 コンソールに入力します



$ app / console asset:web --symlinkがすべて正しい場合はインストールします。パブリックフォルダーのコピーが/ ​​bundle / mybundle /フォルダーに表示されるはずです。 運転しました。 次に、各ファイルについて順番に説明します。 したがって、ファイル番号1(js.fileDropBlock.js)とそのコード:



// MyBundle / Resources / public / js / admin / js.fileDropBlock.js

 function fileDropBlock(block, type) { var allowType = { 'img': ['image/jpeg', 'image/png', 'image/gif'] }; block.filedrop({ url: '/upload-file', # url         paramname: 'file', # .     name  input  fallbackid: 'upload_button', maxfiles: 1, # -  maxfilesize: 2, #    mb #   .      error: function (err, file) { switch (err) { case 'BrowserNotSupported': console.log('Old browser'); break; case 'FileTooLarge': console.log('File Too Large'); break; case 'TooManyFiles': console.log('Only 1 file can be downloader'); break; case 'FileTypeNotAllowed': console.log('Wrong file type'); break; default: console.log('Some error'); } }, allowedfiletypes: allowType[type], #      dragOver: function () { block.addClass('active-drag-block'); }, dragLeave: function () { block._removeClass('active-drag-block'); }, uploadFinished: function (i, file, response) { block.find('input[type="text"]').val(response.filePath); #       } }) }
      
      







ファイルNo. 2(js.fileLoadByDefault.js)とそのコード:

// MyBundle / Resources / public / js / admin / js.LoadByDefault.js



 var arrayType = { 'img': [ 'image/png', 'image/jpg', 'image/jpeg' ], 'pdf': [ 'application/pdf', 'application/x-pdf' ] }; function fileLoadByDefault(selector, type, block) { var input = document.getElementById(selector), formdata = false; input.click(); }
      
      







それほどではないですか? 少し後で彼が必要です。 最後に、ファイル番号3(init.js)とそのコード:



// MyBundle / Resources / public / js / admin / init.js

 (function ($) { $(document).ready(function () { $.fn.uploadFile = function (type) { var blockText = { 'img': {'text': ['Drag Image File Here'], 'name': ['img'], 'id': ['imguploadform']} }; this.append('<p>' + blockText[type].text + '</p>'); this.append('<input type="file" class="upload-file" name="' + type + 'file" id="' + type + 'uploadform" data-type="'+ blockText[type].name +'">'); this.addClass('drag_n_drop--' + type + 'Path'); $('input', this).hide(); fileDropBlock(this, type); }; var imgBlock = $('div', 'div[id$="_coverPath"]'); imgBlock.uploadFile('img'); $('input[type="file"]').on("change", function () { var $_this = $(this), type = $_this.data('type'), reader, file; file = this.files[0]; if (window.FormData) { formdata = new FormData(); } if (window.FileReader) { reader = new FileReader(); reader.readAsDataURL(file); } if (formdata) { formdata.append("file", file); } if (!$.inArray(file.type, arrayType[type])) { $.ajax({ url: "/upload-file", type: "POST", data: formdata, processData: false, contentType: false, success: function (res) { var userData = jQuery.parseJSON(res); $_this.parent().find('input[type="text"]').val(userData.filePath); } }); } else { alert('Wrong type') } }); imgBlock.click(function () { fileLoadByDefault('imguploadform', 'img', this); }); }); })(jQuery);
      
      







何が起こっているのかを明確にし、部分的にコードを分析しましょう。 以前は、ページごとに1つの入力しかありませんでしたが、ドラッグアンドドロップ用の領域が必要です。



 $.fn.uploadFile = function (type) { var blockText = { 'img': { 'text': ['Drag Image File Here'], 'name': ['img'], 'id': ['imguploadform'] } }; this.append('<p>' + blockText[type].text + '</p>'); this.append('<input type="file" class="upload-file" name="' + type + 'file" id="' + type + 'uploadform" data-type="'+ blockText[type].name +'">'); this.addClass('drag_n_drop--' + type + 'Path'); $('input', this).hide(); fileDropBlock(this, type); };
      
      







単一のパラメーターとして、特定の領域にロード(ドロップ)するドキュメントのタイプを取得する関数。



関数はそれを受け入れて、本質的に新しいhtmlコードを返しました。 テキストを含む段落が含まれます:



 this.append('<p>' + blockText[type].text + '</p>');
      
      







ダウンロードボタンは、それでも重要な役割を果たします。



 this.append('<input type="file" class="upload-file" name="' + type + 'file" id="' + type + 'uploadform" data-type="'+ blockText[type].name +'">');
      
      







要素にクラスを追加して、それが何であるかを理解します。



 this.addClass('drag_n_drop--' + type + 'Path');
      
      







そして、すべての入力を非表示にします。



 $('input', this).hide();
      
      







CSSカラーを追加します。



// MyBundle / Resources / public / css / style.css

 .drag_n_drop--imgPath{ width: 150px; height: 100px; cursor: pointer; border: 2px solid #e0e0e0; background: #f9f9f9; }
      
      







最終的に、これらすべての操作の後、これに似たものを取得する必要があります。

画像



もしそうなら、すべてが順調です。



さらにinit.jsファイル



そのようなコード:



 var imgBlock = $('div', 'div[id$="_name"]'); #        imgBlock.uploadFile('img'); #     uploadFile
      
      







以下はそのような小さなコードです。



 $('input[type="file"]').on("change", function () { #   ,     var $_this = $(this), type = $_this.data('type'), reader, file; file = this.files[0]; #      file if (window.FormData) { formdata = new FormData(); #   (     js) } if (window.FileReader) { reader = new FileReader(); #   reader.readAsDataURL(file); } if (formdata) { formdata.append("file", file); #     } if (!$.inArray(file.type, arrayType[type])) { #        $.ajax({ url: "/upload-file", #    type: "POST", data: formdata, #     processData: false, contentType: false, success: function (res) { var userData = jQuery.parseJSON(res); #   $_this.parent().find('input[type="text"]').val(userData.filePath); #              } }); } else { alert('Wrong type'); #   alert   } });
      
      







次に、コード:



 imgBlock.click(function () { fileLoadByDefault('imguploadform', 'img', this); });
      
      







それは、その中に写真を投げるように設計されているディーバをクリックすると、その中のfileLoadByDefault関数には3つの引数があります。 1-タイプfileのid input'a。 2-アップロードするファイルのタイプ。 3-クリックが発生した親要素自体。



実際、ここで、注意深い読者は、実際には、コードが2つの読み込み方法を実装していることに気付くでしょう。 1つ目はドラッグ&ドロップ(ストリーミングの目的)で、2つ目はコンテナの歌姫をクリックして、Drup&Dropを対象とした標準形式のupload'aファイルを呼び出すことです。 基本的に2は副作用であり、このような素晴らしい副作用です。



私はあなたを動揺させたくありませんが、私たちは半分の仕事しかしませんでした...さらにもっと楽しく、今度はphpに行きましょう!



そのため、ファイルをドロップするか直接ダウンロードするかにかかわらず、あらゆるイベントの[/ upload-file]リンクを参照することを覚えています。



この場合のルートを決定する必要があります。



// MyFolder / MyBundle / Resourses / config / rounting.yml

 my_file_upload: pattern: /upload-file defaults: { _controller: MyFolderMyBundle:Default:uploadFile }
      
      







[uploadFile]メソッドのコードを見てください。



// MyFolder / MuBundle / Contraller / Default.php

 <?php namespace MyFolder\MyBundle\Controller; use Symfony\Component\HttpFoundation\File\File; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\File\UploadedFile; class DefaultController extends Controller { public function uploadFileAction() { $filename = $_FILES['file']; #    $uploadPath = $this->upload($filename); #    /** *   .     */ return null === $uploadPath ? new Response(json_encode(array( 'status' => 0, 'message' => 'Wrong file type' ) ) ) : new Response(json_encode(array( 'status' => 1, 'message' => $filename, #   'filePath' => $uploadPath #     ) ) ); } private function getFoldersForUploadFile($type) { $fileType = $this->returnExistFileType($type); #       if ($fileType !== null) { return array( 'root_dir' => $this->container->getParameter('upload_' . $fileType . '_root_directory'), #       'dir' => $this->container->getParameter('upload_' . $fileType . '_directory'), #     ); } else { return null; } } #   ()     private function returnExistFileType($type) { $typeArray = array( 'img' => array( 'image/png', 'image/jpg', 'image/jpeg', ), 'pdf' => array( 'application/pdf', 'application/x-pdf', ) ); foreach ($typeArray as $key => $value) { if (in_array($type, $value)) { return $key; } } return null; } #     . ,  ,    private function upload($file) { $filePath = $this->getFoldersForUploadFile($file['type']); if (null === $this->getFileInfo($file['name']) || $filePath === null) { return null; } $pathInfo = $this->getFileInfo($file['name']); $path = $this->fileUniqueName() . '.' . $pathInfo['extension']; $this->uploadFileToFolder($file['tmp_name'], $path, $filePath['root_dir']); unset($file); return $filePath['dir'] . DIRECTORY_SEPARATOR . $path; } #       (    ) private function getFileInfo($file) { return $file !== null ? (array)pathinfo($file) : null; } #    private function fileUniqueName() { return sha1(uniqid(mt_rand(), true)); } #      private function uploadFileToFolder($tmpFile, $newFileName, $rootFolder) { $e = new File($tmpFile); $e->move($rootFolder, $newFileName); }
      
      







結局のところ、悪魔はそれほどひどいものではありません。 おそらく私はいくつかのポイントを逃しました...しかし、あなた、親愛なる読者は、あなたの質問を書いて、コードとその最適化をコメントに自由に書くことができます。 実際、この記事では、ブートローダーをSymfonyに実装する最も簡単な方法を示しました。 当然、これらのメソッドはサービスに渡され、呼び出されるだけです。 すぐに行いますが、これは別の話です。



PSファイルをダウンロードするためのフォルダーへのパスはこのようになります



// app / config / config.yml

 parameters: upload_img_root_directory: %kernel.root_dir%/../web/upload/img upload_img_directory: upload/img
      
      







アップロードフォルダーとimgフォルダーはその中にありません。作成する必要があります。



これらのフォルダが存在しない場合、これを行うメソッドを自由に作成することもできます。 それらに対する書き込み権限を忘れずに入れてください。



All Articles