dongmuyan5638 2017-12-05 11:56
浏览 75
已采纳

附加文件停止工作octobercms电子邮件ajax表单

The below setup has worked until it stopped and right now I'm perplexed why. I've created a contact form with file attachment in OctoberCMS as below

{{ 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() }}

The component for sending email

<?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.');
        });

      }
    }

}

From what I can tell is that the Input::file('fileAttachemnt') is always returning null so I think It could be a problem with the JavaScript framework (?).

This is a weird thing that got me by surprise when working with the project an now Im stuck.

  • 写回答

1条回答 默认 最新

  • douxidang9092 2017-12-05 16:18
    关注

    From your code it looks like by mistake you used wrong method

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

    your code is using this

    Input::get('fileAttachemnt');

    In Reality it should be this

    Input::file('fileAttachemnt');

    may be you updated your code and didn't notice that ;)

    UPDATE

    ok I guess there is some issue with File facade code (new File()) let not use that instead we can directly use file as also you are not saving that file so,

    can you replace your code and check it once

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

    TO

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

    then check it, it should work.

    MORE UPDATE

    I added modified version of ajax framework (added js snippet), code is taken from October cms official git repo, and just removed some part of it so it can override existing code without conflicts.

    I would suggest, take this code and create ajax-fw-override.js file then include file on your page or just duplicate layout and add it at very bottom, any how it should come after October default ajax {% framework %}, so it can override its Request.

    This is not good solution but considering that you can't update your cms version we can use this. (also by making duplicate layout we make sure it won't affect anywhere else).

    I tested it on your site using console and it worked. so just check it out and let me know.


    + 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);

    </div>
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度
  • ¥30 关于#r语言#的问题:如何对R语言中mfgarch包中构建的garch-midas模型进行样本内长期波动率预测和样本外长期波动率预测