【问题标题】:Attaching files stopped working octobercms email ajax form附加文件停止工作 octobercms 电子邮件 ajax 表单
【发布时间】:2017-12-05 11:56:22
【问题描述】:

以下设置一直有效,直到它停止,现在我很困惑为什么。 我在 OctoberCMS 中创建了一个带有文件附件的联系表单,如下所示

{{ form_ajax('ContactForm::onSend', { files: 'true',  flash: 'true', 'data-request-files':true, 'data-request-validate': true }) }}
    <input type="hidden" name="handler" value='onSave'>
    <fieldset class="form">
        <input type="name" name="name" placeholder="Imię i nazwisko" required>
        <input type="email" name="email" placeholder="E-mail" required>
        <input type="phone" name="phone" placeholder="Telefon">
        <input type="text" name="subject" placeholder="Temat" >
        <textarea name="theMessage" placeholder="Zapytanie" required style="width: 100%; height: 140px;"></textarea>
        <input type="file" name="fileAttachment" id="fileAttachment" class="inputfile"  data-multiple-caption="wybrano {count}" /><label for="fileAttachment">wybierz plik </label><span class='attachmentName'></span>

    </fieldset>
        <button type="submit" class="send" data-attach-loading>Wyślij</button>
    </fieldset>

{{ form_close() }}

发送邮件组件

<?php namespace Depcore\Parts\Components;
use Cms\Classes\ComponentBase;

use Mail;
use Lang;
use Flash;
use Input;
use Validator;
use ValidationException;
use Redirect;
use System\Models\File;

class ContactForm extends ComponentBase
{
    public function componentDetails()
    {
        return [
            'name'        => 'depcore.parts::lang.components.contactFormTitle',
            'description' => 'depcore.parts::lang.components.contactFormDescription'
        ];
    }

    public function defineProperties()
    {
        return [
              'emailTo' => [
                    'title' => 'depcore.parts::components.emailAddress',
                    'description' => 'depcore.parts::components.destinationEmailDescription',
                    'default' => 'zamowienia@kludi.pl',
                    'validationPattern' => "\A[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\z",
                    'ValidationMessage' => ''
            ]
        ];
    }

    public function onSend(){

        $data = post();
        $vars = [
            'name' => Input::get('name'),
            'subject' => Input::get('subject'),
            'phone' => Input::get('phone'),
            'theMessage' => Input::get('theMessage'),
            'fileAttachment' => Input::file('fileAttachment'),
        ];

        $rules = [
                'name' => 'required',
                'email' => 'required|email'
            ];

        $validator = Validator::make($data, $rules);

        if ($validator->fails())
            throw new ValidationException( $validator );
        else {

        Mail::send('depcore.parts::mail.message', $vars, function( $message )  use  ( $vars )  {

            // $message->to($this->property('emailTo'));
            $message->to('adam@depcore.pl');

            if ($vars['fileAttachment']) {
                $file = (new File())->fromPost($vars['fileAttachment']);
                $message->attach($file['path']);
            }

            $message->subject($vars['subject']);
            Flash::success('Wiadomość została wysłana.');
        });

      }
    }

}

据我所知,Input::file('fileAttachemnt') 总是返回 null,所以我认为这可能是 JavaScript 框架的问题 (?)。

这是一件奇怪的事情,让我在处理该项目时感到惊讶,现在我被卡住了。

