Twig Extension For Including Templates in Symfony - symfony

I'm storing page code in database so that the admin will be able to rearrange sections and edit content.
I'm organizing all the code in the controller before sending a response that has all the code for the page.
I've seen this question: How to render Twig template from database in symfony2 and it is not the same as the one I'm asking
I'd like to be able to have a code in the database like "{% include 'tmp/header.html.twig' %} and have the twig run that.
So far twig gives an error that 'Template "tmp/header.html.twig" is not defined in __string_template__59b79c6909e3d467bcae264ee8ebdf3697db94a9096b7457d0c43bac9c0d8fb1 at line 345.'
Here is a test page:
/**
* #Route("/test/for/conservatoire/of/music", name="test")
*/
public function test(PageRepository $pageRepo, SectionRepository $sectionRepo): Response
{
// this page
$page = $pageRepo->findOneByName('about');
// html is now empty
$html = "<html><body><h1>Hello pal</h1></body></html>";
// THIS IS THE PROBLEMATIC PART
$html .= '{% include("tmp/header.html.twig") %}';
$variables = ['this' => 'that'];
$loader = new \Twig\Loader\ArrayLoader([
'test.html.twig' => '{{ include(template_from_string(html)) }}',
]);
$twig = new \Twig\Environment($loader);
$profile = new \Twig\Profiler\Profile();
$context = new Routing\RequestContext();
$router = $this->get('router');
$routes = $router->getRouteCollection();
$generator = new Routing\Generator\UrlGenerator($routes, $context);
$versionStrategy = new StaticVersionStrategy('v1');
$defaultPackage = new Package($versionStrategy);
$namedPackages = [
'img' => new UrlPackage('http://img.example.com/', $versionStrategy),
'doc' => new PathPackage('/somewhere/deep/for/documents', $versionStrategy),
];
$packages = new Packages($defaultPackage, $namedPackages);
// this enables template_from_string function
$twig->addExtension(new \Twig\Extension\StringLoaderExtension());
// this enables debug
$twig->addExtension(new \Twig\Extension\DebugExtension());
// this enables {{asset('somefile')}}
$twig->addExtension(new AssetExtension($packages));
// this enables {{path('someroute')}}
$twig->addExtension(new RoutingExtension($generator));
// I NEED ONE THAT ENABLES {% include('tmp/header.html.twig') %}
// so far I'm getting this error:
// Template "tmp/header.html.twig" is not defined in __string_template__59b79c6909e3d467bcae264ee8ebdf3697db94a9096b7457d0c43bac9c0d8fb1 at line 345.
$response = new Response();
$response->setContent($twig->render('test.html.twig', ['html' => $html]));
$response->setStatusCode(Response::HTTP_OK);
// sets a HTTP response header
$response->headers->set('Content-Type', 'text/html');
// return response
return $response;
}
It doesn't work even when the include is added separately like so:
$loader = new \Twig\Loader\ArrayLoader([
'test.html.twig' => '{% include("tmp/header.html.twig") %}{{ include(template_from_string(html)) }}',
]);
Error: Template "tmp/header.html.twig" is not defined in test.html.twig at line 1.

I finally found out the way to do it.
I only needed to add the page to be included to the ArrayLoader like so:
use Symfony\Component\Routing;
use Symfony\Component\Asset\VersionStrategy\StaticVersionStrategy;
use Symfony\Component\Asset\Package;
use Symfony\Component\Asset\UrlPackage;
use Symfony\Component\Asset\PathPackage;
use Symfony\Component\Asset\Packages;
use Symfony\Bridge\Twig\Extension\AssetExtension;
use Symfony\Bridge\Twig\Extension\RoutingExtension;
/**
* #Route("/test/for/conservatoire/of/music", name="test")
*/
public function test(PageRepository $pageRepo, SectionRepository $sectionRepo): Response
{
// this page
$page = $pageRepo->findOneByName('about');
// html is now empty
$html = "<html><body><h1>Hello from test</h1></body></html>";
// THIS WAS THE PROBLEMATIC PART
$html .= '{{ include("header.html.twig") }}';
$variables = ['this' => 'that'];
// HERE IS THE SOLUTION -> ADD THE NEW TEMPLATE TO THE ARRAY LOADER
$loader = new \Twig\Loader\ArrayLoader([
'test.html.twig' => '{{ include(template_from_string(html)) }}',
'header.html.twig' => "<html><body><h1>Hello from {{name}}</h1></body></html>",
]);
$twig = new \Twig\Environment($loader);
$profile = new \Twig\Profiler\Profile();
$context = new Routing\RequestContext();
$router = $this->get('router');
$routes = $router->getRouteCollection();
$generator = new Routing\Generator\UrlGenerator($routes, $context);
$versionStrategy = new StaticVersionStrategy('v1');
$defaultPackage = new Package($versionStrategy);
$namedPackages = [
'img' => new UrlPackage('http://img.example.com/', $versionStrategy),
'doc' => new PathPackage('/somewhere/deep/for/documents', $versionStrategy),
];
$packages = new Packages($defaultPackage, $namedPackages);
// this enables template_from_string function
$twig->addExtension(new \Twig\Extension\StringLoaderExtension());
// this enables debug
$twig->addExtension(new \Twig\Extension\DebugExtension());
// this enables {{asset('somefile')}}
$twig->addExtension(new AssetExtension($packages));
// this enables {{path('someroute')}}
$twig->addExtension(new RoutingExtension($generator));
$response = new Response();
$response->setContent($twig->render('test.html.twig', ['html' => $html, 'name' => 'header']));
$response->setStatusCode(Response::HTTP_OK);
// sets a HTTP response header
$response->headers->set('Content-Type', 'text/html');
// return response
return $response;
}

