Silex: Redirect with Flash Data - php

I need to redirect one page to another with a message in Silex. Hopefully there's a Laravelesque way of doing it, but I highly doubt it:
$app->redirect('/here', 301)->with('message', 'text');
I'd then want to display the message in my template:
{{ message }}
If not, is there another way?
Update
I see there's a getFlashBag method in Symfony - is that what I'm supposed to use? Specifically, I am using the Bolt Content Management system.

Yes, FlashBag is the right way.
Set a flash message in your controller (you can add multiple messages):
$app['session']->getFlashBag()->add('message', 'text');
$app->redirect('/here', 301)
And print it in the template:
{% for message in app.session.getFlashBag.get('message') %}
{{ message }}
{% endfor %}

I created this simple FlashBagTrait that may be of use:
<?php
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
trait FlashBagTrait
{
/**
* #return FlashBagInterface
*/
public function getFlashBag() {
return $this['session']->getFlashBag();
}
}
Just add it to your Application class and it will make things ever-so-slightly easier!
$app->getFlashBag()->add('message',array('type'=>"danger",'content'=>"You shouldn't be here"));
{% if app.flashbag.peek('message') %}
<div class="row">
{% for flash in app.flashbag.get('message') %}
<div class="bs-callout bs-callout-{{ flash.type }}">
<p>{{ flash.content }}</p>
</div>
{% endfor %}
</div>
{% endif %}
Its main advantage is that type-hinting will work in PhpStorm.
You can also add it as a service provider,
$app['flashbag'] = $app->share(function (Application $app) {
return $app['session']->getFlashBag();
});
Which makes it more convenient to use from PHP (but you lose the type-hinting):
$app['flashbag']->add('message',array('type'=>"danger",'content'=>"You shouldn't be here"));

Related

Custom dynamic Twig template that extends Twig_Template

TL;DR: I am currently struggling with the idea how to elegantly generate CRUDs/GRID using Twig.
Long story:
I have a Phalcon app with AngularJs, templating system is Twig.
PHP is suppose to prepare a template for CRUD that contains:
List od entities, table that contains proper headers, columns, row items, action buttons
Simple and advanced search
Mass actions block
Main buttons - Add/Import/Export etc.
AngularJs is responsible for:
Paginating results in 2 modes: Ajax Loaded entities, All entities at once
Changing number of entities per page
Displaying various forms in modals - Add/Edit/Import
Filtering entities - simple and advanced search
Everything is working right now but I am not particularly fond of how it works.
For example a simple entity with few fields needs a following template:
{% extends 'index.twig' %}
{% block containerAttr %}ng-controller="InventoryController as ctrl"{% endblock %}
{% set ctrlName = 'ctrl' %}
{% set columnWidth = 'col-xs-12' %}
{% set tableClass = 'table table-bordered table-striped table-hover' %}
{% block header %}
{% include '#crud/crud/header.twig' %}
{% endblock %}
{% block content %}
{% embed '#crud/crud/main-box.twig' %}
{% block tableHeader %}
{% autoescape false %}
{{ crud.tableHeader('Id', 'id') }}
{{ crud.tableHeader('Nazwa', 'name') }}
<th class="col-xs-1">Actions</th>
{% endautoescape %}
{% endblock %}
{% block tableRow %}
<td ng-bind="e.id"></td>
<td ng-bind="e.name"></td>
{% endblock %}
{% endembed %}
{% embed '#crud/crud/form.twig' %}
{% block modalBody %}
{% autoescape false %}
<div class="row">
{{ crud.input('ctrl.entity.name', 'Name', 12) }}
</div>
{% endautoescape %}
{% endblock %}
{% endembed %}
{% embed '#crud/crud/upload.twig' %}{% endembed %}
{% embed '#crud/crud/advancedSearch.twig' %}{% endembed %}
<script>
window.xdata = {{ xdata | json_encode | raw }};
</script>
{% endblock %}
crud in this template is responsible for generating form fields compatible with AngularJs.
Idea is: To create new CRUDs/Grids with the least amount of work required. While still giving a room for some flexibility.
Right now to make a CRUD/Grid inside my application there is a really little work required:
PHP Controller needs to contain only one line:
class SubCategoryController extends CrudBase
{
protected $entityClass = InventoryCategory::class;
}
Thanks to extending it is really easy to customize every part of it.
Model needs to have just a few fields:
class InventoryCategory extends ModelBase
{
/** #var integer */
public $id;
/** #var string */
public $name;
public function initialize()
{
$this->setSource('inventory_subcategory');
$this::setup(['castOnHydrate' => true]);
}
}
Even the AngularJs controller contains only URLs and one line:
class InventoryCategoryController extends CrudBase {
constructor($injector, $scope) {
super($injector, $scope);
this.urlSave = '/inventory/category/save';
this.urlImport = '/inventory/category/import';
this.urlExport = '/inventory/category/export';
this.urlDelete = '/inventory/category/delete';
this.init({
advancedSearch: false
});
}
}
angular.module('App').controller('InventoryCategoryController', InventoryCategoryController);
Yes I use ES6, application is not compatible with older browsers anyways and it is admin panel so I do not care about older browsers.
But now only templates remains a tedious work to copy it over and change it. Not to mention they do look pretty ugly.
So my idea was to use Annotation Reader (Phalcon has one) to read fields from Model, then transform it into a base configuration, check if there is custom configuration in json and merge it. Then based on configuration, generate this whole template on the fly.
So the grand question is:
I was wondering if I can create some class that extends Twig_Template to generate this template on the fly?
I have seen Twig cache and it should be pretty easy but then how can i use it? How can i render it? Will extend still work?

