SlideShare a Scribd company logo
1 of 47
Filesystem abstraction
layer and message
queue for Symfony
About me
SergeevYuriy
Technical lead
Digital department 1+1 media
7 years with PHP
3 years with Symfony 😍
https://www.facebook.com/sergeevyv
Agenda
● Image processing packages (VichUploaderBundle,
LiipImagiuneBundle)
● Filesystem abstraction layer (Gaufrette)
● Message queue package (Enqueue)
● Symfony Messenger Component
Start from scratch
$form = $this->createFormBuilder()
->add('attachment', FileType::class)
->getForm();
// ...
if ($form->isSubmitted() && $form->isValid()) {
/** @var SymfonyComponentHttpFoundationFileUploadedFile $file */
$file = $form['attachment']->getData();
$file->move(
$this->getParameter('upload_directory'),
'image.jpg'
);
}
Real life problems
Folders structure
File names
Files & entities binding
Storage
Scaling
Thumbnails
Performance
Background handlers
Symfony Filesystem
Component
Basic utilities for the filesystem.
Methods: mkdir, exists, copy, touch, chown, chgrp, chmod, remove, rename, symlink, readlink,
makePathRelative, mirror, isAbsolutePath, dumpFile, appendToFile
$fileSystem->exists('/tmp/photos');
$fileSystem->dumpFile('file.txt', 'Hello World');
$fileSystem->remove(array('symlink', '/path/to/directory', 'activity.log'));
What about images?
VichUploaderBundle
- File and folder names
- Inject the file into the entity
- Delete the file upon removal of the entity
- Templating helpers
https://github.com/dustin10/VichUploaderBundle
Mapping
/**
* @VichUploadableField(mapping="product_image", fileNameProperty="imageName")
*/
private $imageFile;
/**
* @ORMColumn(type="string", length=255)
*/
private $imageName;
Manual upload
/**
* @ORMColumn(type="datetime")
*/
private $updatedAt;
//...
public function setImageFile(?File $image = null): void
{
$this->imageFile = $image;
if (null !== $image) {
$this->updatedAt = new DateTimeImmutable();
}
}
Configuration (events)
vich_uploader:
# ...
mappings:
product_image:
# ...
inject_on_load: false
delete_on_update: true
delete_on_remove: true
vich_uploader:
storage: file_system # one of ['gaufrette', 'flysystem',
'file_system']
mappings:
product_image:
# ...
inject_on_load: false
delete_on_update: true
delete_on_remove: true
Configuration (storage)
Gaufrette
http://knplabs.github.io/Gaufrette
Filesystem abstraction layer.
Data Abstraction layer Storage
Supported adapters:
Local, AWS S3, Google Cloud Storage, OpenCloud, FTP,
SFTP etc.
Basic usage
use GaufretteFilesystem;
use GaufretteAdapterLocal as LocalAdapter;
// First, you need a filesystem adapter
$adapter = new LocalAdapter('/var/media');
// Then, you can access your filesystem directly
var_dump($filesystem->read('myFile')); // bool(false)
$filesystem->write('myFile', 'Hello world!');
//Then, create filesystem with adapter
$filesystem = new Filesystem($adapter);
Extras: Resolvable filesystem
https://github.com/Gaufrette/extras
- AwsS3PublicUrlResolver: Create a URL for an object stored
on S3 with public ACL.
- AwsS3PresignedUrlResolver: Create a temporary URL, valid
for a given amount of time.
- StaticUrlResolver: Resolves the object into an URL by
concatenating a prefix with object path.
Usage example
$client = // AwsS3 client instantiation
$expDate = new DateTime('+ 1 hour');
$decorated = new Filesystem(
new AwsS3($client, 'my_bucket', ['directory' => 'root/dir'])
);
$filesystem = new ResolvableFilesystem(
$decorated,
new AwsS3PresignedUrlResolver($client, 'my_bucket', 'root/dir', $expDate)
);
$url = $filesystem->resolve('/foo/bar.png');
// https://eu-west-1.blabla.aws.com/my_bucket/root/dir/foo/bar.png?token
Symfony Integration -
KnpGaufretteBundle
https://github.com/KnpLabs/KnpGaufretteBundle
Filesystem map service: 'knp_gaufrette.filesystem_map'
Filesystem services: 'gaufrette.%filesystem_alias%'
Stream wrapper: protocol and filesystems config and ability to use code
like 'gaufrette://domain/file.txt'
Adapters and
Filesystems configuration
knp_gaufrette:
adapters:
foo:
local:
directory: /path/to/my/filesystem
create: true
knp_gaufrette:
filesystems:
bar:
adapter: foo
alias: foo_filesystem
aws:
adapter: profile_photos
profile_photos:
aws_s3:
service_id: 'acme.aws_s3.client'
bucket_name: 'images'
detect_content_type: true
custom_adapter:
service:
id: 'my.adapter.service'
Basic usage
// get from filesystem map service
$container->get('knp_gaufrette.filesystem_map')->get('bar');
//get by filesystem alias “foo”
$container->get('gaufrette.foo_filesystem');
//stream_wrapper usage example
$fileStream = sprintf('gaufrette://your_defined_fs/%s', 'path/to/file.pdf');
$response = new BinaryFileResponse($fileStream);
Back to VichUploader
vich_uploader:
storage: gaufrette
mappings:
product_image:
uri_prefix: /images/products
upload_destination: aws # gaufrette filesystem name
What about
thumbnails?
LiipImagineBundle
https://github.com/liip/LiipImagineBundle
- Filters, filter sets (size, orientation etc.)
- Post processors (JPEG Optim, Opti PNG etc.)
- Runtime filter configuration
- Background processing
- Data Loaders
- Cache Resolvers
<img src="{{ asset('/relative/path/to/image.jpg') | imagine_filter('my_thumb') }}" />
Data Loaders
liip_imagine:
loaders:
stream.profile_photos:
stream:
wrapper: gaufrette://profile_photos
Custom loader
interface LoaderInterface
{
public function find($path);
}
Cache Resolvers
interface ResolverInterface
{
public function isStored($path, $filter);
public function resolve($path, $filter);
public function store(BinaryInterface $binary, $path, $filter);
public function remove(array $paths, array $filters);
}
When to do it?
kernel.terminate
Do stuff
kernel.terminate
How it works: fastcgi_finish_request()
When to use:
- short time processes
- small number of requests
Possible problems:
- exceptions breaks profiler
- execution control complexity
- pm.max_children limitation
Enqueue
https://github.com/php-enqueue/enqueue-dev
- Remote Procedure Calls
- Job queue
- Async commands
- frameworks integration: Symfony, Magento, Laravel,
Yii2
Supported transports: AMQP, Amazon SQS, Kafka, Redis,
Gearman, Mongodb etc.
How it works
Producer Consumer
Queue
Messages
Message
use EnqueueClientMessage;
use EnqueueClientMessagePriority;
$message = new Message();
$message->setBody('Hello %username%');
$message->setPriority(MessagePriority::NORMAL);
Message Producer
//send to all "fire and forget"
$producer->sendEvent('a_topic', 'Hello there!');
use EnqueueClientProducerInterface;
$producer = $container->get(ProducerInterface::class);
// send to one consumer
$producer->sendCommand('a_processor_name', 'Hello there!');
Spool Producer
use EnqueueClientSpoolProducer;
$spoolProducer = $container->get(SpoolProducer::class);
// messages is being sent on console.terminate or kernel.terminate event
$spoolProducer->sendEvent('a_topic', 'Hello there!');
$spoolProducer->sendCommand('a_processor_name', 'Hello there!');
// you could send queued messages manually by calling flush method
$spoolProducer->flush();
Message Processor
use InteropQueuePsrProcessor;
use InteropQueuePsrMessage;
use InteropQueuePsrContext;
class SendMailProcessor implements PsrProcessor
{
public function process(PsrMessage $message, PsrContext $context)
{
$this->mailer->send('foo@example.com', $message->getBody());
return self::ACK;
}
}
Consumer extensions
use InteropQueuePsrContext;
use EnqueueConsumptionChainExtension;
use EnqueueConsumptionQueueConsumer;
use EnqueueConsumptionExtensionReplyExtension;
/** @var InteropQueuePsrContext $psrContext */
$queueConsumer = new QueueConsumer(
$psrContext,
new ChainExtension([
new ReplyExtension()
])
);
Reply extension
use EnqueueConsumptionResult;
use InteropQueuePsrProcessor;
use InteropQueuePsrMessage;
use InteropQueuePsrContext;
class SendMailProcessor implements PsrProcessor
{
public function process(PsrMessage $message, PsrContext $context)
{
$this->mailer->send('foo@example.com', $message->getBody());
$replyMessage = $context->createMessage('Message has been sent');
return Result::reply($replyMessage);
}
}
Async commands
(enqueue/async-command)
use EnqueueAsyncCommand{CommandResult, Commands, RunCommand};
$promise = $producer->sendCommand(
Commands::RUN_COMMAND,
new RunCommand('debug:container'),
true
);
// do other stuff.
if ($replyMessage = $promise->receive(5000)) {
$result = CommandResult::jsonUnserialize($replyMessage->getBody());
echo $result->getOutput();
}
Testing & Debugging
enqueue:
transport: 'null:'
client:
traceable_producer: true
use EnqueueClientTraceableProducer;
use SymfonyBundleFrameworkBundleClient;
// ...
$service = $client->getContainer()->get('a_service');
// the method calls inside $producer->send('fooTopic', 'messageBody');
$service->do();
$producer = $client->getContainer()->get(TraceableProducer::class);
$traces = $producer->getTopicTraces('fooTopic');
//use inside SomeServiceTest
$this->assertCount(1, $traces);
$this->assertEquals('messageBody', $traces[0]['message']);
Integration with
LiipImagineBundle
enqueue:
transport: "amqp:"
client: ~
liip_imagine:
enqueue: true
./bin/console enqueue:consume --setup-broker -vvv
Run consumer
Long running commands
● Clear all Doctrine ORM entity managers (to prevent outdated entities from being
updated)
● Reset all closed Doctrine ORM entity managers (after a failed transaction)
● Close all database connections (to prevent database timeout errors)
● Clear all Monolog "fingers crossed" handlers (clears messages and resets the handler
when there was no failure during the execution of a task)
● Close all Monolog buffer handlers (clears log messages that were buffered during the
execution of a task)
● Flush all Swift Mailer "in memory" spools (i.e. send spooled e-mails)
● Flush all unsent Sentry errors (in case they are handled async)
https://github.com/LongRunning/LongRunning
''long_running.delegating_cleaner'' service
Alternative - Messenger
Component
https://symfony.com/doc/current/components/messenger.html
Message Bus
use AppMessageMyMessage;
use SymfonyComponentMessengerMessageBus;
use SymfonyComponentMessengerHandlerLocatorHandlerLocator;
use SymfonyComponentMessengerMiddlewareHandleMessageMiddleware;
$bus = new MessageBus([
new HandleMessageMiddleware(new HandlerLocator([
MyMessage::class => $handler,
])),
]);
//Default middleware: LoggingMiddleware, SendMessageMiddleware, HandleMessageMiddleware
$result = $bus->dispatch(new MyMessage(/* ... */));
Message Handler
use AppMessageMyMessage;
class MyMessageHandler
{
public function __invoke(MyMessage $message)
{
// Message processing...
}
}
Message Envelope
use SymfonyComponentMessengerEnvelope;
use SymfonyComponentMessengerTransportSerializationSerializerConfiguration;
$bus->dispatch(
(new Envelope($message))->with(new SerializerConfiguration([
'groups' => ['my_serialization_groups'],
]))
);
//Built-in envelopes: SerializerConfiguration, ValidationConfiguration, ReceivedMessage
Conclusions
Links
VichUploaderBundle - https://github.com/dustin10/VichUploaderBundle
LiipImagineBundle - https://github.com/liip/LiipImagineBundle
Gaufrette - http://knplabs.github.io/Gaufrette/
KnpGaufretteBundle - https://github.com/KnpLabs/KnpGaufretteBundle
Enqueue - https://github.com/php-enqueue/enqueue-dev
Enqueue Bundle - https://github.com/php-enqueue/enqueue-bundle
LongRunning - https://github.com/LongRunning/LongRunning
Symfony Messenger - https://symfony.com/doc/current/components/messenger.html
Thanks!