Related

auto-responder with login details in Symfony

Here is the funcion im using
public function sendCredentialsEmailMessage(UserInterface $user)
{
$template = 'Emails/afterRegister.html.twig';
$rendered = $this->templating->render($template, array(
'user' => $user,
));
$this->sendEmailMessage($rendered,
$this->parameters['from_email']['confirmation'], $user->getEmail());
}
Basically I want the auto-mailer to send my template along with the login name. When i create a new user nothing is being sent. My email template is located in app>resources>views>emails>
and this controller file is located in src>myname>userbundle>mailer>
protected function sendEmailMessage($renderedTemplate, $fromEmail, $toEmail)
{
// Render the email, use the first line as the subject, and the rest as the body
$renderedLines = explode("\n", trim($renderedTemplate));
$subject = array_shift($renderedLines);
$body = implode("\n", $renderedLines);
$message = (new \Swift_Message())
->setSubject($subject)
->setFrom($fromEmail)
->setTo($toEmail)
->setBody($body);
$this->mailer->send($message);
}
Also this works for sure:
public function sendResettingEmailMessage(UserInterface $user)
{
$template = $this->parameters['resetting.template'];
$url = $this->router->generate('fos_user_resetting_reset', array('token' => $user->getConfirmationToken()),
UrlGeneratorInterface::ABSOLUTE_URL);
$rendered = $this->templating->render($template, array(
'user' => $user,
'confirmationUrl' => $url,
));
$this->sendEmailMessageCustom($rendered, $this->from, (string)$user->getEmail(),'Password resseting');
}

Why won't my kernel.response event listener modify my response?

I don't find the reason why my subsequent kernel.response event listener won't modify my response here. Do you encountered this problem too before, or is there a misprint into the lines ?
Context: users will have a 10-items visit history attached to them, under Symfony3.
public function onResponse(FilterResponseEvent $event)
{
$request = $event->getRequest();
if(!$event->isMasterRequest() || !preg_match('#^dm_.*#', $request->get('_route'))){
return;
}
$history = $request->cookies->get('history');
if(!$history)$history = "[]";
$history = json_decode($history, true);
$addon = [
'route' => $request->get('_route'),
'route_params' => $request->attributes->get('_route_params'),
'url' => $request->getRequestUri(),
'date' => new \Datetime
];
$history[] = $addon;
$history = array_slice(
$history,
-10
);
$cookie = new Cookie('history', json_encode($history), time() + 3600);
$response = $event->getResponse();
$response->headers->setCookie($cookie);
}
I added some var_dump()s, to check that event was caught (and it was). I also tested to modify headers elsewhere, and it works fine. So, just here, I don't see why it doesn't.

Payum Paypal on Symfony3

