Symfony2: phpinfo() using a twig template for layout? - symfony

Twig won't process PHP tags. Hence, it is a challenge to create a phpinfo() page based on a layout (say base.html.twig).
Is it possible to dump the HTML content of phpinfo() into some variable and pass it as body content to the layout? Or, is there a better way to proceed?

Just capture the output of phpinfo() with output buffering, and pass it to the template.
ob_start();
phpinfo();
$phpinfo = ob_get_clean();
echo $twig->render('phpinfo.html.twig', array('phpinfo' => $phpinfo));

This is an addition to answer from Federkun.
In controller:
ob_start();
phpinfo();
$phpinfo = ob_get_contents();
ob_end_clean();
return $this->render('phpinfo.html.twig', array(
'phpinfo'=>$phpinfo,
));
Don't forget to put a | raw in twig!
{{ phpinfo | raw }}

class DefaultController extends Controller
{
/**
* #Route("/", name="index")
* #Method("GET")
*/
public function index()
{
ob_start();
phpinfo();
$phpinfo = ob_get_clean();
return new Response(
'<html><body>'.$phpinfo.'</body></html>'
);
}
}

With Symfony, if you just need to check phpinfo()'s output, you can use dump(phpinfo()) inside a controller and you'll get the basic phpinfo()'s output. Also working to call phpinfo() as parameter of the Response object then return it:
class DefaultController extends AbstractController
{
/**
* #Route("/", name="default")
*/
public function index()
{
dump(phpinfo());
// Then return something else, or call directly phpinfo() on return, like bellow
return new Response(phpinfo());
}
}

Related

Substring Count in Twig

I am looking to use substr_count in Twig, does anything exist already? I want to perform something like this;
<?php
$text = 'This is a test';
echo strlen($text); // 14
echo substr_count($text, 'is'); // 2
I can do an extension but it seems this might be something built in already that I have missed.
How about this?
{%set count = text|split('is')|length-1 %}
This doesn't exist in the list of Twig functions or filters.
You'll have to write your own custom function/filter or try a package (note; I've never used this package so can't comment on it, but was on the first page of Google results).
I went for an extension
namespace AppBundle\Twig;
class SubStrCountExtension extends \Twig_Extension
{
public function getFunctions()
{
return array(
new \Twig_SimpleFunction('substr_count', array($this, 'substr_count')),
);
}
public function getName()
{
return 'substr_count_extension';
}
public function substr_count($str, $char)
{
return substr_count($str, $char);
}
}
And in services.yml
app.twig_extension.substr_count_extension:
class: AppBundle\Twig\SubStrCountExtension
tags:
- { name: twig.extension }
I use solution in Symfony 3.2.8 but in the description does not say this block of code should is inside : services
If you does not make show this error:
There is no extension able to load the configuration for .....
This code should is inside services this is correct:
services:
app.twig_extension.substr_count_extension:
class: AppBundle\Twig\SubStrCountExtension
tags:
- { name: twig.extension }
Finally, the correct use in twig is:
tu placa es: {{substr_count(datos.picoyplaca,4)}}
Regards

How to create a form using block module in drupal 8?