More Related Content

What's hot

The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010Fabien Potencier
 
Webrtc mojo
Webrtc mojoWebrtc mojo
Webrtc mojobpmedley
 
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]Eleanor McHugh
 
solving little problems
solving little problemssolving little problems
solving little problemsAustin Ziegler
 
4069180 Caching Performance Lessons From Facebook
4069180 Caching Performance Lessons From Facebook4069180 Caching Performance Lessons From Facebook
4069180 Caching Performance Lessons From Facebookguoqing75
 
Forget about loops
Forget about loopsForget about loops
Forget about loopsDušan Kasan
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Fabien Potencier
 
Shell实现的windows回收站功能的脚本
Shell实现的windows回收站功能的脚本Shell实现的windows回收站功能的脚本
Shell实现的windows回收站功能的脚本Lingfei Kong
 
vfsStream - effective filesystem mocking
vfsStream - effective filesystem mocking vfsStream - effective filesystem mocking
vfsStream - effective filesystem mocking Sebastian Marek
 
Perl web frameworks
Perl web frameworksPerl web frameworks
Perl web frameworksdiego_k
 
Introduction to CloudForecast / YAPC::Asia 2010 Tokyo
Introduction to CloudForecast / YAPC::Asia 2010 TokyoIntroduction to CloudForecast / YAPC::Asia 2010 Tokyo
Introduction to CloudForecast / YAPC::Asia 2010 TokyoMasahiro Nagano
 
