Symfony2 Define Media Uploaded Directory in Config file and access it it in controller twig - symfony

In my project i have lot of different types of document of user to be uploaded. I am using local drive to save media and ony save the file. What it want is to define the uploaded directory in only configuration file (category wise) access it in controller and twig files. so that if i changed the media path later, i have to change it only once and should work everywhere?
I know lot bundle available for this, but i am not using any bundle I used doctrine to upload this media. More, later i also move this media to Amazon S3.

You can do it directly in parameters.yml:
parameters:
/.../
media_directory: '%kernel.root_dir%/../web/uploads'
And you can have access in controller like all other parameters:
public function someAction()
{
$directory = $this->getParameter('media_directory');
}
EDIT
For twig, try like that:
<p>Media Directory: {{ media_directory }}</p>
Before, I think you have to declare twig global var in app/config/config.yml:
# Twig Configuration
twig:
globals:
media_directory: %media_directory%

Related

Symfony Twig config : how to exclude a folder from cached files

I have added a path entry in Twig config so I can also use template located in this folder:
twig:
paths:
'%kernel.project_dir%/modules': Modules
I would like to disable the cache only for this path, is this possible ?
If I do:
twig:
cache: false
Then caching is disabled for all templates, even the default path (ie the files inside app/templates/...)
Another person will update these templates regularly and I want the app to take the changes into account without him having to call me to empty the Symfony cache (he has an ftp access to the template folder, but he has no access to the Symfony console to clear the cache)

Symfony2 - Gregwar/Image Bundle - resized images cache to S3 (Cloudfront)

I would like to use the Amazon Cloudfront service as a CDN.
My question is:
How can get Gregwar/ImageBundle to work with S3?
So this:
{% set img_path = asset('assets/' ~ app.request.get('product_id') ~ '/images/' ~ contents.background) %}
<img src="{{ web_image(img_path).forceResize(1000) }}" alt="{{contents.title|default('') }}">
generates this:
https://s3-cdn.com/cache/f/5/f/1/4/f5f1407eb85e38e94019a03082b10611f57b22e5.png
instead of this:
/cache/f/5/f/1/4/f5f1407eb85e38e94019a03082b10611f57b22e5.png (local fylesystem)
Some update:
I could figure out the asset dumping with this:
Dump Symfony2 assets to Amazon S3
I can not set the permission to readable for the public.
I have written a stream wrapper for S3 (protocol) in Symfony.
Also it seems that the Gregwar/ImagineBundle does not support CDN...
As you track down the upload folder config, you can see... tell me if i wrong...
Other thing:
https://github.com/symfony/symfony/issues/4014
Closing as generating the cache directly on S3 won't be supported as
there are many other ways to move files from the computer where you
generated your cache to S3.
by fabpot
Anyway it is sorted out as I can use the assetic:install in symfony command line, just could not figure out setting the public access for the uploaded/generated assets with S3 streamwrapper...
Problems remaining:
symfony assetic install/dump to S3 with the right settings so
available for the public
Gregwar/ImageBundle -> generated images (ie.: forceResize(), usually to /web/cache/...) to CDN
Another update:
symfony assetic install/dump -> I decided to use Bower and Grunt to get the same result. Still no idea how to add that public amazon ACL thingie for the command line... sorry, add a comment here if you know
image uploads -> I am on to "extend" the symfony UploadedFile so when that is triggered to move the file, than the official AWS SDK S3 take over the process and handles it... will let you know with the solution.... [update] I could not modify the move method in a "standard" or non-hacking way. So I created a helper class (using the SDK) and did refactoring with it on the right places.
the Gregwar/ImageBundle cache (after processing images based upon the Twig "function" you know .forceResize) still outstanding... any thoughts are welcome
Cheers
Greg
If https://s3-cdn.com will not change you can concatenate it for your src like this :
src="https://s3-cdn.com~{{ web_image(img_path).forceResize(1000) }}"
or make a twig extension to be cleaner or override the web_image function to build correctly your url and return the right one, overriding it would result on the bundle working only for S3.
update
This question is ambiguous, he wants to upload to S3 not read from it, the twig have nothing to do here.
for more information on the upload :
github.com/1up-lab/OneupFlysystemBundle/blob/master/Resources/… this is a nice bundle it uses the league/flysystem take a look at the page see how they handle uploads to amazon flysystem.thephpleague.com/adapter/aws-s3-v3

Specify alternative fallback paths for Symfony to find twig templates for bundles

