my script defines a absolute path in PHP and gives it to the twig template with the render()-function. All works well, I can access my variables with {{ varName }} in the view. But if I try to use a absolute path as a variable inside a include-command like {% include varName %} it will say: Unable to find template. This will even happen if the absolute path is correct.
What am I missing here?
Well it's weird but unfortunately I had no possibility to include a file from somewhere else not in the specific symfony structure. So I had to move all contents to the view folder.
I hope someone fixes this, which is anything but flexible.
To add template search paths to Twig_Loader_Filesystem, you can use
$loader->addPath($templateDir);
or
$loader->prependPath($templateDir);
Where $templateDir is a parent directory and $loader is the variable containing your Twig_Loader_Filesystem object. In your example, you would want $templateDir to be the path where the Bundle directory is located.
Then, in your include do something like this:
{% include 'Bundle\Somedir\somefile.html.twig' %}
Twig will then search all paths in looking for Bundle\Somedir\somefile.html.twig and will return the first one it finds.
The Twig documentation on this subject can be found here: http://twig.sensiolabs.org/doc/api.html#twig-loader-filesystem
Note: Choice of using addPath or prependPath depends on which order you'd like Twig to search the directories in. Paths added using prependPath will be searched before any of the previously loaded paths.
Caution: The search order applies to all templates so if the path/filename you use in the include statement is not unique, you could end up overriding another template.
Related
I am working on a proof-of-concept project that needs to be built quickly, so we are taking shortcuts. I have created the basic Symfony/Twig structure. A colleague has created a PHP application that we want to include into an iFrame on the site (eventually we will do this by means of proper templates, etc.).
I created the following index.html.twig (simplified):
{% extends 'base.html.twig' %}
{% block body %}
<iframe src="project/index.php"></iframe>
{% endblock %}
This throws me an error:
Unable to find template "project/index.php"
I understand the error, but am not sure what to do so that the external application simply gets loaded into the iFrame. Basically I want Symfony and Twig to ignore it (for now, so it can be used as prove of concept).
I will make an assumption here, specifically, that your code is included in a template for /app/somethingelse (two slashes or more).
which will lead to, the uri in the following (your code)
<iframe src="project/index.php"></iframe>
to be interpreted as /app/project/index.php - since it's a relative path -, which most likely doesn't exist. What you probably want is an absolute path (which always begins with a slash):
{% block body %}
<iframe src="/project/index.php"></iframe>
{% endblock %}{# ^here #}
I suggest reading up on relative vs. absolute paths. combined with the comment, that you almost always want absolute paths (unless full URLs are necessary of course) - this also includes paths to images, paths to css files, paths to anything and everything really. relative paths can be quite handy, but you always have to be aware that the relative position of locations gets relevant and cannot be changed without impacting other places where those relative positions are assumed to be static.
I'm having issues with a small and trivial application that I created to help me learn Symfony 3. The Application simple allows me to upload an image when I create a new blog post.
I'm using the Symfony 3 documentation to learn about uploading file, and in it, it suggests that I rename the file to a unique name using the md5() hash method to request a strange looking name for the file.
Everything works find until I want to display the image in the index.html.twig file. I was under the impression that I could simply use the asset() method that I was using to import bootstrap and other publicly viewable files, and then simply append the file name to the end of that. But nothing seems to work.
Here are some things that I have tried.
<img src="{{ asset('blog/images/') }}{{ blog.imageUrl }}">
<img src="{{ asset('blog/images/', { 'imageUrl': blog.imageUrl }) }}">
<img src="{{ asset('blog/images/' . blog.imageUrl) }} ">
And there is probably a few more different combinations that I have tried but can remember. Now I have since found the documentation that talks a little about the asset() method, but there is nothing there that seems to state that you can use it and then just append the file name to the end of it, And I haven't found any information that allows me to point directly to the web directories, where the blog/images folder now lives. So any help with this would be awesome. Thank you so much.
Not knowing the content of blog.imageUrl its hard to know what is expected. My guess for the 'correct' answer to your question is that you were very close with option #3, however in twig string concatenation is done using the ~ symbol and not .
So in your case you would use <img src="{{ asset('blog/images/' ~ blog.imageUrl) }}" />
Regards
Make sure that the new name of the file matches the name stored in the database. That and make sure the path you're using is correct.
I saw someone including a template on his application using the twig template system.
He included his template like this:
{{ include( 'Bundlename:Directory:template.html.twig' ) }}
instead of this:
{% include 'Bundlename:Directory:template.html.twig' %}
At first I thought he was using a custom twig extension, but it actually
works on symfony in general, even though its not documented.
http://twig.sensiolabs.org/doc/tags/include.html
So is there a difference between the two?
why is it not documented?
if the syntax is wrong why is it even working?
It is documented http://twig.sensiolabs.org/doc/functions/include.html.
Twig tag include vs function include
Lets say I have two controllers that work with the same entity, and use the same set of templates. Every template is supposed to generate buttons/forms/links with URLs to actions of controller that generated this template. So basically, the only thing that is different in the templates are the URLs generated.
You can imagine the problem like a admin CRUD controller with a newAction and editAction, which use the same template, but form actions must differ. My case is more complicated than that, though.
I considered following:
Setting the routes from the controller, but it feels like a lot of code that is out of place.
Different set of templates. Seems like anti-DRY and a lot of reused code.
Using template inheritance, where base template is the one with all the HTML, and child templates only contain the links, but it feels really hacky.
Is there a clever approach to solve this problem?
EDIT: My problem is not generating CRUD. This is more of a "best-practice" question.
I encountered this problem while implementing something like a eshop cart with tons of javascript logic bound to it. It appears twice: in the website, and in a iframe, used by some other devices (iPads and stuff). Both carts have to look the same, but because of different logic, the links must lead to different URLs.
What I ended up doing for now is having 2 templates
The one with all the markup, cart.html.twig:
{% set edit_cart_item = path('edit_cart_item') %}
{% set remove_cart_item = path('remove_cart_item') %}
...html...
Edit item
...more html...
The one for usage in iframe, public_cart.html.twig:
{% extends 'MyCartBundle::cart.html.twig' %}
{% set edit_cart_item = path('public_edit_cart_item') %}
{% set remove_cart_item = path('public_remove_cart_item') %}
Does the problem have some better solution in all the fancy OOP principles?
There isn't a 'clever' approach really. Why not just use the specified Doctrine command to generate it for you, and then go from there? http://symfony.com/doc/current/bundles/SensioGeneratorBundle/commands/generate_doctrine_crud.html
php app/console generate:doctrine:crud with various options
That will get you a solid base done in an 'appropriate' manner, and then you can perform your customizations.
EDIT:
After reading your updated post, I would have a look at this: http://symfony.com/doc/current/book/forms.html#changing-the-action-and-method-of-a-form
So, if you'd like, you can handle the logic of which form to display by passing in options to the form, and then setting the target via setAction():
$form = $this->createFormBuilder($task)
->setAction($this->generateUrl('target_route'))
;
By design, Symfony gives you a lot of flexibility in how to do things. A good reference of their best practices for forms can be found here: http://symfony.com/doc/current/best_practices/forms.html
I also think what you're doing is just fine. When I have complex cases for forms I like to create a Twig template just for the form itself, and then include that in my other templates. In that template you can pass the target route to it if you'd like, and then you'd just have one form template.
I am having issues using twig templates for email in SF2.
First, I created a template file located at:
MainBundle/Resources/views/Email/InviteNewUsers.twig
Next, I rendered the view as the body of my email: $this->get('mailer')->send($this->renderView('MainBundle:Email:InviteNewUsers.twig', array('code' => $invite->getCode())));
Unfortunately, this triggers an error: Unable to find template "MainBundle:Email:InviteNewUsers.twig"
is there something wrong with my file placement or my render command?
It was suggest that I might need a type in the template name, so I tested with InviteNewUsers.txt.twig and received the same error.
I believe the name of twig template needs to be InviteNewUsers.{_format}.twig. so it must be something like InviteNewUsers.html.twig, InviteNewUsers.xml.twig, or InviteNewUsers.text.twig etc
EDIT:
Also if your namespace includes first directory something like {Company}\BaseBundle\..., then your template path needs to be {Company}MainBundle:Email:InviteNewUsers.text.twig