OctoberCMS Backend User Permissions with Twig

I'm using OctoberCMS which uses Twig.
The way I retrieve user permissions is by getting the information in php then pass a twig variable.
Is there a way to do this using just Twig?
Permissions Docs
PHP
if (BackendAuth::check()) {
# Get User Info
$backend_user = BackendAuth::getUser();
# Superuser
$this['is_superuser'] = $backend_user->is_superuser;
# Permissions
$this['permissions_allow_edit'] = $backend_user->hasPermission(
[
'mycomponent.gallery.allow_edit'
]);
}
Twig
{% if is_superuser or permissions_allow_edit %}
//edit button
{% endif %}
Twig (Standalone)
//another way to backendauth check in twig?
if (BackendAuth::check()) {
$this['backend_user'] = BackendAuth::getUser();
}
//////
{% if backend_user.is_superuser or backend_user.permissions.mycomponent.gallery.allow_edit %}
//edit button
{% endif %}
{{ backend_user }} gives the user information array
{"id":2,"first_name":"Matt","last_name":"","login":"matt","email":"user#example.com","permissions":{"mycomponent.gallery.allow_edit":1},"is_activated":false,"activated_at":null,"last_login":"2017-03-11 09:59:48","created_at":"2017-02-11 10:32:14","updated_at":"2017-03-11 10:03:45","is_superuser":0}
{{ backend_user.permissions }} throws an "Array to string conversion" error.
{{ backend_user.permissions.mycomponent.gallery.allow_edit }} shows nothing.
How do I get the values inside the permissions array?
I have not tested this but you should be able to use the hasPermission method to check if backend user has a specific permission:
{% if backend_user.is_superuser or backend_user.hasPermission('mycomponent.gallery.allow_edit') %}
//edit button
{% endif %}

How to use HTML tags in Symfony flash message

working with Symfony 2.7 I would like to include HTML in a flash message:
class MyController extends Controller {
public function someAction(Request $request) {
...
$this->addFlash('success', $tranlator->trans('some.success.msg', array(), 'app'));
...
}
}
// app.yml
some:
success:
msg: Text with some <strong>HTML</strong>
This creates a Flash Message
Text with some <strong>HTML</strong>
instead of
Text with some HTML
Within my own Twig template I would use the raw filter, to display the HTML code directly instead of the escaped version. But how can I achive the same within addFlash(...)?
Not sure i really understand your question. If this is not what you're asking just say it and I will remove this answer.
As said in documentation you use
app.session.flashbag.get('success')
to retrieve your flash message.
Example :
{% for flash_message in app.session.flashbag.get('success') %}
{{ flash_message|raw }}
{% endfor %}
I think this cannot be done directly. But you can tweak where you are showing the message using some html and css.
Like:
In setting the flash message:
$this->get('session')->getFlashBag()->add('notice', array('type' => 'success', 'title' => 'Done!', 'message' => 'OK! It is done!'));
And in twig file:
{% for msg in app.session.flashbag.get('notice') %}
<div class="alert alert-{{ msg.type }}">
<strong>{{ msg.title }}</strong><br/>{{ msg.message }}
</div>
{% endfor %}

