If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeConfig done! Let's get to work in UploaderHelper
. Instead of passing the $uploadsPath
, which we were using to store things, change this to FilesystemInterface
- the one from Flysystem
- $filesystem
. Use that below, and rename the property to $filesystem
.
Tip
If you're using version 4 of oneup/flysystem-bundle
(so, flysystem
v2),
autowire Filesystem
instead of FilesystemInterface
from League\Flysystem
.
... lines 1 - 5 | |
use League\Flysystem\FilesystemInterface; | |
... lines 7 - 10 | |
class UploaderHelper | |
{ | |
... lines 13 - 14 | |
private $filesystem; | |
... lines 16 - 18 | |
public function __construct(FilesystemInterface $filesystem, RequestStackContext $requestStackContext) | |
{ | |
$this->filesystem = $filesystem; | |
$this->requestStackContext = $requestStackContext; | |
} | |
... lines 24 - 47 | |
} |
Now, in the method, instead of $file->move()
, we can say $this->filesystem->write()
, which is used to create new files. Pass this self::ARTICLE_IMAGE.'/'.$newFilename
and then the contents of the file: file_get_contents()
with $file->getPathname()
.
... lines 1 - 10 | |
class UploaderHelper | |
{ | |
... lines 13 - 24 | |
public function uploadArticleImage(File $file): string | |
{ | |
... lines 27 - 33 | |
$this->filesystem->write( | |
self::ARTICLE_IMAGE.'/'.$newFilename, | |
file_get_contents($file->getPathname()) | |
); | |
... lines 38 - 39 | |
} | |
... lines 41 - 47 | |
} |
That's it! This File
object has a ton of different methods for getting the filename, the full path, the file without the extension and more. Honestly, I get them all confused and have to Google them. getPathname()
gives us the absolute file path on the filesystem.
Above, we can get rid of the unused $destination
variable. Because the filesystem's root is public/uploads/
, the only thing we need to pass to write()
is the path relative to that: article_image/
and then $newFilename
.
I think we're ready! Let's clear out the uploads/
directory again. And then try our fixtures:
php bin/console doctrine:fixtures:load
Oh! It does not work!
Unused binding
$uploadsPath
in serviceUniqueUserValidator
.
This is a bad error message from Symfony, at least the second half of the message. A minute ago, we had an argument here called $uploadsPath
. Open up config/services.yaml
. Ah, that worked because we have $uploadsPath
configured as a global bind. And when you configure a bind, it must be used in at least one place in your app. If it's not used anywhere, you get this error. It's kinda nice: Symfony is saying:
Hey! You configured this bind... but you're not using it - are you maybe... messing something up on accident?
The UniqueUserValidator
part of the message is really a bug in the error message, which makes this a bit confusing.
Anyways, remove that bind and try the fixtures again:
php bin/console doctrine:fixtures:load
This is the error I was waiting for.
Cannot autowire service
UploaderHelper
argument$filesystem
of__construct()
referencesFilesystemInterface
but no such service exists.
There are two ways to fix this. First, we could re-add the alias
option and point it at this FilesystemInterface
:
# config/packages/oneup_flysystem.yaml
oneup_flysystem:
# ...
filesystems:
public_uploads_filesystem:
adapter: public_uploads_adapter
alias: League\Flysystem\Filesystem
Or, we can create a new bind. I'll do the second, because it works better if you have multiple filesystem services, which we will soon. First, rename the argument to be more descriptive, how about $publicUploadFilesystem
:
... lines 1 - 10 | |
class UploaderHelper | |
{ | |
... lines 13 - 18 | |
public function __construct(FilesystemInterface $publicUploadsFilesystem, RequestStackContext $requestStackContext) | |
{ | |
$this->filesystem = $publicUploadsFilesystem; | |
... line 22 | |
} | |
... lines 24 - 47 | |
} |
Then, under bind, set $publicUploadFilesystem
to the filesystem service id - you can see it in the error. It suggests two services that implement the FilesystemInterface
type-hint - we want the second one. Type @
then paste.
... lines 1 - 9 | |
services: | |
... lines 11 - 19 | |
bind: | |
... lines 21 - 22 | |
$publicUploadsFilesystem: '@oneup_flysystem.public_uploads_filesystem_filesystem' | |
... lines 24 - 48 |
One more time for the fixtures!
php bin/console doctrine:fixtures:load
Ok, no error! Check out the public/uploads/
directory. Yes! We have files! Refresh the homepage. We are good! We still need to tweak a few more details, but our app is now way more ready to work locally or in the cloud.
// 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
"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
"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.17.6
"symfony/form": "^4.0", // v4.2.3
"symfony/framework-bundle": "^4.0", // v4.2.3
"symfony/orm-pack": "^1.0", // v1.0.6
"symfony/security-bundle": "^4.0", // v4.2.3
"symfony/serializer-pack": "^1.0", // v1.0.2
"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/profiler-pack": "^1.0", // v1.0.4
"symfony/var-dumper": "^3.3|^4.0" // v4.2.3
}
}