So I'm pretty new to Symfony2 and I'm trying to use the camelize filter in a twig template. However when I request the page I get an error saying that the filter doesn't exist:
The filter "camelize" does not exist in ::base.html.twig
Here's the line from my template file:
{{ 'hello world' | camelize }}
The filter is listed on Twig's quick reference page.
I'm confused, doesn't Symfony2 support all of twig's filters? There seem to be quite a few missing, why? And if it doesn't support them, then is there any way to add the missing ones in?
Thanks in advance!
edit Ok, so it turns out I'm retarded and I need to remember to check that I've actually got the right git project. No wonder I was confused. Thanks replies!
Symfony 2 has title filter for camel case use
{{ entity.yourstring | title }}
to camel case your string
Your link points to a fork on GitHub, meaning a modified copy of the original project. The original project is https://github.com/fabpot/Twig.
There is no camelize filter in Twig. Built-in filters are here. You can write your own camilize filter (it's easy, actually...) following this tutorial: How to write a custom Twig Extension.
EDIT: just for fun, you can write something like:
class MyTwigExtension extends Twig_Extension
{
public function getFilters()
{
return array(
'camelize' => new Twig_Filter_Method($this, 'camelizeFilter'),
);
}
public function camelizeFilter($value)
{
if(!is_string($value)) {
return $value;
}
$chunks = explode(' ', $value);
$ucfirsted = array_map(function($s) { return ucfirst($s); }, $chunks);
return implode('', $ucfirsted);
}
public function getName()
{
return 'my_twig_extension';
}
}
Note that this is a quick and dirty filter! Take a look at the built-in filters to learn best practice!
The filter you're looking for is named "title": http://twig.sensiolabs.org/doc/filters/title.html
Here is the best solution by default in Craft CMS 3
Craft 3 now has a |camel filter for twig
https://docs.craftcms.com/v3/dev/filters.html#camel
{{ 'foo bar'|camel }}
{# Output: fooBar #}
Related
I am working on Symfony application and using Twig for layout.
I facing wrong output issue i google it but can't find the solution.
I have date & time 201801031400 I used this
{{ val.start_date|date("m/d/Y") }}
but get the wrong output 10/27/8364
When i used this {{ "now"|date("m/d/Y") }} it give me correct output
Thanks in Advance!
You need to a function to Twig to achieve this, you can see how to register an extension here
TwigExtension
namespace My/Project/Twig/Extensions
class ProjectTwigExtension extends Twig_Extension {
public function getFunctions() {
return array(
new Twig_SimpleFunction('convert_api_date', function($date) {
return new DateTime($date);
}),
);
}
public function getName() {
return 'ProjectTwigExtension'; //this is mandatory
}
}
twig
{{ convert_api_date('201801031400') | date('d/m/Y') }}
{{ convert_api_date('201801031400') | date('H:i') }}
Above answer will perfectly alright i just my solution code too.
First Twig date filter not support the 201801031400. so for this you have to make your own extension.
How to create twig extension create twig extention
<?php
// src/AppBundle/Twig/AppExtension.php
namespace AppBundle\Twig;
class DateParserFilter extends \Twig_Extension
{
public function getFilters ()
{
return array(
new \Twig_SimpleFilter('parse_date', array($this, 'parseDate'))
);
}
public function parseDate ($string, $formats)
{
if (is_string($formats))
{
$formats = array($formats);
}
foreach ($formats as $format)
{
$dateTime = \DateTime::createFromFormat($format, $string);
if ($dateTime !== false)
{
return $dateTime;
}
}
return $string;
}
public function getName ()
{
return "parse_date";
}
}
after this use your own extension filter first then use twig builtin date filter example show below :)
{{ val.start_date | parse_date(["YmdHi", "d/m/Y H:i"]) | date("M d, Y") }}
Its depend what you have in my case i have [2018][01][03][14][00] = [Y][m][d][H][i]
hope it will help you :)
source of this extension - link
You have to divide your unix timestamp value by 1000.
I'm still not sure with what it's related, but this operation is used by authoritative online converters, that most likely faced the same problem.
I came to this conclusion thanks to this answer Converting a UNIX Timestamp to Formatted Date String.
Below is the proof that your unix timestamp is correct:
1) from www.freeformatter.com
2) from www.epochconverter.com
The data is slightly different due to the time zone. It must be taken into account.
Write in the comments, why should I divide by 1000. I myself will be interested.
I'm new with Sonata Block Bundle.
I would like to put into my block a map. It uses some JS library. Function of the context, I need to pass different height, width etc... for example.
But I don't know if it fits with my needs.
At first, I wanted to use Sonata Block because my Maps has dependencies with some Services. So this is cool, I can centralise them.
But can I pass some arguments functions the parent who calls my block ?
Thanks for your answer.
Redfog
Okay, if I understood your question, what you want to do, is pass some custom arguments from your template (where you call your block to be precise) to the php class that is executing the block. Let's get started:
Lets add option to pass height attribute:
{% sample render of your block %}
{{ sonata_block_render({'type':'your.block.id'}, {'height': 50}) }}
Now, in your block service (php/class). You have to add this attribute as a default option in your method: setDefaultSettings, like this:
public function setDefaultSettings(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
// your options goes here, and we add our new option right after them
'height' => null // or whatever suits your needs
));
}
Finally, all you have to is access your option from your execute method like this:
public function execute(BlockContextInterface $blockContext, Response $response = null) {
$settings = $blockContext->getSettings();
// now your value can be access from $settings['height'];
}
Let me know if that's what you're looking for.
Am not very familiar with twig, am trying to get an image extention, but am not sure how to do this in twig ,in php it's very easy using string functions such as substr and indexof or with the following: ext=pathinfo('/testdir/dir2/image.gif', PATHINFO_EXTENSION), i don't want to code it in controller and pass it to twig as parameter,instead i want to extract it directly in the twig layout,so how am going to do this?
You can get file extension by this way
{{ "filename.txt"|split('.')|last }}
One approach would be to use Twig's slice filter.
For example, if the path to your image file is imgSrc, then imgSrc|slice(-4) will give you the last 4 characters of the filename (eg. .gif, .jpg, jpeg).
You can create Twig extension, that will contain
namespace YourApp\AcmeBundle\Twig;
class MyTwigExtension extends \Twig_Extension
{
public function getFilters(){
return array(
new \Twig_SimpleFilter('ext', array($this, 'ext')),
);
}
public function ext($filepath){
$ext = pathinfo($filepath, PATHINFO_EXTENSION);
return $ext;
}
}
In twig, use the split filter. see http://twig.sensiolabs.org/doc/filters/split.html
you can also simply get the extension in the controller and pass it to twig.
I'm trying to get and manipulate the actual object related to a ImageAdmin class in SonataAdmin (using Symfony 2.3). This works fine when the ImageAdmin class is the only one being used. But when ImageAdmin is embedded in another Admin it goes horribly wrong.
Here's what works when you don't have embedded Admins:
class ImageAdmin extends Admin {
protected $baseRoutePattern = 'image';
protected function configureFormFields(FormMapper $formMapper) {
$subject = $this->getSubject();
}
}
But when you embed ImageAdmin in ParentAdmin using this:
class PageAdmin extends Admin {
protected function configureFormFields(FormMapper $formMapper) {
$formMapper->add('image1', 'sonata_type_admin');
}
}
Then when you're editing a Parent item with id 10 and call getSubject() in ImageAdmin you get the Image with id 10!
In other words getSubject() extracts the id from the URL then calls $this->getModelManager()->find($this->getClass(), $id);, which cross-references the Parent id and the Image id. Oops!
So... what I want to do is be able to get hold of the actual object that is being rendered/edited in the current ImageAdmin instance, whether it's being edited directly or via an embedded form, and then be able to do things with it.
Maybe getSubject() is the wrong tree to be barking up, but I note that $this->getCurrentChild() returns false when called from ImageAdmin::configureFormFields(), even when that ImageAdmin is embedded using the sonata_type_admin field type. I'm quite confused...
Anyway, I hope it is possible to get hold of the object in some obvious way that I've overlooked and somebody here can help enlighten me!
Thanks to Tautrimas for some ideas, but I managed to figure out an answer to this:
In ImageAdmin set this:
protected function configureFormFields(FormMapper $formMapper)
{
if($this->hasParentFieldDescription()) { // this Admin is embedded
$getter = 'get' . $this->getParentFieldDescription()->getFieldName();
$parent = $this->getParentFieldDescription()->getAdmin()->getSubject();
if ($parent) {
$image = $parent->$getter();
} else {
$image = null;
}
} else { // this Admin is not embedded
$image = $this->getSubject();
}
// You can then do things with the $image, like show a thumbnail in the help:
$fileFieldOptions = array('required' => false);
if ($image && ($webPath = $image->getWebPath())) {
$fileFieldOptions['help'] = '<img src="'.$webPath.'" class="admin-preview" />';
}
$formMapper
->add('file', 'file', $fileFieldOptions)
;
}
I'll post this in the upcoming SonataAdmin cookbook soon!
https://github.com/sonata-project/SonataAdminBundle/issues/1546
caponica's solution is working only on oneToOne relations, am I right? In my oneToMany case , this: $parent->$getter() returns a collection, and I don't know how to identify the current subject.
I've found this bug report:
https://github.com/sonata-project/SonataAdminBundle/issues/1568, which contains a fix for this, but it is still open, so I hope they merge it soon:(
Edit
With some research there is a temporary fix for this: Fixed getting wrong subject in sonata_type_collection
In short:
create a class and copypaste the content of this file: AdminType
then add this to your services.yml, and change the class namespace to you new class namespace:
services:
sonata.admin.form.type.admin:
class: ACME\AdminBundle\Form\Type\AdminType
tags:
- { name: form.type, alias: sonata_type_admin }
It still has a bug though:
also fix doesn't work when enabled cascade_validation in the parent docment and embedded form has errors
Can you try $this->getForm()->getViewData(); within your ImageAdmin? This should get you the correct child entity.
I tried all these solutions, but none proved to work.
So, I worked to find a solution. My solution is based on caponica's solution, but work on oneToMany case. Tha solution I found is a workaround, but works good.
It's working using the session.
public function getCurrentObjectFromCollection($adminChild)
{
$getter = 'get' . $adminChild->getParentFieldDescription()
->getFieldName();
$parent = $adminChild->getParentFieldDescription()
->getAdmin()
->getSubject();
$collection = $parent->$getter();
$session = $adminChild->getRequest()->getSession();
$number = 0;
if ($session->get('adminCollection')) {
$number = $session->get('adminCollection');
$session->remove('adminCollection');
}
else {
$session->set('adminCollection', 1 - $number);
}
return $collection[$number];
}
And you get the correct object in the admin by:
$object = $this->getCurrentObjectFromCollection($this)
So, when the parent needs to show the list of child admins, each child admin will run this function and will update the session parameter. When all the elements have been taken, the session parameter is deleted.
This code is made for lists with only 2 elements, but can be updated for any number of elements.
Hope this helps somebody :)
I had same problem and i am able to do this through "Custom Form Type Extension" for which documentation is given on the link "http://symfony.com/doc/current/cookbook/form/create_form_type_extension.html" .
It is the perfect solution ..
I looked around for the code to get the current path in a Twig template (and not the full URL), i.e.
I don't want http://www.sitename.com/page, I only need /page.
{{ path(app.request.attributes.get('_route'),
app.request.attributes.get('_route_params')) }}
If you want to read it into a view variable:
{% set currentPath = path(app.request.attributes.get('_route'),
app.request.attributes.get('_route_params')) %}
The app global view variable contains all sorts of useful shortcuts, such as app.session and app.security.token.user, that reference the services you might use in a controller.
Get current url: {{ app.request.uri }} in Symfony 2.3, 3, 4, 5
Get path only: {{ app.request.pathinfo }} (without parameters)
Get request uri: {{ app.request.requesturi }} (with parameters)
In symfony 2.1 you can use this:
{{ path(app.request.attributes.get('_route'),
app.request.attributes.get('_route_params')) }}
In symfony 2.0, one solution is to write a twig extension for this
public function getFunctions()
{
return array(
'my_router_params' => new \Twig_Function_Method($this, 'routerParams'),
);
}
/**
* Emulating the symfony 2.1.x $request->attributes->get('_route_params') feature.
* Code based on PagerfantaBundle's twig extension.
*/
public function routerParams()
{
$router = $this->container->get('router');
$request = $this->container->get('request');
$routeName = $request->attributes->get('_route');
$routeParams = $request->query->all();
foreach ($router->getRouteCollection()->get($routeName)->compile()->getVariables() as $variable) {
$routeParams[$variable] = $request->attributes->get($variable);
}
return $routeParams;
}
And use like this
{{ path(app.request.attributes.get('_route'), my_router_params()|merge({'additional': 'value'}) }}
You won't need all this unless you want to add additional parameters to your links, like in a pager, or you want to change one of the parameters.
You can get the current URL in Twig like this:
{{ app.request.schemeAndHttpHost ~ app.request.requestUri }}
It should be noted that if you have additional query parameters in your URL, which are not part of the configured route, the accepted answer will not include them in the current URL (path).
Why would you want extra parameters?
For example, if you have a list page with records that can be filtered by keyword and the page has pagination, most likely the query variables for "keyword" and "page" will not be in your route. But in your forward and back buttons for paging, you need the full current URL (that contains the keywords so the next page is still filtered). And you need to modify the page variable.
How to Merge In Extra Query Parameters
So you can get the current route, and merge in the extra variables (after modifying one or more of those extra variables). Note that you are merging in your own variables to the app.request.query.all, and then merging that array into the app.request.attributes.get('_route_params'). The path() method requires that you provide all the required parameters of the route, which is why you need to include the _route_params.
{{ path(app.request.attributes.get('_route'), app.request.attributes.get('_route_params')|merge(app.request.query.all|merge({'page': 2 }))) }}
That's really ugly, but if you are developing pagination, you will need to modify the page variable on each separate link, so you have to include the whole thing each time. Perhaps others have a better solution.
Using Symfony 5 you can use this:
{{ app.request.uri }}
If you are using Silex 2 you can not access the Request object anymore.
You can access the current request attributes this way.
app.request_stack.currentrequest.attributes.get('_route')
And to generate the full current URL :
path(app.request_stack.currentrequest.attributes.get('_route'), app.request_stack.currentrequest.attributes.get('_route_params'))