How to use symfony2 twig extension without symfony2 - symfony

I want to use some of the builtin symfony2 extensions(e.g:humanize,yaml_dump) for twig for a website not developed in symfony but using a twig engine.how can I do that?

The symfony/twig-bridge package provides the symfony-specific twig extensions.
These include i.e. the YamlExtension that provides the yaml_dump filter and the FormExtension that provides the humanize filter.
The extensions can be found in the Extension folder.
I strongly advise you to install the package via composer to get the package's dependencies automatically.
composer require symfony/twig-bridge:~2.3
Further composer will automatically register the classes in the autoloader (vendor/autoload.php) for you.
Now you just need to add the extensions to twig as described in the documentation.
$twig->addExtension(new \Symfony\Bridge\Twig\Extension\YamlExtension());
// ...

A complete example, with an extension class and a quick extension (a new filter) :
<?php
require_once("vendor/autoload.php");
$loader = new Twig_Loader_String();
$twig = new Twig_Environment($loader);
// here we add the extension class (taken from #nifr answer)
$twig->addExtension(new \Symfony\Bridge\Twig\Extension\YamlExtension());
// here we add a new filter quickly
$filter = new Twig_SimpleFilter('paragraph', function ($argument) {
return "<p>{$argument}</p>";
}, array('pre_escape' => 'html', 'is_safe' => array('html')));
$twig->addFilter($filter);
// demo
echo $twig->render('{{ "hello" | paragraph }}');

Related

How to run Drupal 8 functions from an external PHP file

Is there any way to execute Drupal 8 functions from an external PHP file.
You can include/call Drupal's bootstrap in your script and after that call Drupal's functions. Used that for D7, but didn't try for D8. However it should work:
https://drupal.stackexchange.com/questions/174474/bootstrap-from-external-script
And to copy code from that page:
define('DRUPAL_DIR', '/usr/share/nginx/html');
use Drupal\Core\DrupalKernel;
use Symfony\Component\HttpFoundation\Request;
require_once DRUPAL_DIR . '/core/includes/database.inc';
require_once DRUPAL_DIR . '/core/includes/schema.inc';
// Specify relative path to the drupal root.
$autoloader = require_once DRUPAL_DIR . '/autoload.php';
$request = Request::createFromGlobals();
// Bootstrap drupal to different levels
$kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
$kernel->boot();
$kernel->prepareLegacyRequest($request);
$em = $kernel->getContainer()->get('entity.manager');
$entity = $em->getStorage('node')->create(
array(
'type' => "article",
'title'=> "test entity",
'body' => "body body body",
));
$entity->save();
If you have Drush, you can run "drush scr [filename]" which will execute the file as well as bootstrap Drupal. I did a blog post about this - https://www.oliverdavi.es/blog/dont-bootstrap-drupal-use-drush.
I'd only use this for simple local test scripts though to test things out before moving the code into proper functions/classes/controllers/services etc.
You can run any php code either drupal or non-drupal using Devel and Kint module like this.[Use Devel and Kint module] like this
https://i.stack.imgur.com/RUKv6.png

Symfony 1.2 to 2.3 migration

