Chapters
40 Chapters
|
4:39:58
|
Login to bookmark this video
-
Course Code
Subscribe to download the code!Compatible PHP versions: ^7.1.3
Subscribe to download the code!Compatible PHP versions: ^7.1.3
-
This Video
Subscribe to download the video!
Subscribe to download the video!
-
Subtitles
Subscribe to download the subtitles!
Subscribe to download the subtitles!
-
Course Script
Subscribe to download the script!
Subscribe to download the script!
19.
Setup for Uploading Private Article References
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
Subscribe to jump to this part in the video!
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
This tutorial is built on Symfony 4 but works great in Symfony 5!
What PHP libraries does this tutorial use?
// composer.json
{
"require": {
"php": "^7.1.3",
"ext-iconv": "*",
"aws/aws-sdk-php": "^3.87", // 3.87.10
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"doctrine/annotations": "^1.0", // 1.10.1
"doctrine/doctrine-bundle": "^1.6.10", // 1.10.2
"doctrine/doctrine-migrations-bundle": "^1.3|^2.0", // v2.0.0
"doctrine/orm": "^2.5.11", // v2.7.2
"knplabs/knp-markdown-bundle": "^1.7", // 1.7.1
"knplabs/knp-paginator-bundle": "^2.7", // v2.8.0
"knplabs/knp-time-bundle": "^1.8", // 1.9.0
"league/flysystem-aws-s3-v3": "^1.0", // 1.0.22
"league/flysystem-cached-adapter": "^1.0", // 1.0.9
"liip/imagine-bundle": "^2.1", // 2.1.0
"nexylan/slack-bundle": "^2.0,<2.2.0", // v2.1.0
"oneup/flysystem-bundle": "^3.0", // 3.0.3
"php-http/guzzle6-adapter": "^1.1", // v1.1.1
"phpdocumentor/reflection-docblock": "^3.0|^4.0", // 4.3.0
"sensio/framework-extra-bundle": "^5.1", // v5.2.4
"stof/doctrine-extensions-bundle": "^1.3", // v1.3.0
"symfony/asset": "^4.0", // v4.2.3
"symfony/console": "^4.0", // v4.2.3
"symfony/flex": "^1.9", // v1.21.6
"symfony/form": "^4.0", // v4.2.3
"symfony/framework-bundle": "^4.0", // v4.2.3
"symfony/property-access": "4.2.*", // v4.2.3
"symfony/property-info": "4.2.*", // v4.2.3
"symfony/security-bundle": "^4.0", // v4.2.3
"symfony/serializer": "4.2.*", // v4.2.3
"symfony/twig-bundle": "^4.0", // v4.2.3
"symfony/validator": "^4.0", // v4.2.3
"symfony/web-server-bundle": "^4.0", // v4.2.3
"symfony/yaml": "^4.0", // v4.2.3
"twig/extensions": "^1.5" // v1.5.4
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.0", // 3.1.0
"easycorp/easy-log-handler": "^1.0.2", // v1.0.7
"fzaninotto/faker": "^1.7", // v1.8.0
"symfony/debug-bundle": "^3.3|^4.0", // v4.2.3
"symfony/dotenv": "^4.0", // v4.2.3
"symfony/maker-bundle": "^1.0", // v1.11.3
"symfony/monolog-bundle": "^3.0", // v3.3.1
"symfony/phpunit-bridge": "^3.3|^4.0", // v4.2.3
"symfony/stopwatch": "4.2.*", // v4.2.3
"symfony/var-dumper": "^3.3|^4.0", // v4.2.3
"symfony/web-profiler-bundle": "4.2.*" // v4.2.3
}
}
11 Comments
Argh! I would have liked to have tackled the CollectionType! What do you recommend if we really have to use them?
For example, we have a page that allows us to create multiple users at once. And to each user, we have to attach a file (an ID card, an avatar, whatever).
We are therefore forced to use a CollectionType. What is really annoying in this case is that in the controller, we will have to loop through each user to add the associated file.
Worse, if we are in another even less cool context, in which we have a collection with each item which itself contains a collection of files (and which can in the future be modified, deleted, added). It's an ordeal!
Therefore, I was wondering, would it be possible, a bit like with VichUploader, that we create an event that would take care of all the management of the files, alone, without having to do it ourselves? from the controller?
With VichUploader, when we submit a form that contains a file, VichUploader alone manages the addition of the file. Could we not do the same?
EDIT: I found this (old) tutorial from Grafikart (a boss) : https://grafikart.fr/tutori... .It looks pretty good as a mode of operation! Do you think we could use it?
Hey Kiuega !
I'm still catching up a bit on my messages, as you've probably noticed :).
So... overall... I would once again say: could you possibly... *not* use the CollectionType? It really comes down to the user experience of the page. If you use the CollectionType, then if a user creates 5 users... and uploads 5 avatars... and submits... if there is a validation error on just 1 user, they will lose all 5 uploaded avatars. That's just how non-Ajax upload forms work.
I don't know the exact requirements, but I would make sure that your top-level entity is saved before you get to this page (are these users being added to... like an Organization or something). Then, when you click "add user", you Ajax load a user form and put it on the page. When they hit "add user", you Ajax submit that form & upload. If it's successful, probably you Ajax load an updated "user list" onto the page so the new user shows up there. Stimulus can help do this pretty cleanly. If you were using Turbo (that's a whole other topic), you could probably use a Turbo frame + Turbo Streams to accomplish this. Or just put the "add new user" form onto a totally different page, and leverage Turbo Drive to make the experience feel fast.
So... that's a LONG way of saying: try not to use the CollectionType :). About the tutorial you listed - that may be very good! It certainly looks solid. But it doesn't address the UX problem you'll have with a CollectionType.
Cheers!
Hi Ryan, thanks for your response! It's very clear ! :) I'll remember it the day I need it!
Regarding the use of an Annotation for the uploadable fields, it is now done!
I set up my annotation, and centralized all the file upload part in a service.
Now, when an entity has the @Uploadable annotation and a File type field has an @UploadableField annotation (with the possibility of designating the properties responsible for containing information such as mapping, public or private visibility, size image, mimeType, or original filename), then I have a listener that takes care of doing whatever it takes, and we can forget about all the code that we ourselves coded in the controllers ! Very convenient ! : D
Hi everybody !
In this part of the tutorial:
I was wondering, any workflow I could follow to try to make it ? ;)
Thans !
Hey Christina V.!
Hmm... avoid it if you can? ;)
It simply IS tricky. Well... sort of. Assuming you're not doing anything fancy with AJAX, it's "sort of" simple. In fact, you wouldn't need to make any changes to what we do in this tutorial: you would submit the form and, on success, move the uploaded file around, save the new entity... and everything is happy.
The problem comes when you have validation errors. This is a UX problem: your user uploads a file (hopefully not a big file)... but then the form fails validation because the "email" field (or something) is invalid. When this happens, and the form re-renders, the upload field will be blank. That's annoying - the user has to re-attach their file (if they even notice that it's missing)!
So, to get this right, you need to save the uploaded file... even if the form was unsuccessful.
If you have a separate entity that represents the uploaded file - like ArticleReference - it's a bit easier. When the form submits and is unsuccessful, you would STILL move the uploaded file and create the ArticleReference... but with no related Article. You would then need to take the new id of the ArticleReference and stick it on your form so that when you finally DO submit successfully, you can use that ArticleReference. That's where things get really tricky... specifically with Symfony's form system. I might even skip the form system, and instead pass the new ArticleReference id into the template and render it as a hidden input by hand. Then, on submit (when it's successful) you could read that hidden POST parameter by hand, query for the ArticleReference, and set the Article object on it before saving.
Also, you will probably want some recurring process (e.g. a CRON job) that deletes all the ArticleReference objects in the database that have no related Article and are older than 24 hours. This will "clean out" uploaded files where the user never completed the form successfully.
Phew! So not impossible... just tricker ;). Avoid it if you can. Sometimes that's easy. For example, you could have an "Article Creation Wizard" where on step 1, you ask for the article title. On submit, you save the article to the database. Then, on step 2, you show many more fields and the upload.
Cheers!
Well.. some huge thanks, you made everything really clear!
Just for the fun I'll probably try the hard and tricky one.
But I did a kind of wizard last night, with form in 2 steps. The design is still ugly (wait for it) but it works pretty good!
Thank you very much for your explanations!
Woooh! Nice work! Let me know how the hard way goes :)
Why do you use make:migration instead of doctrine:migrations:diff ?
Hey Рафаил Д.
There is no difference between both commands, it's just for convenience. If you want you can see where the idea came from :)
https://github.com/symfony/...
Cheers!
the code block for edit template is incomplete :)
hey Ad F.
Thank you for your report, we investigate the problem and soon everything will be fixed.
Stay on tuned!
"Houston: no signs of life"
Start the conversation!