Closed geertjanknapen1 closed 2 weeks ago
I did try using the Files fieldtypes, and this does not throw an exception, but as we handle mailing ourselves, the proper files are not added as an attachment as the documentation states.
Additional information regarding how you end up in the custom FormController. Routing
Route::controller(FormController::class)
->middleware(['ajax']) # Returns 403 error if !$request->ajax(), otherwise continues.
->group(function () {
Route::post('/ajaxforms/{formHandle}', 'submitStatamicForm')->name('submit-statamic-form');
});
AJAX form submission
'use strict'
// Define the 'forms' namespace
if (!('forms' in window)) window['forms'] = [];
$(function() {
$('body').on('click', '.form-ajax-submit', function (e) {
e.preventDefault();
forms.disableSubmit(e); // Disables the submit button after user clicked it, not relevant for issue.
forms.ajaxSubmit(e);
});
});
/*******************************
* Methods ('forms' namespace) *
*******************************/
forms.ajaxSubmit = function (e) {
let form = $(e.target).closest('form');
let formId = form.attr('id');
let formName = form.attr('name');
let formErrorSpan = form.find('span[data-failure]');
let failureMessage = formErrorSpan.data('failure');
// clear potential previously set validation errors
// forms.clearValidationErrors(form); // For this issue you can assume no validation errors happen.
// show spinning loader
$('#envelope-icon').addClass('d-none');
$('#spinning-loader').removeClass('d-none');
let formDataForm = $('form#' + formId)[0];
let formData = new FormData(formDataForm);
// If the form contains the resume fields (file) we want to append both the resume and motivation files to the FormData
if ($('input[name="resume"]').length > 0) {
formData.append('resume', $('input[name="resume"]')[0].files[0]);
formData.append('motivation', $('input[name="motivation"]')[0].files[0]);
}
$.ajax('/ajaxforms/' + formName, {
type: 'POST',
processData: false,
contentType: false,
data: formData,
})
.done(function (response) {
let formContainer = form.closest('div');
$(formContainer).html(response.renderedSuccessView);
forms.enableSubmit(e);
})
.fail(function (response) {
if (response.status === 404) {
console.log(response.responseJSON.message);
formErrorSpan.html(failureMessage);
formErrorSpan.show();
} else {
$.each(response.responseJSON.error, function (formFieldName, validationErrorText) {
let formField = form.find('[name=' + formFieldName + ']');
let formFieldValidationSpan = form.find('span.' + formFieldName);
formFieldValidationSpan.html(validationErrorText);
formFieldValidationSpan.show();
formField.addClass('is-invalid');
});
}
forms.enableSubmit(e); // Enables the submit button again, not relevant for issue
});
Below is the code for the listener, it uses Enums to check the form handle which should not be relevant to the issue.
The handleFormSubmission
is part of a Trait and just sends the Mailables to the correct location
public function handle(FormSubmitted $event)
{
if ($event->submission->form->handle() === Form::APPLICATION_FORM->value) {
// Handle form submission (send mail and store submitted data)
$this->handleFormSubmission($event, ApplicationFormInternalMailable::class, ApplicationFormExternalMailable::class);
// return false so Statamic does not send the e-mail (this also stops propagation of this event to other listeners!!).
return false;
}
// return nothing so that propagation is not stopped unless another listener picks up and handles this event
}
Has this only just started happening recently or have you just built this and it's not working?
Has this only just started happening recently or have you just built this and it's not working?
Sad to say I don't really have a proper answer for this. We utilize this setup on another website, but that website does not have any file-upload fields in the forms.
This website used to run on Statamic 3, so I am now updating it. (Yes, it was greatly neglected) I followed the guides from 3 to 4 and 4 to 5, and Control Panel, and the whole shebang seems to work fine.
The form setup used to be less advanced (just the listener, no AJAX submission, and custom form controller), and when it was it worked. properly.
But we want this website to be in line with our more advanced website, thus also utilizing the more advanced form setup.
Old listener:
public function handle(FormSubmitted $event)
{
if ($event->submission->form->handle() === Form::APPLICATION_FORM->value) {
$emailJob = new SendEmail($event->submission, Site::current(), $event->submission->form->email()[0]);
dispatch($emailJob)->onQueue('every_minute');
// return false so Statamic does not send the e-mail (this also stops propagation of this event to other listeners!!).
return false;
}
// return nothing so that propagation is not stopped unless another listener picks up and handles this event
}
If you need any other information please feel free to ask. And thanks for putting up with my shenanigans again @duncanmcclean , it's much appreciated as always!
@duncanmcclean I'll take a look if I can reproduce the error on the website where this setup is working tomorrow. That would probably narrow it down to some configuration issues on our end.
We don't usually recommend that you hijack our controllers like you have. 😄
Although, if you're able to reproduce the issue on a fresh site or provide access to the site you're having the issues on, then I can take a look.
We don't usually recommend that you hijack our controllers like you have. 😄
Although, if you're able to reproduce the issue on a fresh site or provide access to the site you're having the issues on, then I can take a look.
Hijacking is a strong word, I prefer borrowing 😄
I'll report back either tomorrow or the day after, have a good one!
We don't usually recommend that you hijack our controllers like you have. 😄
Although, if you're able to reproduce the issue on a fresh site or provide access to the site you're having the issues on, then I can take a look.
I tried on our other site, no cigar. Same issue, Then I tried on a new Statamic install, same thing.
But your hijacking comment made me wonder, what is the recommended way to take over the whole mailing, without hijacking Statamic's controllers and everything?
Is there something in the docs that I'm missing, where this is thoroughly explained, and I just missed it or something?
I'll try and create a Github repo with my (very very ugly) minimal reproducible example.
I've created a Github repo with my (very very ugly) minimal reproducible example, find it here
Can't give you access to the other site. Or well, I could but the content for that site is not in the same git repo as the project's code, so it'd be a major hassle to setup.
But your hijacking comment made me wonder, what is the recommended way to take over the whole mailing, without hijacking Statamic's controllers and everything?
I don't think we really have a recommended way to not use our native mailing, other than not configuring any emails.
(I've created a Github repo with my (very very ugly) minimal reproducible example, find it here
Thanks, I'll take a look when I get a chance.
Just looking at the code, I can get the assets to upload, but they then get deleted if you return false
from the FormSubmitted
listener (intentionally).
Why can't you use the normal Statamic email logic?
That makes sense I guess..
Well, we've created a collection where our Content department can create dynamic email templates in all the languages that are supported on the site. When a form is submitted, we listen for it, take the content from the correct email template for the type of form that was submitted, toss that content in a mailable, and then use our custom MailJob to send the email.
Then the contacts are subscribed to one or more lists in Mailchimp, again, based on the type of form that was submitted.
Since it's quite conditional what is supposed to happen while certain forms are submitted, we thought (and subsequently decided) that it would be better to handle the mailing ourselves so we have full control over what happens. But it seems we've shot ourselves in the foot in that regard.
But I guess this issue boils down to "You're doing it wrong"?
@duncanmcclean Does Statamic's mailing logic support queues?
This is one of the other reasons we want to 'hijack' the mailing from Statamic :)
When a form is submitted, we listen for it, take the content from the correct email template for the type of form that was submitted, toss that content in a mailable, and then use our custom MailJob to send the email.
We have a config option which'll let you use your own class for sending emails: https://github.com/statamic/cms/blob/5.x/config/forms.php#L36
You could do all of your "which email template" logic in there, as well as determining if emails should actually get sent or not.
Then the contacts are subscribed to one or more lists in Mailchimp, again, based on the type of form that was submitted.
You can continue to listen to the FormSubmitted
event for handling this.
Does Statamic's mailing logic support queues?
Yes, as long as you have a queue enabled, it should send emails using the queue.
But I guess this issue boils down to "You're doing it wrong"?
Yeah, sorry! We never really intended for people to do what you're doing.
Bug description
Important, I have seen and looked at #6431 and #7294 which mention the same error message, they do not seem related to this issue.
So, we have custom form handling for our frontend forms. A long story short, it works as follows;
parent::submit()
.So, explaining out of the way, I use Assets fields in the form, since Statamic does not handle the emailing so I need to store the uploaded files on disk, as per the documentation.
This throws the aforementioned exception in the FormController, but I can't seem to figure out why or what I'm doing wrong, so any nudges in the correct direction would be greatly appreciated.
How to reproduce
I don't think it's easily reproducible, we have a heavily customised setup.
But the jist would be, prevent Statamic from sending the emails by listening for the FormSubmitted event and returning false at the end of it. Create a form with one or more Assets fields. Try to submit that through AJAX with a custom FormController doing as explained in the Bug description.
Logs
Environment
Installation
Existing Laravel app
Additional details
Form blueprint:
FormController (custom):