vfsStream - a better approach for file system dependent tests
vfsStream - a better approach for file system dependent testsvfsStream - a better approach for file system dependent tests
vfsStream - a better approach for file system dependent testsFrank Kleine
 
Clase 15 FOS
Clase 15 FOSClase 15 FOS
Clase 15 FOShydras_cs
 
Crud operations using aws dynamo db with flask ap is and boto3
Crud operations using aws dynamo db with flask ap is and boto3Crud operations using aws dynamo db with flask ap is and boto3
Crud operations using aws dynamo db with flask ap is and boto3Katy Slemon
 
The Enterprise Wor/d/thy/Press
The Enterprise Wor/d/thy/PressThe Enterprise Wor/d/thy/Press
The Enterprise Wor/d/thy/PressJeroen van Dijk
 

What's hot (20)

The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010
 
PhpBB meets Symfony2
PhpBB meets Symfony2PhpBB meets Symfony2
PhpBB meets Symfony2
 
Symfony2 - OSIDays 2010
Symfony2 - OSIDays 2010Symfony2 - OSIDays 2010
Symfony2 - OSIDays 2010
 
Webrtc mojo
Webrtc mojoWebrtc mojo
Webrtc mojo
 
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
 
solving little problems
solving little problemssolving little problems
solving little problems
 
