多文件上传约束

Multiple file upload constraint

我按照教程管理多个文件的上传http://growingcookies.com/easy-multiple-file-upload-in-symfony-using-the-collectiontype-field/

上传多个文件的系统工作正常。

但是,我想添加一个限制条件以仅允许某些类型的文件并设置最大大小。

为此,我添加 @Assert\File:

/**
 * @Assert\File(
 *     maxSize = "300k",
 *     mimeTypes = {"application/pdf", "application/x-pdf", "text/plain", "application/msword",
 *     "application/vnd.ms-excel", "image/jpeg", "image/x-citrix-jpeg", "image/png", "image/x-citrix-png", "image/x-png", "image/gif",
 *     "application/zip"},
 *     mimeTypesMessage = "Liste des formats de fichiers acceptés : PDF, TXT, DOC, XLS, JPG, PNG, GIF"
 * )
 *
 * @ORM\OneToMany(targetEntity="Maps_red\TicketingBundle\Entity\TicketDocument", mappedBy="ticket", cascade={"persist"}, orphanRemoval=true)
 */
protected $documents;

通过添加,代码不再有效。我收到以下错误:

Impossible to access an attribute ("name") on a null variable.

当我发送表单时,这个错误出现在“添加文件”页面上。错误对应的行是:

<div class="col col-xs-11" id="jsPreview{{ pos }}">{{ doc.vars.value.name }}</div>

违反约束的消息是:"The file could not be found."

你知道我的错误在哪里吗?


为@Denis Alimov 编辑:

我用 @Assert\All 尝试了 Denis Alimov 的答案,但 return 出现了同样的错误。 然后我尝试将约束放在 BuildForm 中。现在,.txt 文件顺利通过,但所有其他扩展名总是 return 我同样的错误

Impossible to access an attribute ("name") on a null variable.


为@Jakumi 编辑:

我的树枝:

{% extends '@Ticketing/base.html.twig' %}

{% block title %}{{ 'New Ticket'|trans({}, 'TicketingBundle') }}{% endblock %}
{% block header %}<h1>{{ 'New Ticket'|trans({}, 'TicketingBundle') }}</h1>{% endblock %}

{% block form_group_class -%}
    col-sm-8
{%- endblock form_group_class %}


{% block main %}

    <script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>

    {% form_theme form 'bootstrap_4_layout.html.twig' _self %}

    <div class="box box-danger">
        <div class="box-header with-border">
            <h3 class="box-title">{{ 'Create a new ticket'|trans({}, 'TicketingBundle') }}</h3>
        </div>

        {% form_theme form 'bootstrap_3_horizontal_layout.html.twig' _self %}

        {{ form_start(form, {'attr': {'class': 'form-horizontal'} }) }}
        <div class="box-body">

            <div class="hr-line-dashed"></div>

            <div id="filesProto" data-prototype="{{ form_widget(form.documents.vars.prototype)|e }}"></div>

            <div class="form-group">
                <label class="col-sm-2 control-label" for="ticket_form_documents">Pièce-jointe</label>
                <div class="col-sm-8" id="filesBox">
                    {% set pos = 0 %}
                    {% for doc in form.documents %}
                        <div class="row">
                            <div class="col col-xs-1" id="jsRemove{{ pos }}" style="">
                                <button type="button" class="btn btn-danger" onclick="removeFile($(this));"><i class="fa fa-times" aria-hidden="true"></i></button>
                            </div>
                            <div class="col col-xs-11" id="jsPreview{{ pos }}">{{ doc.vars.value.name }}</div>

                            <div style="display:none">
                                {{ form_widget(doc) }}
                            </div>
                        </div>

                        {% set pos = pos + 1 %}
                    {% endfor %}
                </div>
            </div>

        </div>
        <!-- /.box-body -->

        <div class="box-footer">
            <div class="col-md-offset-2 col-sm-8">

                <button id="dropbutton" class="btn bg-ticketing btn-flat form-control" type="submit">
                    {{ 'Submit the ticket'|trans({}, 'TicketingBundle') }}
                </button>


            </div>
        </div>
        <!-- /.box-footer -->
        {{ form_end(form) }}
    </div>

    <script>
        var fileCount = '{{ form.documents|length }}';
        var removeButton = "<button type='button' class='btn btn-danger btn-xs' onclick='removeFile($(this));'><i class='fa fa-times' aria-hidden='true'></i></button>";
        function removeFile(ob)
        {
            ob.parent().parent().remove();
        }
        function createAddFile(fileCount)
        {
            // grab the prototype template
            var newWidget = $("#filesProto").attr('data-prototype');
            // replace the "__name__" used in the id and name of the prototype
            newWidget = newWidget.replace(/__name__/g, fileCount);
            newWidget = "<div style='display:none'>" + newWidget + "</div>";
            hideStuff = "";
            hideStuff += "<div class='col col-xs-1' id='jsRemove" + fileCount + "' style='display: none;'>";
            hideStuff += removeButton;
            hideStuff += "</div>";
            hideStuff += "<div class='col col-xs-11' id='jsPreview" + fileCount + "'>";
            hideStuff += "</div>";
            hideStuff += "<div class='col-sm-8'>";
            hideStuff += "<button type='button' id='jsBtnUpload" + fileCount + "' class='btn btn-default'>";
            hideStuff += "<i class='fa fa-plus'></i> {{ 'Pièce-jointe' | trans }}";
            hideStuff += "</button>";
            hideStuff += "</div>";
            $("#filesBox").append("<div class='form-group'>" + hideStuff + newWidget + "</div>");
            // On click => Simulate file behaviour
            $("#jsBtnUpload" + fileCount).on('click', function(e){
                $('#ticket_form_documents_' + fileCount + '_file').trigger('click');
            });
            // Once the file is added
            $('#ticket_form_documents_' + fileCount + '_file').on('change', function() {
                // Show its name
                fileName = $(this).prop('files')[0].name;
                $("#jsPreview" + fileCount).append(fileName);
                // Hide the add file button
                $("#jsBtnUpload" + fileCount).hide();
                // Show the remove file button
                $("#jsRemove" + fileCount).show();
                // Create another instance of add file button and company
                createAddFile(parseInt(fileCount)+1);
            });
        }
        $(document).ready(function(){
            createAddFile(fileCount);
            fileCount++;
        });
    </script>

{% endblock %}

编辑:

与{{ doc.vars.value.name ?? '' }} 我没有错误了!!

但是,文件删除按钮仍然显示:

<div class="col col-xs-1" id="jsRemove1" style="">
 <button type="button" class="btn btn-danger" onclick="removeFile($(this));"><i class="fa fa-times" aria-hidden="true"></i></button>
</div>

当文件类型不好时,如何让这些按钮消失?

正如已经提到的那样使用 All constraint

 /**
 * @Assert\All({
 *     @Assert\File(
 *         maxSize = "300k",
 *         mimeTypes = {"application/pdf", "application/x-pdf", "text/plain", "application/msword", "application/vnd.ms-excel", "image/jpeg", "image/x-citrix-jpeg", "image/png", "image/x-citrix-png", "image/x-png", "image/gif","application/zip"},
 *         mimeTypesMessage = "Liste des formats de fichiers acceptés : PDF, TXT, DOC, XLS, JPG, PNG, GIF"
 *     )
 * })
 */
 private $documents;

您还可以在 buildForm 方法中为您的 DocumentType 添加约束条件