I've got a pretty big Symfony 1.2 project to migrate.
First, I modified my .htaccess so I can have some pages handled by Symfony 2.
What I'd like to do, to make the migration smoother, is to be able to render some SF2 action/templates/methods/... inside SF1.
I added the autoloader to the SF1 app, so I can access to twig rendering methods and other stuff.
But how can I call a SF2 action ?
For example, if I want to migrate only the footer first, I would also need some php methods, not only rendering. That was previously in SF1 component, where should it be now ?
If you've got any suggestion about the way of migrating, don't hesitate !
EDIT 1 :
Apparently, the only way to do something like that is to render a full twig template, and/or in this template call some other partial twig templates with render(url, params).
Here is my SF1 code to be able to render twig templates :
public static function getTwig()
{
require_once __DIR__.'SF2_PATH/vendor/twig/extensions/lib/Twig/Extensions/Autoloader.php';
Twig_Autoloader::register();
$loader = new Twig_Loader_Filesystem( __DIR__.'SF2_PATH/sf2/src/VENDOR/BUNDLE/');
$twig = new Twig_Environment($loader, array(
'cache' => __DIR__.'SF2_PATH/sf2/app/cache/dev/twig',
));
return $twig;
}
And so :
$twig->loadTemplate('header.html.twig');
EDIT 2 :
That doesn't seem to work, if in a twig template I try to render an other one with {{render(controller('BUNDLE:CONTROLER:ACTION', {})) }} for example Twig_Error : The function "controller" does not exist. And if I try to render the url Unknown tag name "render".
I guess Symfony 2 twig functionalities are not loaded, how can I do that ?
EDIT 3 :
Ok, now I can do it, but I've got the following message...
Twig_Error_Runtime An exception has been thrown during the rendering
of a template ("Rendering a fragment can only be done when handling a
master Request.") in ...
EDIT : I solved it !
Here is my full bootstrap method to render a Twig template and be able to use some Symfony 2 functionalities, in Symfony 1.
$loader = require_once __DIR__.'/../../../sf2/app/bootstrap.php.cache';
Debug::enable();
require_once __DIR__.'/../../../sf2/app/AppKernel.php';
$kernel = new AppKernel('dev', true);
$kernel->loadClassCache();
Request::enableHttpMethodParameterOverride();
$request = Request::createFromGlobals();
$kernel->boot();
$kernel->getContainer()->enterScope('request');
$kernel->getContainer()->set('request', new \Symfony\Component\HttpFoundation\Request(), 'request');
$this->container = $kernel->getContainer()->get('twig');

Custom route configuration with Silex

I know that the basis of Silex approach in which all the application logic in a single file. But my application will be possible to have more than twenty controllers. So I want to have a handy map to manage the router.
My question is to search for solutions in which I would be able to make a router to a separate file. In the best case, the file must be of YAML type:
# config/routing.yml
_home:
pattern: /
defaults: { _controller: MyProject\Controller\MyController::index }
But the native is also a good case (for me):
$routes = new RouteCollection();
$routes->add(
'home',
new Route('/', array('controller' => 'MyProject\Controller\MyController::index')
));
return $routes;
Problem of the second case is that I have to use the match() function for each rule of routing. It is not at all clear.
What are the ways to solve this issue? The condition is that I want to use the existing API Silex or components of Symfony2.
Small note:
I don't use a ControllerProviderInterface for my Controller classes. This is an independent classes.
First of all, the basis of Silex is not that you put everything in one file. The basis of Silex is that you create your own 'framework', your own way of organizing applications.
"Use silex if you are comfortable with making all of your own architecture decisions and full stack Symfony2 if not."
-- Dustin Whittle
Read more about this in this blogpost, created by the creator of Silex.
How to solve your problem
What you basically want is to parse a Yaml file and get the pattern and defaults._controller settings from each route that is parsed.
To parse a Yaml file, you can use the Yaml Component of Symfony2. You get an array back which you can use to add the route to Silex:
// parse the yaml file
$routes = ...;
$app = new Silex\Application();
foreach ($routes as $route) {
$app->match($route['pattern'], $route['defaults']['_controller']);
}
// ...
$app->run();
I thought I'd add my method here as, although others may work, there isn't really a simple solution. Adding FileLocator / YamlFileLoader adds a load of bulk that I don't want in my application just to read / parse a yaml file.
Composer
First, you're going to need to include the relevant files. The symfony YAML component, and a really simple and useful config service provider by someone who actively works on Silex.
"require": {
"symfony/yaml": "~2.3",
"igorw/config-service-provider": "1.2.*"
}
File
Let's say that your routes file looks like this (routes.yml):
config.routes:
dashboard:
pattern: /
defaults: { _controller: 'IndexController::indexAction' }
method: GET
Registration
Individually register each yaml file. The first key in the file is the name it will be available under your $app variable (handled by the pimple service locator).
$this->register(new ConfigServiceProvider(__DIR__."/../config/services.yml"));
$this->register(new ConfigServiceProvider(__DIR__."/../config/routes.yml"));
// any more yaml files you like
Routes
You can get these routes using the following:
$routes = $app['config.routes']; // See the first key in the yaml file for this name
foreach ($routes as $name => $route)
{
$app->match($route['pattern'], $route['defaults']['_controller'])->bind($name)->method(isset($route['method'])?$route['method']:'GET');
}
->bind() allows you to 'name' your urls to be used within twig, for example.
->method() allows you to specify POST | GET. You'll note that I defaulted it to 'GET' with a ternary there if the route doesn't specify a method.
Ok, that's how I solved it.
This method is part of my application and called before run():
# /src/Application.php
...
protected function _initRoutes()
{
$locator = new FileLocator(__DIR__.'/config');
$loader = new YamlFileLoader($locator);
$this['routes'] = $loader->load('routes.yml');
}
Application class is my own and it extends Silex\Application.
Configuration file:
# /src/config/routes.yml
home:
pattern: /
defaults: { _controller: '\MyDemoSite\Controllers\DefaultController::indexAction' }
It works fine for me!
UPD:
I think this is the right option to add collections:
$this['routes']->addCollection($loader->load('routes.yml'));
More flexible.
You could extend the routes service (which is a RouteCollection), and load a YAML file with FileLocator and YamlFileLoader:
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Routing\Loader\YamlFileLoader;
$app->extend('routes', function($routeCollection) {
$locator = new FileLocator([__DIR__ . '/../config']);
$loader = new YamlFileLoader($locator);
$collection = $loader->load('routes.yml');
$routeCollection->addCollection($collection);
return $routeCollection;
});
You will need symfony/config and symfony/yaml dependencies though.

Symfony2: class MapClassLoader not found

I'm trying to use MapClassLoader in autoload.php but for some reason I keep getting errors saying
Class 'Symfony\Component\ClassLoader\MapClassLoader' not found in ...\autoload.php
autoload.php:
<?php
use Symfony\Component\ClassLoader\UniversalClassLoader;
use Symfony\Component\ClassLoader\MapClassLoader;
use Doctrine\Common\Annotations\AnnotationRegistry;
$loader = new UniversalClassLoader();
$loader->registerNamespaces(array(
//some values
));
$mapLoader = new MapClassLoader(array(
//some values
));
$mapLoader->register();
I double checked and MapClassLoader.php does exist in Symfony\Component\ClassLoader
Any idea why is it happening? :/
autoload.php is a file that configures autoloading for classes so autoloading isn't available in it and you need to include any files manually:
require_once __DIR__.'/../vendor/symfony/src/Symfony/ClassLoader/MapClassLoader.php';
Why is UniversalClassLoader available without require? Because symfony uses bootstrap file for system files to reduce file loading overhead.

How to use PHPExcel correctly with Symfony 2

I need to use PHPExcel with a Symfony2 project. Anyone know how to set up the project correctly to use the library? Should i put it in the vendor directory? What should be changed in the configuration files etc?
Actually, to do it right you need to follow next steps:
Edit your deps file and add dependency from the PHPExcel
[PHPExcel]
git=http://github.com/PHPOffice/PHPExcel.git
target=/phpexcel
version=origin/master
Run php bin/vendors install in order to install all missing dependencies (PHPExcel in our case)
Update prefixes section in app/autoload.php:
$loader->registerPrefixes(array(
// ...
'PHPExcel' => __DIR__.'/../vendor/phpexcel/Classes',
));
Done. Now, you can use it in your bundle's controller (code based on PHPExcel example from Tests/01simple-download-xls.php):
<?php
namespace Demo\MyBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
use PHPExcel;
use PHPExcel_IOFactory;
class DemoController extends Controller
{
public function demoAction()
{
$response = new Response();
// Create new PHPExcel object
$objPHPExcel = new PHPExcel();
// Set document properties
$objPHPExcel->getProperties()->setCreator("Me")
->setLastModifiedBy("Someone")
->setTitle("My first demo")
->setSubject("Demo Document");
// Add some data
$objPHPExcel->setActiveSheetIndex(0)
->setCellValue('A1', 'Hello')
->setCellValue('B2', 'world!')
->setCellValue('C1', 'Hello')
->setCellValue('D2', 'world!');
// Set active sheet index to the first sheet
$objPHPExcel->setActiveSheetIndex(0);
// Redirect output to a client’s web browser (Excel5)
$response->headers->set('Content-Type', 'application/vnd.ms-excel');
$response->headers->set('Content-Disposition', 'attachment;filename="demo.xls"');
$response->headers->set('Cache-Control', 'max-age=0');
$response->prepare();
$response->sendHeaders();
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
$objWriter->save('php://output');
exit();
}
}
Copy the library to your vendors directory.
Configure autoloader in your bootstrap file:
$loader->registerPrefixes(array(
// Swift, Twig etc.
'PHPExcel' => __DIR__ . '/../vendor/phpexcel/lib/PHPExcel'
));
That's all.
actually the best solution is to use https://github.com/liuggio/ExcelBundle.
I tried to use #Crozin's solution but I was still getting an error about IOFactory::createWriter.
Hope this helps,
Simone
As of Symfony 2.3, you can now do this:
...
"require": {
...
"phpoffice/phpexcel": "dev-master"
...
},
...
Then just run composer update and dependencies will resolve automatically.
Or you can do composer require phpoffice/phpexcel:dev-master if you don't want to mess with the composer.json file.
If you are using composer to manage your project, you can just change the composer.json file:
"autoload": {
"psr-4": {
"": "src/",
"": "vendor/phpoffice/phpexcel/Classes/"
},
"classmap": [
"app/AppKernel.php",
"app/AppCache.php"
]
},
Then add
use PHPExcel;
use PHPExcel_IOFactory;
to your controller file, and you can use the PHPExcel like this:
$objPHPExcel = new PHPExcel();
Hope it helps.
With composer (since Symfony2.1) it's really easy, you only have to modify the composer.json.
You don't need to register the namespace anymore!
Only two things, to notice:
refer to github tags, I only found a soltion with the package type
when changing something in the composer.json related to the class autoloading stuff, you have to remove the whole directory in the vendor dir
Here is the related link: use PHPExcel with composer and Symfony2.2

Resources