4069180 Caching Performance Lessons From Facebook
4069180 Caching Performance Lessons From Facebook4069180 Caching Performance Lessons From Facebook
4069180 Caching Performance Lessons From Facebook
 
Tutorial Puppet
Tutorial PuppetTutorial Puppet
Tutorial Puppet
 
ReactPHP
ReactPHPReactPHP
ReactPHP
 
Forget about loops
Forget about loopsForget about loops
Forget about loops
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2
 
Shell实现的windows回收站功能的脚本
Shell实现的windows回收站功能的脚本Shell实现的windows回收站功能的脚本
Shell实现的windows回收站功能的脚本
 
vfsStream - effective filesystem mocking
vfsStream - effective filesystem mocking vfsStream - effective filesystem mocking
vfsStream - effective filesystem mocking
 
Perl web frameworks
Perl web frameworksPerl web frameworks
Perl web frameworks
 
Introduction to CloudForecast / YAPC::Asia 2010 Tokyo
Introduction to CloudForecast / YAPC::Asia 2010 TokyoIntroduction to CloudForecast / YAPC::Asia 2010 Tokyo
Introduction to CloudForecast / YAPC::Asia 2010 Tokyo
 
vfsStream - a better approach for file system dependent tests
vfsStream - a better approach for file system dependent testsvfsStream - a better approach for file system dependent tests
vfsStream - a better approach for file system dependent tests
 
Clase 15 FOS
Clase 15 FOSClase 15 FOS
Clase 15 FOS
 
Crud operations using aws dynamo db with flask ap is and boto3
Crud operations using aws dynamo db with flask ap is and boto3Crud operations using aws dynamo db with flask ap is and boto3
Crud operations using aws dynamo db with flask ap is and boto3
 
