Undefined offset : 1 error on render controller Symfony - symfony

I am stuck with a problem.
I have a controller in my Symfony 2.8 project named 'AchievementController'. which I put inside a folder named 'Registration'. I have a action named listAction which use to list all achievements. So my folder structure to controller is
AppBundle > Controller > Registration > AchievementController
I am using a file named list.html.twig to list all achievemets. I am planning to use render controller method to render listAction on another twig named new.html.twig. And my twig is placed at
AppBundle > Resources > views > Registration > Achievements > list.html.twig and
AppBundle > Resources > views > Registration > Achievements > new.html.twig.
My problem is when I used render controller method I got an error
"An exception has been thrown during the rendering of a template ("Notice: Undefined offset: 1") in AppBundle:Registration/Achievement:new.html.twig"
I have search a lot but every post tell to do the same way I did (I believe), but not working. And I am stuck there. I am attaching my action and twig. Do I want to set some configuration? What mistake I have done?? I have check the same in other projects and it works fine. So I'm confused. (And when I use a folder structure AppBundle > Controller > AchievementController and change code for this, it works fine. Simply it feels like a escape slash problem. But I didn't get any way to fix it.)
new.html.twig
{{ render(controller('AppBundle:Registration/Achievement:list')) }}
listAction
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('AppBundle:Registration\Achievement')->findAll();
return $this->render('AppBundle:Registration/Achievement:list.html.twig', array(
'entities' => $entities,
));
list.html.twig
{% if entities %}
--------
--------
{% endif %}
Thanks for every answers.
I have used yml method to generate bundle.
I am attaching my action and controller here. (Removed other actions in controller)
<?php
namespace AppBundle\Controller\Registration;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use AppBundle\Entity\Registration\Achievement;
use AppBundle\Form\Registration\AchievementType;
class AchievementController extends Controller {
public function listAction() {
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('AppBundle:Registration\Achievement')->findAll();
return $this->render('AppBundle:Registration/Achievement:list.html.twig', array(
'entities' => $entities,
));
}
}

Related

How can I render a controller action within a twig extension?

I do have a twig extension which has a method that uses another method from a different controller to render a json output via dependency jsonResponse.
How can I render a controller within a twig extension?
The following code below doesn't seem to work, because render() needs a view file instead of a controller. And I am now referencing to a controller.
class AreaExtension extends \Twig_Extension {
public function add()
{
$outputJson = $this->container->get('templating')->render(new ControllerReference('CMSCoreBundle:Area:index'));
}
}
$ref = new ControllerReference('CMSCoreBundle:Area:index');
$this->handler->render( $ref, 'inline', $options );
Where $this->handler is the fragment.handler service.
In your case:
$outputJson = $this->container->get('fragment.handler')->render(new ControllerReference('CMSCoreBundle:Area:index'));
You can find a full example in this symfony twig extension, see:
https://github.com/symfony/symfony/blob/4.1/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php#L28
and
https://github.com/symfony/symfony/blob/4.1/src/Symfony/Bridge/Twig/Extension/HttpKernelRuntime.php#L41

Global values: Define as service or define abstract Controller class?

In my Symfony2 app, I want to globally fetch a value from my database on each template and don't want to call on each Controller. I know I could define that as a service and inject that service into my twig templates (by defining it as a twig global).
Is that the common and recommended way? Or should I rather create an abstract Controller class where I fetch that value in my constructor and then inherit from all my other Controllers?
Note: It is actually not a static value that is the same for all users, but it is a user specific value which is different for each user.
If this variables are used to render the same spot on your page you can render an embedded controller. Like this:
<div id="sidebar">
{{ render(controller('YourBundle:User:stats')) }}
</div>
This will inject whole output of YourBundle/UserController/statsAction to the #sidebar div. Inside this action you can extract all inforamtion that you need.
If you need to use this variables in other way maybe you should look at response event.
Are you familiar with event listeners? http://symfony.com/doc/current/cookbook/service_container/event_listener.html
An event listener can be used to inject twig globals.
class ModelEventListener extends ContainerAware implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return array(
KernelEvents::CONTROLLER => array(
array('doProject', -1300),
),
KernelEvents::VIEW => array(
array('doView', -2100),
),
);
}
public function doProject(FilterControllerEvent $event)
{
$project = $whatever_is_needed_to_find_the_project();
if (!$project) throw new NotFoundHttpException('Project not found ' . $projectSearch);
// Add to request
$event->getRequest()->attributes->set('project',$project);
// Give all twig templates access to project
$twig = $this->container->get('twig');
$twig->addGlobal('project',$project);
}
# services.yml
cerad_core__model__event_listener:
class: '%cerad_core__model__event_listener__class%'
calls:
- [setContainer, ['#service_container']]
tags:
- { name: kernel.event_subscriber }
If it's a user value like you said you can get app.user.XXX on every twig template you need without processing nothing ;)