Display split results in Symfony2 twig

I have a function in my Symfony controller which returns the following:
test+testString1+test2
TestController.php
public function getResultAction($fileName) {
$string1="test";
$string2="testString1";
$string3="test2";
$response = $string1."+".$string2."+".$string3;
return new Response($response);
}
In my twig I've rendered the function in my controller:
test.html.twig
{% set test %}
{{ render(controller('TestBundle:Test:getResult')) }}|split('+', 4)
{% endset %}
{{ test[0] }}
I'm using twig split filter so that I can display test, testString1 and test2 individually. But then whenever I attempt to display test[0], I receive the following error:
Impossible to access a key "0" on an object of class "Twig_Markup" that does not implement ArrayAccess interface in TestBundle:Test:test.html.twig
What's wrong with what I'm doing? I hope you could help me with this. Thanks
You miss the split filter inside the double brace as follow:
{% set test %}
{{ render(controller('TestBundle:Test:getResult')) |split('+', 4) }}
{% endset %}
Hovenever seems same problem with the set tag. From the doc:
The set tag can also be used to 'capture' chunks of text
Try with:
{%
set test=render(controller('TestBundle:Test:getResult'))|split('+', 4)
%}
Hope this help

Avoid repeating the same query in controllers for parent template

I am trying to make a messaging system and I'm facing a small problem. I have a bigger template that displays my menu and my content. The menu includes the number of new messages, and the content can be any page(compose a new message, inbox, sent).
The problem is that I have to render each of the small templates by passing the number of new received messages to each of them, calling the doctrine each time and repeating code. Is there any way to send the number only to the parent template?
Here are my templates:
This is the parent containing the newmsg variable that gives me problems.
{% extends "::base.html.twig" %}
{% block body %}
inbox : {{ newmsg }}
sent
compose
{% endblock body %}
Here is an example of child template:
{% block body %}
{{ parent() }}
{% if messageList %}
{% for message in messageList %}
<li>title = {{ message.title|e }}</li>
<li>cont= {{ message.content|e }}</li>
<li>data= {{ message.date|date('d-m-Y H:m:s') }}</li>
<li>sender= {{ message.sender|e }}</li>
<hr>
{% endfor %}
{% else %}
<div>no messages</div>
{% endif %}
{% endblock body %}
The problem is that each child template is asking me for the newmsg variable
$messages = $this->getDoctrine()->getRepository('MedAppCrudBundle:Message');
$newMessagesNo = count($messages->findBy(array('seen' => '0', 'receiver' => $this->getUser())));
return $this->render(
'MedAppCrudBundle:UserBackend\Message:new.html.twig',
array(
'form' => $form->createView(),
'newmsg' => $newMessagesNo,
)
);
And I have to write this in every single controller. Any way I can shorten this problem?
You could implement a service that gives back the newmsg value and call it on your parent template. Then it would not be necessary to pass the variable.
You can add a service in your bundle's services.yml with something like:
services:
newmessages:
class: Full\Class\Name\NewMessagesService
arguments: ["#doctrine.orm.entity_manager"]
Then, implement the Full\Class\Name\NewMessagesService class. Keep in mind that this class will need a constructor that receives an EntityManager argument. Something like:
<?php
namespace Full\Class\Name;
class NewMessagesService{
private $entityManager;
public function __construct($entityManager){
$this->entityManager = $entityManager;
}
public function methodToCalculate(){
//Perform calculation and return result
}
}
Then, in your parent template, replace {{newmsg} with:
{{ newmessages.methodToCalculate() }}

Categories