allow new methods in sandbox policy in twig (drupal 8) - symfony

I am getting this error when using the "field collection" module :
Twig_Sandbox_SecurityError: Calling "uri" method on a "Drupal\field_collection\Entity\FieldCollectionItem" object is not allowed in "themes/communitylife/templates/content/node.html.twig" at line 83. in Drupal\Core\Template\TwigSandboxPolicy->checkMethodAllowed() (line 99 of core/lib/Drupal/Core/Template/TwigSandboxPolicy.php).
the code that causes the problem is this one :
<div class=" title-col col-md-7">
<a href="{{file_url(node.field_pressemappe_bildmaterial[key].getFieldCollectionItem().field_presse_bild_file.entity.uri.value)}}" target="_blank"> <strong> {{node.field_pressemappe_bildmaterial[key].getFieldCollectionItem().field_presse_bild_description.value}}
<span class="file-type"> ({{node.field_pressemappe_bildmaterial[key].getFieldCollectionItem().field_presse_bild_file.entity.uri.value | slice(-3) }} </span>, <span class="file-size"> {{node.field_pressemappe_bildmaterial[key].getFieldCollectionItem().field_presse_bild_file.entity.size }}) </span>
</strong></a>
</div>
what is the best way to fix this ? is it by adding (uri) to the allowed methods in the sandbox policy ? if yes then how I can do that ?
I read in the twig documentation that I can do something like this :
$policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods, $properties, $functions);
but I didn't understand how or where to put this code.
Thanks in advance

Drupal's twig sandbox policy (defined in core/lib/Drupal/Core/Template/TwigSandboxPolicy.php) reads from the global $settings array so you can define your own in your settings.php i.e.
// Override default twig method whitelist.
$settings['twig_sandbox_whitelisted_methods'] = [
// Defaults:
'id',
'label',
'bundle',
'get',
'__toString',
'toString',
// Additions:
'url',
];

Related

Laravel Livewire errors are not cleared

I am experimenting with Laravel Livewire and I came across a situation where the previous errors are displayed even though the form is successfully submitted.
Before hit Save
After hitting Save
Html segment of name in blade file customer-new.blade.php.
<div class="form-group">
<div class="border rounded-0 px-1">
<label class="mb-0" for="name">Name</label>
<input wire:model="name" type="text" class="form-control form-control-sm " id="customer-name" aria-describedby="customer-nameHelp">
</div>
#error('name') <span class="err-message">{{ $message }}</span> #enderror
</div>
and the Save button code:
<button
wire:click="store"
wire:loading.attr="disabled"
wire:target="store"
type="submit"
class="btn btn-sm btn-light">Save
</button>
store method of CustomerNew.php:
public function store()
{
$this->validate([
'name' => 'required|max:80',
'street' => 'required|max:100',
'city' => 'required|max:40',
'dueAmount' => 'numeric|min:0'
]);
Customer::create([
'name' => $this->name,
'street' => $this->street,
'city' => $this->city,
'due_amount' => $this->dueAmount,
]);
session()->flash('message', 'Customer was saved');
$this->clear();
}
and the clear() method is like:
public function clear() {
$this - > name = '';
$this - > street = '';
$this - > city = '';
$this - > dueAmount = 0;
}
According to docs https://laravel-livewire.com/docs/input-validation,
You need to reset the validations whenever you want
Direct Error Message Manipulation The validate() and validateOnly()
method should handle most cases, but sometimes you may want direct
control over Livewire's internal ErrorBag.
Livewire provides a handful of methods for you to directly manipulate
the ErrorBag.
From anywhere inside a Livewire component class, you can call the
following methods:
$this->addError('email', 'The email field is invalid.');
// Quickly add a validation message to the error bag.
$this->resetErrorBag();
$this->resetValidation();
// These two methods do the same thing. The clear the error bag.
// If you only want to clear errors for one key, you can use:
$this->resetValidation('email');
$this->resetErrorBag('email');
$errors = $this->getErrorBag();
// This will give you full access to the error bag,
// allowing you to do things like this:
$errors->add('some-key', 'Some message');
HINT
I am using the reset methods on hydrate function like following
...
public function hydrate()
{
$this->resetErrorBag();
$this->resetValidation();
}
...
You should reset the public properties by using the livewire's reset method. Delete your $this->clear() method definition and replace it with the following:
$this->reset('name', 'street', 'city', 'dueAmount');
add id's to the error message div
#error('name') <span class="err-message" id="name-error">{{ $message }}</span> #enderror
#error('street') <span class="err-message" id="street-error">{{ $message }}</span> #enderror
#error('city') <span class="err-message" id="city-error">{{ $message }}</span> #enderror
#error('due_amount') <span class="err-message" id="due_amount-error">{{ $message }}</span> #enderror
$this->resetErrorBag();
Just add this in your clear() method. This will reset the error bag after each save.
It is better to send $name to the resetValidation and resetErrorBug. In this way you reset validation for the updating fields only. Here is my example:
public function updated($name, $value)
{
$this->resetValidation($name);
$this->resetErrorBag($name);
}