Basic Question
How can you make symfony look in non-standard directories to find the "best" (custom) Twig template to load for a bundle view?
The Symfony docs say by default it looks in two locations to override a Twig template
When the AcmeBlogBundle:Blog:index.html.twig is rendered, Symfony
actually looks in two different locations for the template:
app/Resources/AcmeBlogBundle/views/Blog/index.html.twig
src/Acme/BlogBundle/Resources/views/Blog/index.html.twig
But this is discussing how you would override a vendor bundle. In my case, I have native bundles in my /src/ that I want to overwrite on a per Design Template or Client specific basis. It needs to look in:
Client: /var/www/vhosts/{ID}/src
Template: /var/www/core/cms/src/Gutensite/TemplateBundle/Templates/Admin/src
Twig Loader has a convenient method to add paths:
$templatePath = '/var/www/core/cms/src/Gutensite/TemplateBundle/Templates/Admin/Resources/views';
$this->container->get('twig.loader')->prependPath($templatePath, 'template');
This allows me to register an alternative path to the template resources, so that I can render the template shell like this:
{% extends '#template/shell/shell.html.twig' %}
But what about when I want to overwrite a bundle template, e.g.
Original: /var/www/core/cms/src/Gutensite/MenuBundle/Resources/views/Menu.html.twig
Custom: /var/www/core/cms/src/Gutensite/TemplateBundle/Templates/Admin/src/Gutensite/MenuBundle/Resources/views/Menu.html.twig
How do I register a generic /src/ file so that Symfony looks in there for all references to Vendor Bundle paths, e.g. trying to render #GutensiteMenu/Menu.html.twig will first look in the custom directory for 1) Client , 2) Template, 3) default bundle directory by that name.
Need Assets
Because my TemplateBundle/Templates/Admin/Resources/ are in a non-standard location, assetic won't dump them to the public directory (or create symlinks)... so I'm not sure how to dynamically make assetic find these files.
I'm also not sure how to load the assets that are in these other locations, e.g. this doesn't work:
{% stylesheets '#GutensiteTemplateBundle/Templates/Admin/Resources/public/css/site.css' %}
<link rel="stylesheet" href="{{ asset_url }}">
{% endstylesheets %}
Presumably because it's not dumped.
Why do I need this?
I am building a hosted CMS that is a core vendor which contain various bundles with controllers and templates, e.g. /Gutensite/CmsBundle, Gutensite/ArticleBundle.
Based on the selected "Design Template" for a site, a design template is referenced in a TemplateBundle, e.g. /TemplateBundle/Templates/Admin (a template called "Admin"). The TemplateBundle need to be able to override the core controllers or views.
I have registered the Gutensite/TemplateBundle/Templates/Admin/src/ folder as an alternative namespace for the Composer app/autoload.php, so that controllers can be overwritten as long as they have the same Gutensite namespace (and this works great):
// in my primary controller:
$loader = $GLOBALS['loader'];
$loader->add('Gutensite', '/var/www/core/cms/src/Gutensite/TemplateBundle/Templates/Admin/src', true);
NOTE: I could register every single template as a bundle, and that would theoretically allow me to override controllers and bundles using symfony's built in methods. But this would add a lot of "bundles" that aren't really traditional bundles. Also I need the above solution to point to alternative template paths, because I also need the ability to point to client's custom files located outside the normal symfony root directory (which I successfully do with the namespace auto loader paths for controllers).
You can use the path option in the twig configuration, with the same namespace for 2 paths.
twig:
# ...
paths:
"%kernel.root_dir%/../src/Gutensite/MenuBundle/Resources/views": templates
"%kernel.root_dir%/../src/Gutensite/TemplateBundle/Templates/Admin/src/Gutensite/MenuBundle/Resources/views": templates
Then, using #templates/Menu.html.twig will first look for Menu.html.twig in MenuBundle, then in TemplateBundle.
That's this way that the TwigExtension is registering paths so the loader is looking in app/Resources/views and then in the bundle's views.

Symfony translations not working