The Enterprise Wor/d/thy/Press
The Enterprise Wor/d/thy/PressThe Enterprise Wor/d/thy/Press
The Enterprise Wor/d/thy/Press
 
Fabric Python Lib
Fabric Python LibFabric Python Lib
Fabric Python Lib
 

Similar to Filesystem abstractions and msg queue sergeev - symfony camp 2018

Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsMichael Peacock
 
Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12Jakub Zalas
 
Symfony internals [english]
Symfony internals [english]Symfony internals [english]
Symfony internals [english]Raul Fraile
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony TechniquesKris Wallsmith
 
Aura Project for PHP
Aura Project for PHPAura Project for PHP
Aura Project for PHPHari K T
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteLeonardo Proietti
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Hugo Hamon
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleHugo Hamon
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony AppsKris Wallsmith
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of LithiumNate Abele
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownpartsBastian Feder
 
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnitinternational PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnitsmueller_sandsmedia
 
Mastering the AWS SDK for PHP (TLS306) | AWS re:Invent 2013
Mastering the AWS SDK for PHP (TLS306) | AWS re:Invent 2013Mastering the AWS SDK for PHP (TLS306) | AWS re:Invent 2013
Mastering the AWS SDK for PHP (TLS306) | AWS re:Invent 2013Amazon Web Services
 
Flask patterns
Flask patternsFlask patterns
Flask patternsit-people
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207patter
 
I Phone On Rails
I Phone On RailsI Phone On Rails
I Phone On RailsJohn Wilker
 
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowForget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowKacper Gunia
 

Similar to Filesystem abstractions and msg queue sergeev - symfony camp 2018 (20)

Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friends
 
Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12
 
Symfony internals [english]
Symfony internals [english]Symfony internals [english]
Symfony internals [english]
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony Techniques
 
Aura Project for PHP
Aura Project for PHPAura Project for PHP
Aura Project for PHP
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il cliente
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2
 
Symfony2 revealed
Symfony2 revealedSymfony2 revealed
Symfony2 revealed
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony Apps
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of Lithium
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
 
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnitinternational PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
 
Mastering the AWS SDK for PHP (TLS306) | AWS re:Invent 2013
Mastering the AWS SDK for PHP (TLS306) | AWS re:Invent 2013Mastering the AWS SDK for PHP (TLS306) | AWS re:Invent 2013
Mastering the AWS SDK for PHP (TLS306) | AWS re:Invent 2013
 
Flask patterns
Flask patternsFlask patterns
Flask patterns
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207
 
I Phone On Rails
I Phone On RailsI Phone On Rails
I Phone On Rails
 
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowForget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers Cracow
 

More from Юлия Коваленко (7)

Архитектура фронтенда и дизайн-системы
Архитектура фронтенда и дизайн-системыАрхитектура фронтенда и дизайн-системы
Архитектура фронтенда и дизайн-системы
 
Blockchain
Blockchain Blockchain
Blockchain
 
Symfony 2018 slides
Symfony 2018 slidesSymfony 2018 slides
Symfony 2018 slides
 
Modularity problems
Modularity  problemsModularity  problems
Modularity problems
 
20181023 progressive web_apps_are_here_sfcampua
20181023 progressive web_apps_are_here_sfcampua20181023 progressive web_apps_are_here_sfcampua
20181023 progressive web_apps_are_here_sfcampua
 
Contract testing symfony camp 2018
  Contract testing symfony camp 2018  Contract testing symfony camp 2018
Contract testing symfony camp 2018
 
Database types-1 (1)
Database types-1 (1)Database types-1 (1)
Database types-1 (1)
 

Recently uploaded

"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024BookNet Canada
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
Bluetooth Controlled Car with Arduino.pdf
Bluetooth Controlled Car with Arduino.pdfBluetooth Controlled Car with Arduino.pdf
Bluetooth Controlled Car with Arduino.pdfngoud9212
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Wonjun Hwang
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDGMarianaLemus7
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024The Digital Insurer
 

Recently uploaded (20)

"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
Bluetooth Controlled Car with Arduino.pdf
Bluetooth Controlled Car with Arduino.pdfBluetooth Controlled Car with Arduino.pdf
Bluetooth Controlled Car with Arduino.pdf
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDG
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024
 