Symfony: No route found for "GET/content/articles/changeArt......"

I have a button that contains a link to another page, and pass some variables from the twig template to the controller action of that page :
<button class="btn btn-warning btn-xs" title="modifier l'article">
<i class="fa fa-pencil-square-o"></i>
</button>
The variables pass to the action successfully but I get an error :
No route found for "GET /content/articles/changeArt/3/test3/%3Ci%3E%3Cu%20style=%22background-color:%20rgb%28255,%20255,%200%29;%22%3Esdfghyujhgrertjr%22%5Ekrjthbkrkjgjgrhgiebgfjkebvkebvkezbkzbkdzbdkzbckdszb%20sdnckdzb%20nc,de%3C/u%3E%3C/i%3E/11/04/2017" (from "http://127.0.0.1/PFE_CNAM/web/content/articles")
(the variable 'content' its of type BLOB, and I start geting this error when i changed its type, because before when it was of type text,this action was working pretty good).
Here is the action code :
/**
* #Route("/content/articles/changeArt/{id}/{title}/{content}/{date}",defaults={"id": 0,"title": 0,"content": 0,"date": 0},name="changeArticle")
* #Template()
*/
public function changeArticleAction($id,$title,$content,$date)
{
$session = new Session();
$session->start();
$search = $session->get('user');
$gestAcces = $session->get('acces');
$gestEtat = $session->get('etatUser');
$gestCont = $session->get('contenu');
$repMsg = $session->get('repMsg');
$gestRec = $session->get('Reclam');
$gestMess = $session->get('gestMess');
$gestMp = $session->get('gestMp');
return $this->render('CNAMCMSBundle:Default:changeArticle.html.twig', array('search' => $search,
'contenu' => $gestCont,
'gestAcces' => $gestAcces,
'gestEtat' => $gestEtat,
'repMsg' => $repMsg,
'gestRec' => $gestRec,
'gestMess' => $gestMess,
'gestMp' => $gestMp,
'date'=>$date,
'id'=>$id,
'title'=>$title,
'content'=>$content,
));
}
Look at your route definition /content/articles/changeArt/{id}/{title}/{content}/{date} you can see this route expected exactly 4 params. Then, look at the generated path /content/articles/changeArt/3/test3/%3Ci%3E%3Cu%20style=%22background-color:%20rgb%28255,%20255,%200%29;%22%3Esdfghyujhgrertjr%22%5Ekrjthbkrkjgjgrhgiebgfjkebvkebvkezbkzbkdzbdkzbckdszb%20sdnckdzb%20nc,de%3C/u%3E%3C/i%3E/11/04/2017, it has alot of params separated by / because your params contains slashes.
When matching the URI with route path, it look like:
id: 3
title: test3
content: %3Ci%3E%3Cu%20style=%22background-color:%20rgb%28255,%20255,%200%29;%22%3Esdfghyujhgrertjr%22%5Ekrjthbkrkjgjgrhgiebgfjkebvkebvkezbkzbkdzbdkzbckdszb%20sdnckdzb%20nc,de%3C
date: u%3E%3C
i%3E // how about these extra params?
11 //
04 //
2017 //
I don't known which Symfony version you're using, it should throw exeption if your params contains /. You can solve your problem by encode your params before generate the url.
{{ path('changeArticle', {
id: id,
title: titre|url_encode,
content: corps|url_encode,
date: pub|date('d/m/Y')|url_encode
}) }}
Is 'date':pub|date('d/m/Y') a Typo?
Try this:
<button class="btn btn-warning btn-xs" title="modifier l'article">
<a
href="{{ path('changeArticle',{
'id' : id,
'title' : titre,
'content' : corps,
'date' : date|date('d/m/Y')
}) }}"
style="color: #ffffee;text-decoration: none;"><i class="fa fa-pencil-square-o"></i>
</a>
</button>

How can I unmap a File input without using the form builder?