I want build a form using a block module in Drupal 8. I am aware of building the forms in Drupal 7 but the same seems to be different in Drupal 8.
Request anyone who has worked on drupal8 custom forms as block to help me.
Your question is very vague, as I don't know how much you already know about modules, forms and blocks in Drupal 8. So here is a small guide what to do, further information on how to do stuff in detail would be overkill for this answer.
1. Create a new module and enable it
Look here: Naming and placing your Drupal 8 module.
Basically you create the module folder and the module info yml file to let Drupal know about the module. Then you enable it using drush or the admin area in Drupal.
2. Create the form
Look here: Introduction to Form API.
under your_module/src/Form you create the form. More details in the link above.
3. Create the block and render the form
Look here: Create a custom block.
under your_module/src/Plugin/Block/ you create the block which will render the form.
The idea is basically (code updated with suggestion from Henrik):
$builtForm = \Drupal::formBuilder()->getForm('Drupal\your_module\Form\Your‌​Form');
$renderArray['form'] = $builtForm;
return $renderArray;
Note: You don't need to wrap the $builtForm with the $renderArray, you can return just the $builtForm and be fine. I just personally like to do it that way, because often times I need to add something else to the final render array like some markup, cache settings or a library etc.
4. Place the block
Place the block in the desired region(s). Done.
To build a form using block module, you can easily use Webform module where you can add a form and display as a block.
If you mean to create a form programatically in the custom block, you can achieve that by creating two files shown below:
Form file (src/Form/DemoForm.php):
<?php
/**
* #file
* Contains \Drupal\demo\Form\DemoForm.
*/
namespace Drupal\demo\Form;
use Drupal\Core\Form\FormBase;
class DemoForm extends FormBase {
/**
* {#inheritdoc}.
*/
public function getFormId() {
return 'demo_form';
}
/**
* {#inheritdoc}.
*/
public function buildForm(array $form, array &$form_state) {
$form['email'] = array(
'#type' => 'email',
'#title' => $this->t('Your .com email address.')
);
$form['show'] = array(
'#type' => 'submit',
'#value' => $this->t('Submit'),
);
return $form;
}
/**
* {#inheritdoc}
*/
public function validateForm(array &$form, array &$form_state) {
$values = $form_state->getValues();
if (strpos($values['email'], '.com') === FALSE ) {
$form_state->setErrorByName('email', t('This is not a .com email address.'));
}
}
/**
* {#inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
drupal_set_message($this->t('Your email address is #email', array('#email' => $form_state['values']['email'])));
}
}
Source: Building a Drupal 8 Module: Blocks and Forms.
Block file (src/Plugin/Block/HelloBlock.php):
<?php
namespace Drupal\mymodule\Plugin\Block;
use Drupal\Core\Block\BlockBase;
/**
* Provides a 'Hello' Block.
*
* #Block(
* id = "form_block",
* admin_label = #Translation("My form"),
* category = #Translation("My Category"),
* )
*/
class HelloBlock extends BlockBase {
/**
* {#inheritdoc}
*/
public function build() {
$form = \Drupal::formBuilder()->getForm('\Drupal\mymodule\Form\HelloBlock');
//$form['#attached']['js'][] = drupal_get_path('module', 'example') . '/js/example.js';
//$form['#markup'] = $this->t('Custom text');
return $form;
}
}
Source: Create a custom block.
To add a form to the Block Configuration, see: Add a Form to the Block Configuration.
Here is a detailed summary of how to go about this:-
https://www.sitepoint.com/building-drupal-8-module-blocks-forms/
Following the above guide, you would add the completed form to the block build function, e.g.
class DemoBlock extends BlockBase {
/**
* {#inheritdoc}
*/
public function build() {
$form = \Drupal::formBuilder()->getForm('Drupal\demo\Form\DemoForm');
return $form;
}
}
Some more useful docs if you are new to Drupal 8 or need to dust off your knowledge:
https://www.drupal.org/docs/8/creating-custom-modules
https://www.drupal.org/docs/8/api/block-api
https://www.drupal.org/docs/8/api/form-api

How to set form action in Symfony2? (2.8 LTS)

So I've been playing around with Symfony forms and I want to change the form action.
I've followed this guide but I don't understand what it means by "target_route". As such, I was getting an error message (see below)
I have the code below and I'm pretty sure the route I used in setAction is valid since I can browse it using my browser.
Any ideas? Thank you
my code:
<?php
// src/AppBundle/Controller/DirectoryController.php
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
class DirectoryController extends Controller {
/**
* #Route("/directory/form")
*/
public function formAction() {
$form = $this->get("form.factory")
->createNamedBuilder("form", "form")
->setAction($this->generateUrl("/directory/search"))
->setMethod("get")
->add("search", "submit", array("label" => "Search"))
->add("reset", "reset", array("label" => "Reset"))
->getForm();
return $this->render(
"directory/form.html.twig",
array("form" => $form->createView()
,
)
);
}
/**
* #Route("/directory/search")
*/
public function searchAction() {
return $this->render(
"directory/view.html.twig"
);
}
}
error message:
Unable to generate a URL for the named route "/directory/search" as such route does not exist.
In the example, target_route is the name of a route, not its url. For example, you might define an action like this:
/**
* #Route("/directory/search", name="directory_search")
*/
public function searchAction() {
In that case, your route would have a name of directory_search. You would then use $this->generateUrl('directory_search') to have the router turn the name into a url.
The reason you do it this way (as opposed to using urls directly) is that this allows you to change a url without having to change every place in your code that references it.
->setAction($this->generateUrl("/directory/search"))
setAction() expects a url. So you while you can give it '/directory/search', best practice would be to it $this->generateUrl('directory_search').

Embedding Controller using Twig

I've made it simpler (apologies for the complicated question which I've left at the bottom).
I want to have a twig template render another controller as a sub-part.
Here's the parent twig (Resources/views/Default/testRenderParent.html.twig):
<p>Look! I am your father!</p>
<p>But look, I am not your
{{ render(controller("SarelTestBundle:Default:testRenderChild")) }}</p>
Here's the child twig (Resources/views/Default/testRenderChild.html.twig):
KID
The controller (Controller/DefaultController.php):
<?php
namespace Sarel\Test\TestBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
/**
* #Template()
**/
class DefaultController extends Controller
{
/**
* #Route("/testRenderParent")
*/
public function testRenderParentAction()
{
return array();
}
/**
* #Route("/testRenderChild")
*/
public function testRenderChildAction() {
return array();
}
}
When you run this, with the following URL /testRenderChild you should get "KID" echoed.
When you run this, with the URL /testRenderParent (notice the "Parent" part), you should get echoed:
Look! I am your father!
But look, I am your KID
However, instead you get this echoed, and the error below it:
Look! I am your father!
But look, I am not your
Look! I am your father!
But look, I am not your
Look! I am your father!
But look, I am not your
Look! I am your father!
But look, I am not your
Look! I am your father!
But look, I am not your
Look! I am your father!
But look, I am not your
Look! I am your father!
But look, I am not your
Look! I am your father!
But look, I am not your
FatalErrorException: Error: Maximum function nesting level of '250' reached, aborting! in /Users/sarel/www/playpen/app/cache/dev/classes.php line 6134
Thus you can see, it's rendering "Look! I am your father! But look, I am your "... and then instead of rendering the child controller with it's twig template, it re-renders the parent, ending in an endless loop, which is arrested by the exception.
--- copy before I changed it ---
--- copy before I changed it ---
--- copy before I changed it ---
So I'm trying to embed a controller (and ultimately the template that the action renders) in my symfony2 project using the guidelines in enter link description here.
My Controller is defined below:
<?php
namespace OTS\CoreBundle\Controller;
/**
* #Template()
*/
class EmergencyContactsController extends Controller
{
public function addEmergencyContactAction(Request $request, $id) {
return array();
}
}
I have a twig template attached to that, which right now just have "hello world" in the form of a twig file called addEmergencyContact.html.twig.
When I go to the URL for this, which is something like localhost/my_route_to_it it works perfectly fine and I see "hello world" on the screen.
Now, according to this I merely have to put the following twig command in:
{{ render(controller('OTSCoreBundle:EmergencyContacts:addEmergencyContact', {'id': 15})) }}
When I do this and I load the holding-route it appears to be trying to load the main route, and then load the main route again inside the spot where I render the child-route. I know this because it's telling me there's variables missing - variables that I'm only using in the main twig file.
Yet, when I:
Don't have the {{ render... }} in there, it works fine - i.e. it's not other code that's giving me the exception of missing variable
Render only the child-route I get a nice "hello world" back - i.e. it's not the child twig or child controller that's buggy
Hmmm. The question is a bit confusing but:
A. Like all controller actions, your addEmergencyContact needs to return a response, not an array. So:
class EmergencyContactsController extends Controller
{
public function addEmergencyContactAction(Request $request, $id)
{
$tplData = array();
$tplData['id'] = $id;
return $this->render('CoreBundle::emergency_contact.html.twig', $tplData);
}
}
B. You need two template files. Something like:
class HelloWorldController extends Controller
{
public function helloWorldAction(Request $request, $id)
{
$tplData = array();
$tplData['id'] = $id;
return $this->render('CoreBundle::hello_world.html.twig', $tplData);
}
}
C. The render line then goes in the hello_world.html.twig file.
{{ render(controller('OTSCoreBundle:EmergencyContacts:addEmergencyContact', {'id': 15})) }}
D. Note that your emergency_contact template will only have access to values passed into it by the emergency contact action. It will not "inherit" the values that hello_world has.
So why is my code formatting messed up? Did not like numbered lists.
This turns out to be a bug in the way annotations work. When I change the controller from being globally #Template() enabled to moving that old-school back to each action individually, it works. Here's the updated controller, look at where the #Template() now sits:
<?php
namespace Sarel\Test\TestBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
class DefaultController extends Controller
{
/**
* #Route("/testRenderParent")
* #Template()
*/
public function testRenderParentAction()
{
return array();
}
/**
* #Route("/testRenderChild")
* #Template()
*/
public function testRenderChildAction() {
return array();
}
}

How can I set the url for the form to POST using the FormBuilder in Symfony2?

I'm dynamically loading different form classes in my Controller and displaying them in my template. This works fine, except that the Symfony2 docs show adding the route for the form to POST to in the template by hand.
<form action="{{ path('task_new') }}" method="post" {{ form_enctype(form) }}>
{{ form_widget(form) }}
<input type="submit" />
</form>
I need to set that form action in the FormBuilder class-- the POST routes (e.g. 'task_new') are different depending on the form class I'm using. Is there a way to set the form action url in the FormBuilder class? How can we get {{ form_widget(form) }} to render the complete form, and not just the rows? Thanks!
It is possible out of the box -- http://symfony.com/doc/current/book/forms.html#changing-the-action-and-http-method
$form = $this->createFormBuilder($task)
->setAction($this->generateUrl('target_route'))
->setMethod('GET')
->add('task', 'text')
->add('dueDate', 'date')
->add('save', 'submit')
->getForm();
I had the same problem. I was using a simple FormType class and wanted to set the action url in buildForm function. I tried different things, but couldn't do it that way.
Eventually I used a Form option called 'action'. I don't think it's documented in the Symfony Reference, I have found it by accident while reading some error report :).
You can set the option when creating the form within your controller like this:
$form = $this->createForm(new FormType(), $obj, array( 'action' => 'whatever you want'));
It's not as pretty as having it encapsulated in the form class, but it works..
I hope this helps.
It's bad practice to change submit route in form type. It not form type responsibility. If you added form from not handle form route, you can just change action url in template:
{{ form_start(yourForm,{action:path('yourSubmitRoute')}) }}
I solved this problem by injecting the router into my form type. In my application I have created a zip code search form called ZipCodeSearchType:
Form Class
use Symfony\Component\Form\AbstractType;
/*
* I'm using version 2.6. At this time 2.7 has introduced a
* new method for the Option Resolver. Refer to the documentation
* if you are using a newer version of symfony.
*/
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Routing\Router;
/**
* Class ZipCodeSearchType is the form type used to search for plans. This form type
* is injected with the container service
*
* #package TA\PublicBundle\Form
*/
class ZipCodeSearchType extends AbstractType
{
/**
* #var Router
*/
private $router;
public function __construct(Router $router)
{
//Above I have a variable just waiting to be populated with the router service...
$this->router = $router;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('zipCode', 'text', [
'required' => true,
])
/*
* Here is where leverage the router's url generator
*/
//This form should always submit to the ****** page via GET
->setAction($this->router->generate('route_name'))
->setMethod("GET")
;
}
...
}
The next step is to configure your form as a service, and let symfony know that you need the router service injected into your class:
Define Form as Service
/*
* My service is defined in app/config/services.yml and you can also add this configuration
* to your /src/BundleDir/config/services.yml
*/
services:
############
#Form Types
############
vendor_namespace.zip_search_form:
class: VENDOR\BundleNameBundle\Form\ZipCodeSearchType
arguments: [#router]
tags:
- { name: form.type, alias: zip_code_search }
Use It In Your Controller
/**
* #param Request $request
* #return Form
*/
private function searchByZipAction(Request $request)
{
...
$zipForm = $this
->createForm('zip_code_search', $dataModel)
;
...
}
I don't think it's possible out-of-box today (Mar 18 '12). You could, however, do something like this:
in your controller:
....
....
$post_route = null;
if ( $something ){
$post_route = "some_post_route";
}else if ( $something_else ){
$post_route = "some_other_post_route"
}else{
$post_route = "my_default_route";
}
....
....
return array(
'post_route' => $post_route
);
... and in you template:
<form action="{ path(post_route) }" method="post" {{ form_enctype(form) }}>
Similar approach would be to generate URL (not just route name) within your controller and pass it to template, in which case you don't need path function there.

Resources