Symfony project; SonataUser, FOSUser and their registration_content.html.twig

Solved -- see bottom of entry
I'm trying to get familiar with the SonataUserBundle extending the FOSUserBundle.
The installation worked fine (as far as I can tell) and now I want to customize
the login and registration forms.
I overwrote templates in app/Resources and it worked fine.
However, for the registration form I do not understand why it works...
Here's my problem:
The SonataUserBundle registration controller (RegistrationFOSUser1) sets up the form
and renders it with FOSUserBundle:Registration:register.html.twig as template:
$form = $this->container->get('sonata.user.registration.form');
$formHandler = $this->container->get('sonata.user.registration.form.handler');
[...]
return $this->container->get('templating')->renderResponse('FOSUserBundle:Registration:register.html.'.$this->getEngine(), array(
'form' => $form->createView(),
));
register.html.twig includes FOSUserBundle:Registration:register_content.html.twig:
{% block fos_user_content %}
{% include "FOSUserBundle:Registration:register_content.html.twig" %}
{% endblock fos_user_content %}
register_content.html.twig contains the twig code to render the form.
However, what is actually rendered is SonataUserBundle:Registration:register_content.html.twig
I just can't figure out where, when and how SonataUserBundle substitutes FOSUserBundle here...
Thanks for any hints!
Ok, I now see that the solution to my question is well documented in the symfony cookbook:
http://symfony.com/doc/current/cookbook/bundles/inheritance.html
For those as new to symfony as myself:
If you define a parent 'ParentBundle' for another bundle 'ChildBundle', then everytime a function, template etc. from ParentBundle is called, symfony will first look whether there is a file with the same name in ChildBundle.
The parent bundle is defined in the ChildBundle.php:
public function getParent()
{
return 'ParentBundle';
}
This works, as long as the file of the parent bundle is called via the usual ParentBundle:path:file notation.
Ok, I now see that the solution to my question is well documented in the symfony cookbook: http://symfony.com/doc/current/cookbook/bundles/inheritance.html
For those as new to symfony as myself:
If you define a parent 'ParentBundle' for another bundle 'ChildBundle', then everytime a function, template etc. from ParentBundle is called, symfony will first look whether there is a file with the same name in ChildBundle.
The parent bundle is defined in the ChildBundle.php:
public function getParent()
{
return 'ParentBundle';
}
This works, as long as the file of the parent bundle is called via the usual ParentBundle:path:file notation.

How to add custom link or button to SonataAdminBundle Dashboard in Symfony2