I have inherited an application that seems to have existed before the form builder existed. The developer kind of rolled his own with twig macros. Now I want to add a file upload to some existing forms, but I get what seems to be a well known error:
There was 1 error:
myBundle\Tests\Controller\snip\DefaultControllerUnitTest::testCanStoreDocumentAtS3
Exception: Serialization of
'Symfony\Component\HttpFoundation\File\UploadedFile' is not allowed
C:\apath\vendor\symfony\symfony\src\Symfony\Component\HttpKernel\DataCollector\DataCollector.php:27
C:\apath\vendor\symfony\symfony\src\Symfony\Component\HttpKernel\Profiler\Profiler.php:218
The solutions is to unmap the file field:
$builder->add('pic','file');
to this :
$builder->add('pic','file', array('mapped'=>false));
But in this case a builder is not used. Instead it looks like this:
{# file(name, value) #}
{% macro file(name, value) %}
<input type="file" name="{{ name }}" id="{{ name }}" value="{{ value }}" />
{% endmacro %}
Is there anything I can add to this macro, or do in the controller action to keep the Profiler from serializing this?
The answer was in part pilot error, but there is enough going on here that I hope I can help others avoid the same pitfall.
This error was triggered by a unit test where I was simulating a file upload along with other parameters. Initially the code that caused this error was:
$photo = new UploadedFile(
__DIR__ . '/TestReportMethod.xlsx',
'TestReportMethod.xlsx',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
123
);
....
$form['reportFile'] = $photo;
//submit
This caused the error in my original post.
After trying a few things I moved to this form instead.
$crawler = $this->client->request('POST',
$url,
array('id' => 328),
array('agencyInfoId' => 328),
array('reportFile' => $photo)
);
Which causes an InvalidArgumentException I think a little better example in the cookbook could have prevented. The correct form needs to be an array of parameter values, followed by an array of files:
$crawler = $this->client->request('POST',
$url,
array('id' => 328,
'agencyInfoId' => 328),
array('reportFile' => $photo)
);
I hope this helps somebody else!

Make controller only give a value to template, not render it - Symfony2

I have a twig template with the navbar and all other templates (the pages) include this template. I have a value in it which should be equal to all pages. How to set this value?
I tries something like this in a controller:
public function setNotificationsAction() {
$this->setNotifications();
return $this->render('AcmeMyBundle::navbar.html.twig', array(
'debts' => $this->notifications,
));
}
and then this in the template:
<span class="badge badge-important">
{% render(controller('AcmeMyBundle:DebtsLoansController:setNotifications')) %}
{{ debts }}
</span>
The result I want it like this:
<span class="badge badge-important">
3
</span>
but the number should be different and the controller should tell it.
I also tried to create a function which returns the value and to call it in the way like above.
I also tried this syntax
{{ render(controller('AcmeMyBundle:DebtsLoansController:setNotifications')) }}
but it isn't working, too.
I get the following mistake:
The function "controller" does not exist in AcmeMyBundle::navbar.html.twig at line 6
Do you have any idea how to achive this and not to have to edit each controller and each template :S Thanks very much in advance!
Well, I would suggest creating your own Twig extension. Something around the lines of:
<span class="badge">
{{ acme_notifications() }}
</span>
namespace Acme\DemoBundle\Twig\AcmeDemoExtension
class AcmeDemoExtension extends \Twig_Extension
{
public function getFunctions()
{
return array(
'acme_notifications' => new \Twig_Function_Method($this, 'getNotifications');
);
}
public function getNotifications()
{
$notifications = ...;
return $notifications;
}
}
Read more about creating your own Twig extension in the Symfony2 documentation.
You don't need the controller part :
{% render "AcmeBundle:MyController:MyAction" %}
Be aware however, that a render is a completely new request going through the whole Symfony lifecycle and thus can impact performance if you abuse it.
Edit : And as #Wouter J has pointed out : prior to Symfony 2.2 use above notation. After Symfony 2.2 the following has to be used :
{{ render(controller('AcmeArticleBundle:Article:recentArticles', { 'max': 3 })) }}

Symfony2: How use 'ckeditor' in a form?

I installed TRsteelCkeditorBundle, when I'm building in the view a form manually, it works.
<form method="post">
<p>
My Editor:<br>
<textarea name="editor1"><p>Initial value.</p></textarea>
<script>
CKEDITOR.replace( 'editor1' );
</script>
</p>
<p>
<input type="submit">
</p>
</form>
But when I try to use the Symfony2 form I get this error :
An exception has been thrown during the rendering of a template
("Route "route_name" does not exist.") in
lbTestBundle:Default:index.html.twig at line 8
My codes :
In the Twig template
{{ form_widget(form) }}
Ligne 8 is the form_widget
In the controller:
public function indexAction()
{
$formBuilder = $this->createFormBuilder();
$formBuilder
->add('date', 'date')
->add('title', 'text')
->add('content', 'ckeditor')
->add('author', 'text');
$form = $formBuilder->getForm();
$view['form'] = $form -> CreateView();
return $this->render('lbTestBundle:Default:index.html.twig', $view);
}
I followed step by step the indications of the Read_me.txt in he github page, and try to find answers elsewhere but found nothing. If someone can help me to solve that problem, i'm still beginner with SF2. Thanks
What is at lbTestBundle:Default:index.html.twig at line 8?
Obviously you have a route route_name in you template which is not defined in you routing.yml file.
That's all the error message says.
Same problem here. Spend all day today researching.
Finally, fixed it by replacing the TRsteelCkeditor bundle with the IvoryCKEditor bundle.
I found where the error comes from.
the route_name comes from
#config.yml for TrsteelCkeditor
filebrowser_image_browse_url:
route: route_name
route_parameters:
type: image
I suppose I have to put the route where the editor goes when you want to upload images in the editor.
I'll continue to test this budle till I got something fine and I'll give the result
Adding in comment the line
#route: route_name
In the config.yml solve the problem, this line is for uploading images on the server I think, see this link :
http://docs.cksource.com/CKEditor_3.x/Developers_Guide/File_Browser_(Uploader)
But now I am having some issues with language, I want to put it in French, at the moment the skin seems language dependent just like the hover on the buttons.
Also if you want to configure it, you can do it either in the config.yml or the config.js in /web/bundle repository if you already install the assets.

Resources