I'm trying to integrate a payment system of paypal on my webpage under Symfony. After some researches, I ran into Payum which is a apparently the best bundle for this feature.
The issue is that I don't really understand the doc so the final code I have doesn't work.
Somebody already used payum and could help me to understand it ?
I have for example : $paypalRestPaymentDetailsClass which comes from nowhere and I don't know what should be in this class
Here is my code :
namespace PlatformBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Payum\Core\PayumBuilder;
use Payum\Core\Payum;
use PayPal\Api\Amount;
use PayPal\Api\Payer;
use PayPal\Api\RedirectUrls;
use PayPal\Api\Transaction;
use Payum\Core\Request\GetHumanStatus;
class PayumController extends Controller
{
private function config()
{
return (new PayumBuilder())
->addDefaultStorages()
->addGateway('gatewayName', [
'factory' => 'paypal_rest',
'client_id' => 'REPLACE IT',
'client_secret' => 'REPLACE IT',
'config_path' => 'REPLACE IT',
])
->getPayum();
}
public function prepare()
{
$payum = $this->config();
$storage = $payum->getStorage($paypalRestPaymentDetailsClass);
$payment = $storage->create();
$storage->update($payment);
$payer = new Payer();
$payer->payment_method = "paypal";
$amount = new Amount();
$amount->currency = "USD";
$amount->total = "1.00";
$transaction = new Transaction();
$transaction->amount = $amount;
$transaction->description = "This is the payment description.";
$captureToken = $payum->getTokenFactory()->createCaptureToken('paypalRest', $payment, 'create_recurring_payment.php');
$redirectUrls = new RedirectUrls();
$redirectUrls->return_url = $captureToken->getTargetUrl();
$redirectUrls->cancel_url = $captureToken->getTargetUrl();
$payment->intent = "sale";
$payment->payer = $payer;
$payment->redirect_urls = $redirectUrls;
$payment->transactions = array($transaction);
$storage->update($payment);
header("Location: ".$captureToken->getTargetUrl());
}
public function capture()
{
$payum = $this->config();
$token = $payum->getHttpRequestVerifier()->verify($_REQUEST);
$gateway = $payum->getGateway($token->getGatewayName());
if ($reply = $gateway->execute(new Capture($token), true)) {
if ($reply instanceof HttpRedirect) {
header("Location: ".$reply->getUrl());
die();
}
throw new \LogicException('Unsupported reply', null, $reply);
}
$payum->getHttpRequestVerifier()->invalidate($token);
header("Location: ".$token->getAfterUrl());
}
public function done()
{
$payum = $this->config();
$token = $payum->getHttpRequestVerifier()->verify($_REQUEST);
$gateway = $payum->getGateway($token->getGatewayName());
// you can invalidate the token. The url could not be requested any more.
// $payum->getHttpRequestVerifier()->invalidate($token);
// Once you have token you can get the model from the storage directly.
//$identity = $token->getDetails();
//$payment = $payum->getStorage($identity->getClass())->find($identity);
// or Payum can fetch the model for you while executing a request (Preferred).
$gateway->execute($status = new GetHumanStatus($token));
$payment = $status->getFirstModel();
header('Content-Type: application/json');
echo json_encode(array(
'status' => $status->getValue(),
'order' => array(
'total_amount' => $payment->getTotalAmount(),
'currency_code' => $payment->getCurrencyCode(),
'details' => $payment->getDetails(),
),
));
}
}
Thanks

isValid() method return false in symfony

I am using symfony3 with window 7 AND using custom form rending. like that
{{ form_start(form,{ 'attr': {'class': 'form-horizontal','role':'form','id':'form'} }) }}
---- form field here
{{ form_widget(form._token) }}
{{ form_end(form, {'render_rest': false}) }}
/**
* #Route("entity/entity/{id}", name="entity_entity",defaults={"id" = 0})
*/
public function entityAction(Request $request,$id){
$action = false;
$arr_XYZ_data = array();
$arr_XYZ_prepare_data = array();
$form_title = 'Add New XYZ';
$obj_XYZ = new XYZ();
$form = $this->createForm(XYZType::class, $obj_XYZ);
if($id!=0){
$obj_repo = $this->getDoctrine()->getRepository('AppBundle:XYZ');
$arr_XYZ_data = $obj_repo->find($id);
if($arr_XYZ_data){
$action = true;
$form_title = 'Update XYZ';
$arr_XYZ_data = $obj_repo->findXYZById($id);
$arr_XYZ_prepare_data = $this->_prepareData($arr_XYZ_data);
}
}
$form->handleRequest($request);
if (($form->isSubmitted())&&($form->isValid())) {
$obj_XYZ->setXYZId($id);
$str_hiddenfield_result = $form->get('extraformfield')->getData();
$arr_hiddenfield_result = explode('&',$str_hiddenfield_result);
$obj_XYZ->setDef($obj_XYZ->getDef()->getDefId());
$obj_XYZ->setAbc($arr_hiddenfield_result[3]);
$obj_XYZ->setAuthor(1); //ldap session value
$em = $this->getDoctrine()->getManager();
$em->persist($obj_XYZ);
$em->flush();
$this->addFlash('success', 'Your record has been added successfully!');
return $this->redirectToRoute('XYZ_index', array(), 301);
}else{
$form->getErrors();
}
}
above code does not print any error but unable to submit. so please anyone can suggest me how can i fix the issue.
how to get all error in string with corresponding each form field.
Just calling the getter will not print anything, you need to do it by yourself using another (printing) function.
return new \Symfony\Component\HttpFoundation\Response($form->getErrors());
It will render a string containing all errors.
Depending on the context (traditional, ajax, ...), you can just re-render the form like so:
return $this->render('YourBundle:YourView.html.twig', [
'form' => $form->createView(),
]);
The errors should be properly displayed.