I have done the following checklist:
created translation file respecting format domain.lang.loader
cleared cache
checked that language catalogue is created in cache folder
Though in my twig template file,
{{ 'message'|trans }}
never translates.
Where can I look next in order to make translations work?
Is there any chance that Doctrine Translatable Extension that I am using generates some kind of conflicts?
In Symfony 3.0 I had to clear the cache:
php bin/console cache:clear
I see you already did that, maybe it helps other like me.
Have you enabled the Translator service in your config file?
framework:
translator: { fallbacks: en }
The language catalogue is created in your cache folder irrespective of whether your translator is enabled or not.
Did you try translating in your controller?
$trans = $this->get('translator')->trans('message');
Try to specify domain. If you not specify domain by default it a messages.
{{ 'message'|trans({}, 'some_domain') }}
Then translations can be found in
the kernel root directory/Resources/translations directory;
the kernel root directory/Resources/bundle name/translations
directory;
the Resources/translations/ directory of the bundle.
For example some_domain.fr.yml. Last step is to configure your locale. You can get current locale from request with $request->getLocale()
P.S. try to rm -r app/cache to make sure that the cache is deleted
I could use one of the translations, but not the other and didn't know why. If you have troubles with translations also, read this.
First, standard checklist:
Make sure you enabled and configured translator.
Make sure translation is in proper place and follows proper naming convenction ( domain(messages by default).lang_code.file_format ).
Clear cache using php app/console cache:clear command.
Try to manually call $this->getRequest()->setLocale('en'); in Controller, also you may try to use $this->get('translator')->trans('Some message'); directly in your Controller.
If it still doesn't work, make sure BOM isn't in your translated file. That was my case.
Watch out for BOM in the translated file. The translator who translates the yml file used UTF8 which is OK, but editor he used leaved BOM at the beginning of the file. This is dangerous probably because of PHP's UTF8 BOM bug as it adds few invisible characters to first section of your file.
Btw, debugging your translations may be very helpful, too.
According to the Symfony Translations Documentation page, if you are not using a Service Container for your translation purpose, these are simple steps to go:
Enable and configure Symfony's translation service.
YAML
framework:
translator: { fallbacks: [en] }
PHP
$container->loadFromExtension('framework', array(
'translator' => array('fallbacks' => array('en')),
));
Abstract strings (i.e. "messages") by wrapping them in calls to the Translator ("Basic Translation").
public function indexAction()
{
$translated = $this->get('translator')->trans('Symfony is great');
return new Response($translated);
}
Create translation resources/files for each supported locale that translate each message in the application.
Symfony looks for message files (i.e. translations) in the following default locations:
the app/Resources/translations directory;
the app/Resources/<bundle name>/translations directory;
the Resources/translations/ directory inside of any bundle.
Translation File Name
The filename of the translation files is also important: each message file must be named according to the following path: domain.locale.loader (e.g. filename: navigation.en.xlf):
domain: An optional way to organize messages into groups (e.g. admin, navigation or the default messages) - see Using Message Domains;
locale: The locale that the translations are for (e.g. en_GB, en, etc);
loader: How Symfony should load and parse the file (e.g. xlf, php, yml, etc).
The loader can be the name of any registered loader. By default, Symfony provides many loaders, including:
xlf: XLIFF file;
php: PHP file;
yml: YAML file.
The choice of which loader to use is entirely up to you and is a matter of taste. The recommended option is to use xlf for translations.
Determine, set and manage the user's locale for the request and optionally on the user's entire session.
Clear the cache:
php bin/console c:c
The Translation Process
To actually translate the message, Symfony uses a simple process:
The locale of the current user, which is stored on the request is determined;
A catalog (e.g. big collection) of translated messages is loaded from translation resources defined for the locale (e.g. fr_FR). Messages from the fallback locale are also loaded and added to the catalog if they don't already exist. The end result is a large "dictionary" of translations.
If the message is located in the catalog, the translation is returned. If not, the translator returns the original message.
This helped me to get it worked, since clearing the cache also didn't help.
Symfony 4.6.2:
Try this command to update translation files:
php bin/console translation:update --dump-messages --force de
(Source: https://symfony.com/doc/current/translation.html#configuration)
I can already answer your 2 questions:
1: you can look at
https://github.com/symfony/symfony/blob/master/src/Symfony/Bridge/Twig/Extension/TranslationExtension.php#L97
https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php
https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Translation/Translator.php#L174
2: If you're talking about gedmo doctrine extensions, or Knplabs DoctrineBehaviors, no, there is no way it conflicts with symfonys's translator. These are 2 independant pieces.
Just faced the same issue and fixed it by $this->get('translator')->setLocale('fr'); in the controller action. I fixed it by adding {_locale} in the route path.

How to hide physical path for images and files in symfony2

I've got to read and serve a lot of resources (images and files) and I want to hide real path where resources are stored. What is the best way to do it with symfony 2.x?
If you want to abstract from the filesystem you could use KnpGaufretteBundle. Gaufrette is a PHP library that abstracts the filesystem. That is, you can access resources no matter where they are stored (e.g., the local filesystem, a FTP server, Amazon S3, Dropbox, etc).
However, Gaufrette does not abstract the path (you set up a kind of base directory for the filesystem) and you would use a path relative to this base directory. Consider the following code that abstracts the local filesystem:
<?php
use Gaufrette\Filesystem;
use Gaufrette\Adapter\Local as LocalAdapter;
$adapter = new LocalAdapter('/var/media');
$filesystem = new Filesystem($adapter):
$content = $filesystem->read('myFile.txt');
$content = 'Hello I am the new content';
$filesystem->write('myFile.txt', $content);
In this example you would read and write the file /var/media/myFile.txt.
If you want to further abstract the filesystem, you could create a service that has a map of files and its aliases. For example, you could read a list of these file/alias pairs from a YAML configuration file. You can then get the real filename by using some kind of getter with the alias as parameter.

Resources