【问题讨论】:

    标签: javascript php jquery ajax octobercms


    【解决方案1】:

    从您的代码看来,您错误地使用了错误的方法

     $vars = [
            'name' => Input::get('name'),
            'subject' => Input::get('subject'),
            'phone' => Input::get('phone'),
            'theMessage' => Input::get('theMessage'),
            'fileAttachment' => Input::get('fileAttachment'), <-- here
     ];
    

    你的代码正在使用这个

    输入::get('fileAttachemnt');

    现实中应该是这样的

    输入::文件('fileAttachemnt');

    可能是您更新了代码但没有注意到 ;)

    更新

    好的,我猜 File 外观代码 (new File()) 存在一些问题 不要使用它,我们可以直接使用文件,因为您也没有保存该文件,

    你能替换你的代码并检查一次吗

    $file = (new File())->fromPost($vars['fileAttachment']);
    $message->attach($file['path']);
    

    $file = $vars['fileAttachment'];
    $pathToFile = $file->getPathname();
    $fileName = $file->getClientOriginalName();
    $mime = $file->getMimeType()
    $message->attach($pathToFile, ['as' => $fileName, 'mime' => $mime]);
    

    然后检查它,它应该可以工作。

    更多更新

    我添加了 ajax 框架的修改版本(添加了 js sn-p),代码取自 10 月 cms 官方 git repo,只是删除了其中的一部分,以便它可以覆盖现有代码而不会发生冲突。

    我建议,使用此代码并创建 ajax-fw-override.js 文件,然后在您的页面上包含文件,或者只是复制布局并将其添加到最底部,无论它应该如何出现10 月默认 ajax {% framework %},所以它可以覆盖它的Request

    这不是好的解决方案,但考虑到您无法更新您的 cms 版本,我们可以使用它。 (同样通过重复布局,我们确保它不会影响其他任何地方)。

    我使用控制台在您的网站上对其进行了测试,并且成功了。所以请检查一下并告诉我。


    + function($) {
      "use strict";
    
      var Request = function(element, handler, options) {
        var $el = this.$el = $(element);
        this.options = options || {};
    
        /*
         * Validate handler name
         */
        if (handler === undefined) {
          throw new Error('The request handler name is not specified.')
        }
    
        if (!handler.match(/^(?:\w+\:{2})?on*/)) {
          throw new Error('Invalid handler name. The correct handler name format is: "onEvent".')
        }
    
        /*
         * Prepare the options and execute the request
         */
        var $form = options.form ? $(options.form) : $el.closest('form'),
          $triggerEl = !!$form.length ? $form : $el,
          context = {
            handler: handler,
            options: options
          }
    
        $el.trigger('ajaxSetup', [context])
        var _event = jQuery.Event('oc.beforeRequest')
        $triggerEl.trigger(_event, context)
        if (_event.isDefaultPrevented()) return
    
        var loading = options.loading !== undefined ? options.loading : null,
          isRedirect = options.redirect !== undefined && options.redirect.length,
          useFlash = options.flash !== undefined,
          useFiles = options.files !== undefined
    
        if (useFiles && typeof FormData === 'undefined') {
          console.warn('This browser does not support file uploads via FormData')
          useFiles = false
        }
    
        if ($.type(loading) == 'string') {
          loading = $(loading)
        }
    
        /*
         * Request headers
         */
        var requestHeaders = {
          'X-OCTOBER-REQUEST-HANDLER': handler,
          'X-OCTOBER-REQUEST-PARTIALS': this.extractPartials(options.update)
        }
    
        if (useFlash) {
          requestHeaders['X-OCTOBER-REQUEST-FLASH'] = 1
        }
    
        /*
         * Request data
         */
        var requestData,
          inputName,
          data = {}
    
        $.each($el.parents('[data-request-data]').toArray().reverse(), function extendRequest() {
          $.extend(data, paramToObj('data-request-data', $(this).data('request-data')))
        })
    
        if ($el.is(':input') && !$form.length) {
          inputName = $el.attr('name')
          if (inputName !== undefined && options.data[inputName] === undefined) {
            options.data[inputName] = $el.val()
          }
        }
    
        if (options.data !== undefined && !$.isEmptyObject(options.data)) {
          $.extend(data, options.data)
        }
    
        if (useFiles) {
          requestData = new FormData($form.length ? $form.get(0) : null)
    
          if ($el.is(':file') && inputName) {
            $.each($el.prop('files'), function() {
              requestData.append(inputName, this)
            })
    
            delete data[inputName]
          }
    
          $.each(data, function(key) {
            requestData.append(key, this)
          })
        } else {
          requestData = [$form.serialize(), $.param(data)].filter(Boolean).join('&')
        }
    
        /*
         * Request options
         */
        var requestOptions = {
          url: window.location.href,
          crossDomain: false,
          context: context,
          headers: requestHeaders,
          success: function(data, textStatus, jqXHR) {
            /*
             * Halt here if beforeUpdate() or data-request-before-update returns false
             */
            if (this.options.beforeUpdate.apply(this, [data, textStatus, jqXHR]) === false) return
            if (options.evalBeforeUpdate && eval('(function($el, context, data, textStatus, jqXHR) {' + options.evalBeforeUpdate + '}.call($el.get(0), $el, context, data, textStatus, jqXHR))') === false) return
    
            /*
             * Trigger 'ajaxBeforeUpdate' on the form, halt if event.preventDefault() is called
             */
            var _event = jQuery.Event('ajaxBeforeUpdate')
            $triggerEl.trigger(_event, [context, data, textStatus, jqXHR])
            if (_event.isDefaultPrevented()) return
    
            if (useFlash && data['X_OCTOBER_FLASH_MESSAGES']) {
              $.each(data['X_OCTOBER_FLASH_MESSAGES'], function(type, message) {
                requestOptions.handleFlashMessage(message, type)
              })
            }
    
            /*
             * Proceed with the update process
             */
            var updatePromise = requestOptions.handleUpdateResponse(data, textStatus, jqXHR)
    
            updatePromise.done(function() {
              $triggerEl.trigger('ajaxSuccess', [context, data, textStatus, jqXHR])
              options.evalSuccess && eval('(function($el, context, data, textStatus, jqXHR) {' + options.evalSuccess + '}.call($el.get(0), $el, context, data, textStatus, jqXHR))')
            })
    
            return updatePromise
          },
          error: function(jqXHR, textStatus, errorThrown) {
            var errorMsg,
              updatePromise = $.Deferred()
    
            if ((window.ocUnloading !== undefined && window.ocUnloading) || errorThrown == 'abort')
              return
    
            /*
             * Disable redirects
             */
            isRedirect = false
            options.redirect = null
    
            /*
             * Error 406 is a "smart error" that returns response object that is
             * processed in the same fashion as a successful response.
             */
            if (jqXHR.status == 406 && jqXHR.responseJSON) {
              errorMsg = jqXHR.responseJSON['X_OCTOBER_ERROR_MESSAGE']
              updatePromise = requestOptions.handleUpdateResponse(jqXHR.responseJSON, textStatus, jqXHR)
            }
            /*
             * Standard error with standard response text
             */
            else {
              errorMsg = jqXHR.responseText ? jqXHR.responseText : jqXHR.statusText
              updatePromise.resolve()
            }
    
            updatePromise.done(function() {
              $el.data('error-message', errorMsg)
    
              /*
               * Trigger 'ajaxError' on the form, halt if event.preventDefault() is called
               */
              var _event = jQuery.Event('ajaxError')
              $triggerEl.trigger(_event, [context, errorMsg, textStatus, jqXHR])
              if (_event.isDefaultPrevented()) return
    
              /*
               * Halt here if the data-request-error attribute returns false
               */
              if (options.evalError && eval('(function($el, context, errorMsg, textStatus, jqXHR) {' + options.evalError + '}.call($el.get(0), $el, context, errorMsg, textStatus, jqXHR))') === false)
                return
    
              requestOptions.handleErrorMessage(errorMsg)
            })
    
            return updatePromise
          },
          complete: function(data, textStatus, jqXHR) {
            $triggerEl.trigger('ajaxComplete', [context, data, textStatus, jqXHR])
            options.evalComplete && eval('(function($el, context, data, textStatus, jqXHR) {' + options.evalComplete + '}.call($el.get(0), $el, context, data, textStatus, jqXHR))')
          },
    
          /*
           * Custom function, requests confirmation from the user
           */
          handleConfirmMessage: function(message) {
            var _event = jQuery.Event('ajaxConfirmMessage')
    
            _event.promise = $.Deferred()
            if ($(window).triggerHandler(_event, [message]) !== undefined) {
              _event.promise.done(function() {
                options.confirm = null
                new Request(element, handler, options)
              })
              return false
            }
    
            if (_event.isDefaultPrevented()) return
            if (message) return confirm(message)
          },
    
          /*
           * Custom function, display an error message to the user
           */
          handleErrorMessage: function(message) {
            var _event = jQuery.Event('ajaxErrorMessage')
            $(window).trigger(_event, [message])
            if (_event.isDefaultPrevented()) return
            if (message) alert(message)
          },
    
          /*
           * Custom function, focus fields with errors
           */
          handleValidationMessage: function(message, fields) {
            $triggerEl.trigger('ajaxValidation', [context, message, fields])
    
            var isFirstInvalidField = true
            $.each(fields, function focusErrorField(fieldName, fieldMessages) {
              fieldName = fieldName.replace(/\.(\w+)/g, '[$1]')
    
              var fieldElement = $form.find('[name="' + fieldName + '"], [name="' + fieldName + '[]"], [name$="[' + fieldName + ']"], [name$="[' + fieldName + '][]"]').filter(':enabled').first()
              if (fieldElement.length > 0) {
    
                var _event = jQuery.Event('ajaxInvalidField')
                $(window).trigger(_event, [fieldElement.get(0), fieldName, fieldMessages, isFirstInvalidField])
    
                if (isFirstInvalidField) {
                  if (!_event.isDefaultPrevented()) fieldElement.focus()
                  isFirstInvalidField = false
                }
              }
            })
          },
    
          /*
           * Custom function, display a flash message to the user
           */
          handleFlashMessage: function(message, type) {},
    
          /*
           * Custom function, redirect the browser to another location
           */
          handleRedirectResponse: function(url) {
            window.location.href = url
          },
    
          /*
           * Custom function, handle any application specific response values
           * Using a promisary object here in case injected assets need time to load
           */
          handleUpdateResponse: function(data, textStatus, jqXHR) {
    
            /*
             * Update partials and finish request
             */
            var updatePromise = $.Deferred().done(function() {
              for (var partial in data) {
                /*
                 * If a partial has been supplied on the client side that matches the server supplied key, look up
                 * it's selector and use that. If not, we assume it is an explicit selector reference.
                 */
                var selector = (options.update[partial]) ? options.update[partial] : partial
                if ($.type(selector) == 'string' && selector.charAt(0) == '@') {
                  $(selector.substring(1)).append(data[partial]).trigger('ajaxUpdate', [context, data, textStatus, jqXHR])
                } else if ($.type(selector) == 'string' && selector.charAt(0) == '^') {
                  $(selector.substring(1)).prepend(data[partial]).trigger('ajaxUpdate', [context, data, textStatus, jqXHR])
                } else {
                  $(selector).trigger('ajaxBeforeReplace')
                  $(selector).html(data[partial]).trigger('ajaxUpdate', [context, data, textStatus, jqXHR])
                }
              }
    
              /*
               * Wait for .html() method to finish rendering from partial updates
               */
              setTimeout(function() {
                $(window)
                  .trigger('ajaxUpdateComplete', [context, data, textStatus, jqXHR])
                  .trigger('resize')
              }, 0)
            })
    
            /*
             * Handle redirect
             */
            if (data['X_OCTOBER_REDIRECT']) {
              options.redirect = data['X_OCTOBER_REDIRECT']
              isRedirect = true
            }
    
            if (isRedirect) {
              requestOptions.handleRedirectResponse(options.redirect)
            }
    
            /*
             * Handle validation
             */
            if (data['X_OCTOBER_ERROR_FIELDS']) {
              requestOptions.handleValidationMessage(data['X_OCTOBER_ERROR_MESSAGE'], data['X_OCTOBER_ERROR_FIELDS'])
            }
    
            /*
             * Handle asset injection
             */
            if (data['X_OCTOBER_ASSETS']) {
              assetManager.load(data['X_OCTOBER_ASSETS'], $.proxy(updatePromise.resolve, updatePromise))
            } else {
              updatePromise.resolve()
            }
    
            return updatePromise
          }
        }
    
        if (useFiles) {
          requestOptions.processData = requestOptions.contentType = false
        }
    
        /*
         * Allow default business logic to be called from user functions
         */
        context.success = requestOptions.success
        context.error = requestOptions.error
        context.complete = requestOptions.complete
        requestOptions = $.extend(requestOptions, options)
        requestOptions.data = requestData
    
        /*
         * Initiate request
         */
        if (options.confirm && !requestOptions.handleConfirmMessage(options.confirm)) {
          return
        }
    
        if (loading) loading.show()
        $(window).trigger('ajaxBeforeSend', [context])
        $el.trigger('ajaxPromise', [context])
    
        return $.ajax(requestOptions)
          .fail(function(jqXHR, textStatus, errorThrown) {
            if (!isRedirect) {
              $el.trigger('ajaxFail', [context, textStatus, jqXHR])
            }
            if (loading) loading.hide()
          })
          .done(function(data, textStatus, jqXHR) {
            if (!isRedirect) {
              $el.trigger('ajaxDone', [context, data, textStatus, jqXHR])
            }
            if (loading) loading.hide()
          })
          .always(function(dataOrXhr, textStatus, xhrOrError) {
            $el.trigger('ajaxAlways', [context, dataOrXhr, textStatus, xhrOrError])
          })
      }
    
      Request.DEFAULTS = {
        update: {},
        type: 'POST',
        beforeUpdate: function(data, textStatus, jqXHR) {},
        evalBeforeUpdate: null,
        evalSuccess: null,
        evalError: null,
        evalComplete: null
      }
    
      /*
       * Internal function, build a string of partials and their update elements.
       */
      Request.prototype.extractPartials = function(update) {
        var result = []
    
        for (var partial in update)
          result.push(partial)
    
        return result.join('&')
      }
    
      // REQUEST PLUGIN DEFINITION
      // ============================
    
      var old = $.fn.request
    
      $.fn.request = function(handler, option) {
        var args = arguments
    
        var $this = $(this).first()
        var data = {
          evalBeforeUpdate: $this.data('request-before-update'),
          evalSuccess: $this.data('request-success'),
          evalError: $this.data('request-error'),
          evalComplete: $this.data('request-complete'),
          confirm: $this.data('request-confirm'),
          redirect: $this.data('request-redirect'),
          loading: $this.data('request-loading'),
          flash: $this.data('request-flash'),
          files: $this.data('request-files'),
          form: $this.data('request-form'),
          update: paramToObj('data-request-update', $this.data('request-update')),
          data: paramToObj('data-request-data', $this.data('request-data'))
        }
        if (!handler) handler = $this.data('request')
        var options = $.extend(true, {}, Request.DEFAULTS, data, typeof option == 'object' && option)
        return new Request($this, handler, options)
      }
    
      $.fn.request.Constructor = Request
    
      $.request = function(handler, option) {
        return $(document).request(handler, option)
      }
    
      // REQUEST NO CONFLICT
      // =================
    
      $.fn.request.noConflict = function() {
        $.fn.request = old
        return this
      }
    
      // REQUEST DATA-API
      // ==============
    
      function paramToObj(name, value) {
        if (value === undefined) value = ''
        if (typeof value == 'object') return value
    
        try {
          return JSON.parse(JSON.stringify(eval("({" + value + "})")))
        } catch (e) {
          throw new Error('Error parsing the ' + name + ' attribute value. ' + e)
        }
      }
    
    }(window.jQuery);

    【讨论】:

    • Sh** 我发布了错误的代码,这是我拼命尝试使用任何东西来获得结果的部分(我已经更新了代码)
    • 更新答案请尝试该代码并告诉我。
    • 代码导致错误调用非对象上的函数getPathname,在检查ajax调用后似乎没有提交文件。所以我猜这是一个 octoberCMS ajax 框架错误。
    • 您能分享您的网络请求标头和发布的参数吗?在这里我使用了相同的代码及其工作。
    • pastebin.com/siNd5vEk你可以在www.kludi.pl/pliki/dev(主页上的联系方式)上自己查看
    猜你喜欢
    • 1970-01-01
    • 2011-09-12
    • 2020-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-08
    • 2019-01-09
    相关资源
    最近更新 更多