ZF2 Unit test album module returns routing issue

I am trying out the phpunit in the Zf2 album module. I encountered an error which states about routing.
Below is the debug information. It says 'Route with name "album" not found', but when I checked module.config.php in the album module folder, I see that is correctly set and in the browser the redirection to that route is working fine.
Album\Controller\AlbumControllerTest::testDeleteActionCanBeAccessed
Zend\Mvc\Router\Exception\RuntimeException: Route with name "album" not found
D:\www\zend2\vendor\zendframework\zendframework\library\Zend\Mvc\Router\SimpleRouteStack.php:292
D:\www\zend2\vendor\zendframework\zendframework\library\Zend\Mvc\Controller\Plugin\Url.php:88
D:\www\zend2\vendor\zendframework\zendframework\library\Zend\Mvc\Controller\Plugin\Redirect.php:54
D:\www\zend2\module\Album\src\Album\Controller\AlbumController.php:80
D:\www\zend2\vendor\zendframework\zendframework\library\Zend\Mvc\Controller\AbstractActionController.php:87
D:\www\zend2\vendor\zendframework\zendframework\library\Zend\EventManager\EventManager.php:468
D:\www\zend2\vendor\zendframework\zendframework\library\Zend\EventManager\EventManager.php:208
D:\www\zend2\vendor\zendframework\zendframework\library\Zend\Mvc\Controller\AbstractController.php:108
D:\www\zend2\tests\module\Album\src\Album\Controller\AlbumControllerTest.php:35
C:\wamp\bin\php\php5.4.3\phpunit:46
I understand that the issue in AlbumController.php line 80 is
return $this->redirect()->toRoute('album');
But not sure why it is not working. Any one has encountered and overcome such issues?
To avoid duplicate Code, you can load your Routes from Module Config:
$module = new \YourNameSpace\Module();
$config = $module->getConfig();
$route = \Zend\Mvc\Router\Http\Segment::factory($config['router']['routes']['Home']['options']);
$router = new \Zend\Mvc\Router\SimpleRouteStack();
$router->addRoute('Home', $route);
I hope it will save approx. 30 minutes of searching in the zend framework 2 code:
class AlbumControllerTest extends PHPUnit_Framework_TestCase
{
//...
protected function setUp()
{
$bootstrap = \Zend\Mvc\Application::init(include 'config/application.config.php');
$this->controller = new AlbumController();
$this->request = new Request();
$this->routeMatch = new RouteMatch(array('controller' => 'index'));
$this->event = $bootstrap->getMvcEvent();
$router = new \Zend\Mvc\Router\SimpleRouteStack();
$options = array(
'route' => '/album[/:action][/:id]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
),
'defaults' => array(
'controller' => 'Album\Controller\Album',
'action' => 'index',
),
);
$route = \Zend\Mvc\Router\Http\Segment::factory($options);
$router->addRoute('album', $route);
$this->event->setRouter($router);
$this->event->setRouteMatch($this->routeMatch);
$this->controller->setEvent($this->event);
$this->controller->setEventManager($bootstrap->getEventManager());
$this->controller->setServiceLocator($bootstrap->getServiceManager());
}
}
Actually the easy way is to get the config data from the service manager:
$config = $serviceManager->get('Config');
Full code for the function setUp():
protected function setUp() {
$serviceManager = Bootstrap::getServiceManager();
$this -> controller = new AlbumController();
$this -> request = new Request();
$this -> routeMatch = new RouteMatch(
array(
'controller' => 'index',
)
);
$this -> event = new MvcEvent();
$config = $serviceManager->get('Config');
$routerConfig = isset($config['router']) ? $config['router'] : array();
$router = HttpRouter::factory($routerConfig);
$this -> event -> setRouter($router);
$this -> event -> setRouteMatch($this -> routeMatch);
$this -> controller -> setEvent($this -> event);
$this -> controller -> setServiceLocator($serviceManager);
}

Resources