I am new with symfony2 and SonataAdminBundle.
I have added 3 entities to the SonataAdminBundle Dashboard and they appear successfully.
The Entities appear with the default links - "Add new" and "List" buttons.
I want to be able to do the following
I want to add a third link to one of the entities on the dashboard.
I want to be able to add a link to the buttons located above the grid in the
default list page.
I want to be able to add/customize links appearing under the form on Edit or Create new page
I have not been able to find a way to do any of the above, been searching for hours, any help will be highly appreciated.
thanks.
To display custom elements in the dashbord Sonata Admin uses Sonata Block Bundle.
To add custom link or button you need to create a new block using Sonata Block Bundle.
The core template (dashboard.html.twig) of the Admin Bundle iterates blocks that is configured to run (in config.yml of the application).
Still, Admin Bundle iterates all your entity blocks in the template block_admin_list.html.twig. Creating your custom block template it is from here that you can take layout to wrap your custom groups (sections) and buttons so they have same feel as those of the entities groups.
Ok, it was introduction.
For example we want to make custom newsletter section.
There are steps:
create new block class that implements BlockBundleInterface
create new block template
create block service (read and understand what are services in Symfony 2 library)
add newly created service to Sonata Block Bundle configuration
add newly created service to Sonata Admin Bundle configuration
enter dashboard and enjoy new group/button/link/whatever-stuff-you-put-in-your-block-template :)
Ad1) Create new block class
General instruction under: http://sonata-project.org/bundles/block/master/doc/reference/your_first_block.html
My file looks like this:
<?php
namespace InstitutoStorico\Bundle\NewsletterBundle\Block;
use Symfony\Component\HttpFoundation\Response;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Validator\ErrorElement;
use Sonata\BlockBundle\Model\BlockInterface;
use Sonata\BlockBundle\Block\BaseBlockService;
class NewsletterBlockService extends BaseBlockService
{
public function getName()
{
return 'My Newsletter';
}
public function getDefaultSettings()
{
return array();
}
public function validateBlock(ErrorElement $errorElement, BlockInterface $block)
{
}
public function buildEditForm(FormMapper $formMapper, BlockInterface $block)
{
}
public function execute(BlockInterface $block, Response $response = null)
{
// merge settings
$settings = array_merge($this->getDefaultSettings(), $block->getSettings());
return $this->renderResponse('InstitutoStoricoNewsletterBundle:Block:block_my_newsletter.html.twig', array(
'block' => $block,
'settings' => $settings
), $response);
}
}
I added some lines reading Sonata Media Bundle code files.
Ad2) Create new block template
Layout I took from block_admin_list.html.twig of Sonata Admin bundle.
My file looks like this:
{% extends 'SonataBlockBundle:Block:block_base.html.twig' %}
{% block block %}
<table class="table table-bordered table-striped sonata-ba-list">
<thead>
<tr>
<th colspan="3">Newsletter - inviare</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="btn-group" align="center">
<a class="btn btn-small" href="#">Servizio Newsletter</a>
</div>
</td>
</tr>
</tbody>
</table>
{% endblock %}
Ad3) Create block service
In your bundle there's a file where you declare services (services.yml or admin.yml). Whatever. But it's important that it is plugged into config.yml of your application in "imports" section.
My service declaration looks like this:
sonata.block.service.newsletter:
class: InstitutoStorico\Bundle\NewsletterBundle\Block\NewsletterBlockService
arguments: [ "sonata.block.service.newsletter", #templating ]
tags:
- { name: sonata.block }
Ad4) Add newly created service to Sonata Block Bundle configuration
This configuration is put into config.yml of your application.
My config looks like this:
#Sonata Block Bundle
sonata_block:
default_contexts: [cms]
blocks:
sonata.admin.block.admin_list:
contexts: [admin]
sonata.block.service.text: ~
sonata.block.service.action: ~
sonata.block.service.rss: ~
sonata.block.service.newsletter: ~
Ad5) Add newly created service to Sonata Admin Bundle configuration
This configuration is put into config.yml of your application.
My config looks like this:
# Sonata Admin Generator
sonata_admin:
...
dashboard:
blocks:
# display a dashboard block
- { position: left, type: sonata.admin.block.admin_list }
- { position: left, type: sonata.block.service.newsletter}
Ad6) Enter dashboard and enjoy
That's all. Looks like complicated, but to be sincere it is not so much. It's important it's a clean way of modifying your dashboard page without overriding whole templates without great need.
All those Il learned reading source code of Admin Bundle :) Whole day
I had troubles with method execute (I am using Sonata 2.3.x ).
Here is the code that works for me.
Note BlockContextInterface and $blockContext->getBlock() :
public function execute(BlockContextInterface $blockContext, Response $response = null)
{
// merge settings
$settings = array_merge($this->getDefaultSettings(), $blockContext->getSettings());
return $this->renderResponse('bundleName:Block:templateName.html.twig', array(
'block' => $blockContext->getBlock(),
'settings' => $settings
), $response);
}

stripslashes inside Twig template

i want to use the php stripslashes function inside a twig template but this function is not a standard twig function, so i have to add it to twig as an extension, i tried this code inside a controller, but it doesnt work:
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
class XController extends Controller
{
public function YAction($page)
{
$twig=$this->get('twig');
$twig->addFunction('functionName', new Twig_Function_Function('someFunction'));
...
do i need a use statement for the "Twig_Function_Function" class?
am i doing this wrong?
If you want to use it in your twig templates, you don't need to make any add or call inside your controller, Read the How to write a custom Twig Extension section of the documentation.
Basicaly, you need to create an Extension Class that extends \Twig_Extension , then you need to register it as a service using the twig.extension tag. And finally you need to implement the getFunctions() method in order to add customized twig functions.
But in your case better is to add a filter, with the same logic you can also add a getFilters() method in your extension class so that you can specify your customized filters.
Also, take a deeper look at the Extending Twig section of the documentation to understand all the ways twig can be extended.
Or {{ function('stripslashes', "This\\'ll do") }}
(or apply stripslashes() when building your Twig context)
But, also, if you do this in php:
add_filter('timber/twig', function(\Twig_Environment $twig) {
$twig->addFunction(new Twig\TwigFunction('stripslashes', 'stripslashes'));
return $twig;
});
Then this works in twig:
{{ stripslashes("This\'ll do...") }}

Resources