Filesystem abstractions and msg queue sergeev - symfony camp 2018

  • 1.
  • 2. Filesystem abstraction layer and message queue for Symfony
  • 3. About me SergeevYuriy Technical lead Digital department 1+1 media 7 years with PHP 3 years with Symfony 😍 https://www.facebook.com/sergeevyv
  • 4. Agenda ● Image processing packages (VichUploaderBundle, LiipImagiuneBundle) ● Filesystem abstraction layer (Gaufrette) ● Message queue package (Enqueue) ● Symfony Messenger Component
  • 5. Start from scratch $form = $this->createFormBuilder() ->add('attachment', FileType::class) ->getForm(); // ... if ($form->isSubmitted() && $form->isValid()) { /** @var SymfonyComponentHttpFoundationFileUploadedFile $file */ $file = $form['attachment']->getData(); $file->move( $this->getParameter('upload_directory'), 'image.jpg' ); }
  • 6. Real life problems Folders structure File names Files & entities binding Storage Scaling Thumbnails Performance Background handlers
  • 7. Symfony Filesystem Component Basic utilities for the filesystem. Methods: mkdir, exists, copy, touch, chown, chgrp, chmod, remove, rename, symlink, readlink, makePathRelative, mirror, isAbsolutePath, dumpFile, appendToFile $fileSystem->exists('/tmp/photos'); $fileSystem->dumpFile('file.txt', 'Hello World'); $fileSystem->remove(array('symlink', '/path/to/directory', 'activity.log'));
  • 9. VichUploaderBundle - File and folder names - Inject the file into the entity - Delete the file upon removal of the entity - Templating helpers https://github.com/dustin10/VichUploaderBundle
  • 10. Mapping /** * @VichUploadableField(mapping="product_image", fileNameProperty="imageName") */ private $imageFile; /** * @ORMColumn(type="string", length=255) */ private $imageName;
  • 11. Manual upload /** * @ORMColumn(type="datetime") */ private $updatedAt; //... public function setImageFile(?File $image = null): void { $this->imageFile = $image; if (null !== $image) { $this->updatedAt = new DateTimeImmutable(); } }
  • 12. Configuration (events) vich_uploader: # ... mappings: product_image: # ... inject_on_load: false delete_on_update: true delete_on_remove: true
  • 13. vich_uploader: storage: file_system # one of ['gaufrette', 'flysystem', 'file_system'] mappings: product_image: # ... inject_on_load: false delete_on_update: true delete_on_remove: true Configuration (storage)
  • 14. Gaufrette http://knplabs.github.io/Gaufrette Filesystem abstraction layer. Data Abstraction layer Storage Supported adapters: Local, AWS S3, Google Cloud Storage, OpenCloud, FTP, SFTP etc.
  • 15. Basic usage use GaufretteFilesystem; use GaufretteAdapterLocal as LocalAdapter; // First, you need a filesystem adapter $adapter = new LocalAdapter('/var/media'); // Then, you can access your filesystem directly var_dump($filesystem->read('myFile')); // bool(false) $filesystem->write('myFile', 'Hello world!'); //Then, create filesystem with adapter $filesystem = new Filesystem($adapter);
  • 16. Extras: Resolvable filesystem https://github.com/Gaufrette/extras - AwsS3PublicUrlResolver: Create a URL for an object stored on S3 with public ACL. - AwsS3PresignedUrlResolver: Create a temporary URL, valid for a given amount of time. - StaticUrlResolver: Resolves the object into an URL by concatenating a prefix with object path.
  • 17. Usage example $client = // AwsS3 client instantiation $expDate = new DateTime('+ 1 hour'); $decorated = new Filesystem( new AwsS3($client, 'my_bucket', ['directory' => 'root/dir']) ); $filesystem = new ResolvableFilesystem( $decorated, new AwsS3PresignedUrlResolver($client, 'my_bucket', 'root/dir', $expDate) ); $url = $filesystem->resolve('/foo/bar.png'); // https://eu-west-1.blabla.aws.com/my_bucket/root/dir/foo/bar.png?token
  • 18. Symfony Integration - KnpGaufretteBundle https://github.com/KnpLabs/KnpGaufretteBundle Filesystem map service: 'knp_gaufrette.filesystem_map' Filesystem services: 'gaufrette.%filesystem_alias%' Stream wrapper: protocol and filesystems config and ability to use code like 'gaufrette://domain/file.txt'
  • 19. Adapters and Filesystems configuration knp_gaufrette: adapters: foo: local: directory: /path/to/my/filesystem create: true knp_gaufrette: filesystems: bar: adapter: foo alias: foo_filesystem aws: adapter: profile_photos profile_photos: aws_s3: service_id: 'acme.aws_s3.client' bucket_name: 'images' detect_content_type: true custom_adapter: service: id: 'my.adapter.service'
  • 20. Basic usage // get from filesystem map service $container->get('knp_gaufrette.filesystem_map')->get('bar'); //get by filesystem alias “foo” $container->get('gaufrette.foo_filesystem'); //stream_wrapper usage example $fileStream = sprintf('gaufrette://your_defined_fs/%s', 'path/to/file.pdf'); $response = new BinaryFileResponse($fileStream);
  • 21. Back to VichUploader vich_uploader: storage: gaufrette mappings: product_image: uri_prefix: /images/products upload_destination: aws # gaufrette filesystem name
  • 23. LiipImagineBundle https://github.com/liip/LiipImagineBundle - Filters, filter sets (size, orientation etc.) - Post processors (JPEG Optim, Opti PNG etc.) - Runtime filter configuration - Background processing - Data Loaders - Cache Resolvers <img src="{{ asset('/relative/path/to/image.jpg') | imagine_filter('my_thumb') }}" />
  • 25. Cache Resolvers interface ResolverInterface { public function isStored($path, $filter); public function resolve($path, $filter); public function store(BinaryInterface $binary, $path, $filter); public function remove(array $paths, array $filters); }
  • 26. When to do it?
  • 28. kernel.terminate How it works: fastcgi_finish_request() When to use: - short time processes - small number of requests Possible problems: - exceptions breaks profiler - execution control complexity - pm.max_children limitation
  • 29. Enqueue https://github.com/php-enqueue/enqueue-dev - Remote Procedure Calls - Job queue - Async commands - frameworks integration: Symfony, Magento, Laravel, Yii2 Supported transports: AMQP, Amazon SQS, Kafka, Redis, Gearman, Mongodb etc.
  • 30. How it works Producer Consumer Queue Messages
  • 31. Message use EnqueueClientMessage; use EnqueueClientMessagePriority; $message = new Message(); $message->setBody('Hello %username%'); $message->setPriority(MessagePriority::NORMAL);
  • 32. Message Producer //send to all "fire and forget" $producer->sendEvent('a_topic', 'Hello there!'); use EnqueueClientProducerInterface; $producer = $container->get(ProducerInterface::class); // send to one consumer $producer->sendCommand('a_processor_name', 'Hello there!');
  • 33. Spool Producer use EnqueueClientSpoolProducer; $spoolProducer = $container->get(SpoolProducer::class); // messages is being sent on console.terminate or kernel.terminate event $spoolProducer->sendEvent('a_topic', 'Hello there!'); $spoolProducer->sendCommand('a_processor_name', 'Hello there!'); // you could send queued messages manually by calling flush method $spoolProducer->flush();
  • 34. Message Processor use InteropQueuePsrProcessor; use InteropQueuePsrMessage; use InteropQueuePsrContext; class SendMailProcessor implements PsrProcessor { public function process(PsrMessage $message, PsrContext $context) { $this->mailer->send('foo@example.com', $message->getBody()); return self::ACK; } }
  • 35. Consumer extensions use InteropQueuePsrContext; use EnqueueConsumptionChainExtension; use EnqueueConsumptionQueueConsumer; use EnqueueConsumptionExtensionReplyExtension; /** @var InteropQueuePsrContext $psrContext */ $queueConsumer = new QueueConsumer( $psrContext, new ChainExtension([ new ReplyExtension() ]) );
  • 36. Reply extension use EnqueueConsumptionResult; use InteropQueuePsrProcessor; use InteropQueuePsrMessage; use InteropQueuePsrContext; class SendMailProcessor implements PsrProcessor { public function process(PsrMessage $message, PsrContext $context) { $this->mailer->send('foo@example.com', $message->getBody()); $replyMessage = $context->createMessage('Message has been sent'); return Result::reply($replyMessage); } }
  • 37. Async commands (enqueue/async-command) use EnqueueAsyncCommand{CommandResult, Commands, RunCommand}; $promise = $producer->sendCommand( Commands::RUN_COMMAND, new RunCommand('debug:container'), true ); // do other stuff. if ($replyMessage = $promise->receive(5000)) { $result = CommandResult::jsonUnserialize($replyMessage->getBody()); echo $result->getOutput(); }
  • 38. Testing & Debugging enqueue: transport: 'null:' client: traceable_producer: true use EnqueueClientTraceableProducer; use SymfonyBundleFrameworkBundleClient; // ... $service = $client->getContainer()->get('a_service'); // the method calls inside $producer->send('fooTopic', 'messageBody'); $service->do(); $producer = $client->getContainer()->get(TraceableProducer::class); $traces = $producer->getTopicTraces('fooTopic'); //use inside SomeServiceTest $this->assertCount(1, $traces); $this->assertEquals('messageBody', $traces[0]['message']);
  • 39. Integration with LiipImagineBundle enqueue: transport: "amqp:" client: ~ liip_imagine: enqueue: true ./bin/console enqueue:consume --setup-broker -vvv Run consumer
  • 40. Long running commands ● Clear all Doctrine ORM entity managers (to prevent outdated entities from being updated) ● Reset all closed Doctrine ORM entity managers (after a failed transaction) ● Close all database connections (to prevent database timeout errors) ● Clear all Monolog "fingers crossed" handlers (clears messages and resets the handler when there was no failure during the execution of a task) ● Close all Monolog buffer handlers (clears log messages that were buffered during the execution of a task) ● Flush all Swift Mailer "in memory" spools (i.e. send spooled e-mails) ● Flush all unsent Sentry errors (in case they are handled async) https://github.com/LongRunning/LongRunning ''long_running.delegating_cleaner'' service
  • 42. Message Bus use AppMessageMyMessage; use SymfonyComponentMessengerMessageBus; use SymfonyComponentMessengerHandlerLocatorHandlerLocator; use SymfonyComponentMessengerMiddlewareHandleMessageMiddleware; $bus = new MessageBus([ new HandleMessageMiddleware(new HandlerLocator([ MyMessage::class => $handler, ])), ]); //Default middleware: LoggingMiddleware, SendMessageMiddleware, HandleMessageMiddleware $result = $bus->dispatch(new MyMessage(/* ... */));
  • 43. Message Handler use AppMessageMyMessage; class MyMessageHandler { public function __invoke(MyMessage $message) { // Message processing... } }
  • 44. Message Envelope use SymfonyComponentMessengerEnvelope; use SymfonyComponentMessengerTransportSerializationSerializerConfiguration; $bus->dispatch( (new Envelope($message))->with(new SerializerConfiguration([ 'groups' => ['my_serialization_groups'], ])) ); //Built-in envelopes: SerializerConfiguration, ValidationConfiguration, ReceivedMessage
  • 46. Links VichUploaderBundle - https://github.com/dustin10/VichUploaderBundle LiipImagineBundle - https://github.com/liip/LiipImagineBundle Gaufrette - http://knplabs.github.io/Gaufrette/ KnpGaufretteBundle - https://github.com/KnpLabs/KnpGaufretteBundle Enqueue - https://github.com/php-enqueue/enqueue-dev Enqueue Bundle - https://github.com/php-enqueue/enqueue-bundle LongRunning - https://github.com/LongRunning/LongRunning Symfony Messenger - https://symfony.com/doc/current/components/messenger.html

Editor's Notes

  1. какие у нас есть проекты, что на симфони
  2. Минимально необходымий рабочий код
  3. Задачи и проблемы, которые возникают в реальном проекте
  4. Работа с файловой системой из коробки, базовые операции
  5. Свой велосипед, или ищем готовые решения
  6. Основные задачи которые закрывает вич аплоадер
  7. Доп поля для мапинга (size, mimeType, originalName, dimensions) Задача свойства updatedAt (если вручную сетаем файл - обновляем updatedAt)
  8. Конфиг для эвентов и абстракция для файловой системы, здесь подходим к использованию Gaugrette
  9. Общая инфа по адаптерам
  10. Возможность юзать сервисы в качестве адаптеров
  11. Меняем storage + upload_destination Включаем stream_wrapper
  12. pm.max_children для terminate
  13. context нужен если прокидываем новые сообщения или очереди
  14. superviser для консьюмеров