Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Bootstrap Symfony2 project

$> composer create-project symfony/framework-standard-edition fullstack-bdd-uk12 2.1.1
$> cd fullstack-bdd-uk12
$> vim composer.json
$> composer install --dev

First stage of project development - bootstraping. On this stage, we're
creating Symfony2 Standard Edition project and declaring some dependencies
that we will need to use during development:

* doctrine/data-fixtures - to use purger, that will clean database for us
* behat/behat - to describe business requirements for the project
* behat/mink-extension - to test business requirements through web UI
* behat/mink-browserkit-driver - to use Symfony2 driver in Mink
* behat/symfony2-extension - to integrate Behat with Symfony2
* phpspec/phpspec2 - to describe code-level specifications
  • Loading branch information...
commit d7271a712b896ff6b05d77ca5edff9b709a3d3e4 0 parents
@everzet authored
Showing with 2,315 additions and 0 deletions.
  1. +8 −0 .gitignore
  2. +1 −0  app/.htaccess
  3. +9 −0 app/AppCache.php
  4. +38 −0 app/AppKernel.php
  5. +13 −0 app/Resources/views/base.html.twig
  6. +638 −0 app/SymfonyRequirements.php
  7. +16 −0 app/autoload.php
  8. +55 −0 app/check.php
  9. +59 −0 app/config/config.yml
  10. +26 −0 app/config/config_dev.yml
  11. +19 −0 app/config/config_prod.yml
  12. +14 −0 app/config/config_test.yml
  13. +15 −0 app/config/parameters.yml
  14. +4 −0 app/config/routing.yml
  15. +27 −0 app/config/routing_dev.yml
  16. +43 −0 app/config/security.yml
  17. +22 −0 app/console
  18. +41 −0 app/phpunit.xml.dist
  19. +56 −0 composer.json
  20. +208 −0 composer.lock
  21. +1 −0  src/.htaccess
  22. +9 −0 src/Acme/DemoBundle/AcmeDemoBundle.php
  23. +57 −0 src/Acme/DemoBundle/Controller/DemoController.php
  24. +69 −0 src/Acme/DemoBundle/Controller/SecuredController.php
  25. +18 −0 src/Acme/DemoBundle/Controller/WelcomeController.php
  26. +22 −0 src/Acme/DemoBundle/DependencyInjection/AcmeDemoExtension.php
  27. +25 −0 src/Acme/DemoBundle/EventListener/ControllerListener.php
  28. +20 −0 src/Acme/DemoBundle/Form/ContactType.php
  29. +18 −0 src/Acme/DemoBundle/Resources/config/services.xml
  30. +294 −0 src/Acme/DemoBundle/Resources/public/css/demo.css
  31. BIN  src/Acme/DemoBundle/Resources/public/images/blue-arrow.png
  32. BIN  src/Acme/DemoBundle/Resources/public/images/field-background.gif
  33. BIN  src/Acme/DemoBundle/Resources/public/images/logo.gif
  34. BIN  src/Acme/DemoBundle/Resources/public/images/search.png
  35. BIN  src/Acme/DemoBundle/Resources/public/images/welcome-configure.gif
  36. BIN  src/Acme/DemoBundle/Resources/public/images/welcome-demo.gif
  37. BIN  src/Acme/DemoBundle/Resources/public/images/welcome-quick-tour.gif
  38. +15 −0 src/Acme/DemoBundle/Resources/views/Demo/contact.html.twig
  39. +9 −0 src/Acme/DemoBundle/Resources/views/Demo/hello.html.twig
  40. +14 −0 src/Acme/DemoBundle/Resources/views/Demo/index.html.twig
  41. +11 −0 src/Acme/DemoBundle/Resources/views/Secured/hello.html.twig
  42. +9 −0 src/Acme/DemoBundle/Resources/views/Secured/helloadmin.html.twig
  43. +6 −0 src/Acme/DemoBundle/Resources/views/Secured/layout.html.twig
  44. +29 −0 src/Acme/DemoBundle/Resources/views/Secured/login.html.twig
  45. +65 −0 src/Acme/DemoBundle/Resources/views/Welcome/index.html.twig
  46. +49 −0 src/Acme/DemoBundle/Resources/views/layout.html.twig
  47. +17 −0 src/Acme/DemoBundle/Tests/Controller/DemoControllerTest.php
  48. +80 −0 src/Acme/DemoBundle/Twig/Extension/DemoExtension.php
  49. +10 −0 web/.htaccess
  50. +24 −0 web/app.php
  51. +30 −0 web/app_dev.php
  52. BIN  web/apple-touch-icon.png
  53. +98 −0 web/config.php
  54. BIN  web/favicon.ico
  55. +4 −0 web/robots.txt
8 .gitignore
@@ -0,0 +1,8 @@
+web/bundles/
+app/bootstrap.php.cache
+app/cache/*
+app/logs/*
+build/
+vendor
+bin
+composer.phar
1  app/.htaccess
@@ -0,0 +1 @@
+deny from all
9 app/AppCache.php
@@ -0,0 +1,9 @@
+<?php
+
+require_once __DIR__.'/AppKernel.php';
+
+use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache;
+
+class AppCache extends HttpCache
+{
+}
38 app/AppKernel.php
@@ -0,0 +1,38 @@
+<?php
+
+use Symfony\Component\HttpKernel\Kernel;
+use Symfony\Component\Config\Loader\LoaderInterface;
+
+class AppKernel extends Kernel
+{
+ public function registerBundles()
+ {
+ $bundles = array(
+ new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
+ new Symfony\Bundle\SecurityBundle\SecurityBundle(),
+ new Symfony\Bundle\TwigBundle\TwigBundle(),
+ new Symfony\Bundle\MonologBundle\MonologBundle(),
+ new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(),
+ new Symfony\Bundle\AsseticBundle\AsseticBundle(),
+ new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
+ new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(),
+ new JMS\AopBundle\JMSAopBundle(),
+ new JMS\DiExtraBundle\JMSDiExtraBundle($this),
+ new JMS\SecurityExtraBundle\JMSSecurityExtraBundle(),
+ );
+
+ if (in_array($this->getEnvironment(), array('dev', 'test'))) {
+ $bundles[] = new Acme\DemoBundle\AcmeDemoBundle();
+ $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
+ $bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle();
+ $bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle();
+ }
+
+ return $bundles;
+ }
+
+ public function registerContainerConfiguration(LoaderInterface $loader)
+ {
+ $loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml');
+ }
+}
13 app/Resources/views/base.html.twig
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8" />
+ <title>{% block title %}Welcome!{% endblock %}</title>
+ {% block stylesheets %}{% endblock %}
+ <link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" />
+ </head>
+ <body>
+ {% block body %}{% endblock %}
+ {% block javascripts %}{% endblock %}
+ </body>
+</html>
638 app/SymfonyRequirements.php
@@ -0,0 +1,638 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/*
+ * Users of PHP 5.2 should be able to run the requirements checks.
+ * This is why the file and all classes must be compatible with PHP 5.2+
+ * (e.g. not using namespaces and closures).
+ *
+ * ************** CAUTION **************
+ *
+ * DO NOT EDIT THIS FILE as it will be overriden by Composer as part of
+ * the installation/update process. The original file resides in the
+ * SensioDistributionBundle.
+ *
+ * ************** CAUTION **************
+ */
+
+/**
+ * Represents a single PHP requirement, e.g. an installed extension.
+ * It can be a mandatory requirement or an optional recommendation.
+ * There is a special subclass, named PhpIniRequirement, to check a php.ini configuration.
+ *
+ * @author Tobias Schultze <http://tobion.de>
+ */
+class Requirement
+{
+ private $fulfilled;
+ private $testMessage;
+ private $helpText;
+ private $helpHtml;
+ private $optional;
+
+ /**
+ * Constructor that initializes the requirement.
+ *
+ * @param Boolean $fulfilled Whether the requirement is fulfilled
+ * @param string $testMessage The message for testing the requirement
+ * @param string $helpHtml The help text formatted in HTML for resolving the problem
+ * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
+ * @param Boolean $optional Whether this is only an optional recommendation not a mandatory requirement
+ */
+ public function __construct($fulfilled, $testMessage, $helpHtml, $helpText = null, $optional = false)
+ {
+ $this->fulfilled = (Boolean) $fulfilled;
+ $this->testMessage = (string) $testMessage;
+ $this->helpHtml = (string) $helpHtml;
+ $this->helpText = null === $helpText ? strip_tags($this->helpHtml) : (string) $helpText;
+ $this->optional = (Boolean) $optional;
+ }
+
+ /**
+ * Returns whether the requirement is fulfilled.
+ *
+ * @return Boolean true if fulfilled, otherwise false
+ */
+ public function isFulfilled()
+ {
+ return $this->fulfilled;
+ }
+
+ /**
+ * Returns the message for testing the requirement.
+ *
+ * @return string The test message
+ */
+ public function getTestMessage()
+ {
+ return $this->testMessage;
+ }
+
+ /**
+ * Returns the help text for resolving the problem
+ *
+ * @return string The help text
+ */
+ public function getHelpText()
+ {
+ return $this->helpText;
+ }
+
+ /**
+ * Returns the help text formatted in HTML.
+ *
+ * @return string The HTML help
+ */
+ public function getHelpHtml()
+ {
+ return $this->helpHtml;
+ }
+
+ /**
+ * Returns whether this is only an optional recommendation and not a mandatory requirement.
+ *
+ * @return Boolean true if optional, false if mandatory
+ */
+ public function isOptional()
+ {
+ return $this->optional;
+ }
+}
+
+/**
+ * Represents a PHP requirement in form of a php.ini configuration.
+ *
+ * @author Tobias Schultze <http://tobion.de>
+ */
+class PhpIniRequirement extends Requirement
+{
+ /**
+ * Constructor that initializes the requirement.
+ *
+ * @param string $cfgName The configuration name used for ini_get()
+ * @param Boolean|callback $evaluation Either a Boolean indicating whether the configuration should evaluate to true or false,
+ or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement
+ * @param Boolean $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false.
+ This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin.
+ Example: You require a config to be true but PHP later removes this config and defaults it to true internally.
+ * @param string|null $testMessage The message for testing the requirement (when null and $evaluation is a Boolean a default message is derived)
+ * @param string|null $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a Boolean a default help is derived)
+ * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
+ * @param Boolean $optional Whether this is only an optional recommendation not a mandatory requirement
+ */
+ public function __construct($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null, $optional = false)
+ {
+ $cfgValue = ini_get($cfgName);
+
+ if (is_callable($evaluation)) {
+ if (null === $testMessage || null === $helpHtml) {
+ throw new InvalidArgumentException('You must provide the parameters testMessage and helpHtml for a callback evaluation.');
+ }
+
+ $fulfilled = call_user_func($evaluation, $cfgValue);
+ } else {
+ if (null === $testMessage) {
+ $testMessage = sprintf('%s %s be %s in php.ini',
+ $cfgName,
+ $optional ? 'should' : 'must',
+ $evaluation ? 'enabled' : 'disabled'
+ );
+ }
+
+ if (null === $helpHtml) {
+ $helpHtml = sprintf('Set <strong>%s</strong> to <strong>%s</strong> in php.ini<a href="#phpini">*</a>.',
+ $cfgName,
+ $evaluation ? 'on' : 'off'
+ );
+ }
+
+ $fulfilled = $evaluation == $cfgValue;
+ }
+
+ parent::__construct($fulfilled || ($approveCfgAbsence && false === $cfgValue), $testMessage, $helpHtml, $helpText, $optional);
+ }
+}
+
+/**
+ * A RequirementCollection represents a set of Requirement instances.
+ *
+ * @author Tobias Schultze <http://tobion.de>
+ */
+class RequirementCollection implements IteratorAggregate
+{
+ private $requirements = array();
+
+ /**
+ * Gets the current RequirementCollection as an Iterator.
+ *
+ * @return Traversable A Traversable interface
+ */
+ public function getIterator()
+ {
+ return new ArrayIterator($this->requirements);
+ }
+
+ /**
+ * Adds a Requirement.
+ *
+ * @param Requirement $requirement A Requirement instance
+ */
+ public function add(Requirement $requirement)
+ {
+ $this->requirements[] = $requirement;
+ }
+
+ /**
+ * Adds a mandatory requirement.
+ *
+ * @param Boolean $fulfilled Whether the requirement is fulfilled
+ * @param string $testMessage The message for testing the requirement
+ * @param string $helpHtml The help text formatted in HTML for resolving the problem
+ * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
+ */
+ public function addRequirement($fulfilled, $testMessage, $helpHtml, $helpText = null)
+ {
+ $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, false));
+ }
+
+ /**
+ * Adds an optional recommendation.
+ *
+ * @param Boolean $fulfilled Whether the recommendation is fulfilled
+ * @param string $testMessage The message for testing the recommendation
+ * @param string $helpHtml The help text formatted in HTML for resolving the problem
+ * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
+ */
+ public function addRecommendation($fulfilled, $testMessage, $helpHtml, $helpText = null)
+ {
+ $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, true));
+ }
+
+ /**
+ * Adds a mandatory requirement in form of a php.ini configuration.
+ *
+ * @param string $cfgName The configuration name used for ini_get()
+ * @param Boolean|callback $evaluation Either a Boolean indicating whether the configuration should evaluate to true or false,
+ or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement
+ * @param Boolean $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false.
+ This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin.
+ Example: You require a config to be true but PHP later removes this config and defaults it to true internally.
+ * @param string $testMessage The message for testing the requirement (when null and $evaluation is a Boolean a default message is derived)
+ * @param string $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a Boolean a default help is derived)
+ * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
+ */
+ public function addPhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null)
+ {
+ $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, false));
+ }
+
+ /**
+ * Adds an optional recommendation in form of a php.ini configuration.
+ *
+ * @param string $cfgName The configuration name used for ini_get()
+ * @param Boolean|callback $evaluation Either a Boolean indicating whether the configuration should evaluate to true or false,
+ or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement
+ * @param Boolean $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false.
+ This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin.
+ Example: You require a config to be true but PHP later removes this config and defaults it to true internally.
+ * @param string $testMessage The message for testing the requirement (when null and $evaluation is a Boolean a default message is derived)
+ * @param string $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a Boolean a default help is derived)
+ * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
+ */
+ public function addPhpIniRecommendation($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null)
+ {
+ $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, true));
+ }
+
+ /**
+ * Adds a requirement collection to the current set of requirements.
+ *
+ * @param RequirementCollection $collection A RequirementCollection instance
+ */
+ public function addCollection(RequirementCollection $collection)
+ {
+ $this->requirements = array_merge($this->requirements, $collection->all());
+ }
+
+ /**
+ * Returns both requirements and recommendations.
+ *
+ * @return array Array of Requirement instances
+ */
+ public function all()
+ {
+ return $this->requirements;
+ }
+
+ /**
+ * Returns all mandatory requirements.
+ *
+ * @return array Array of Requirement instances
+ */
+ public function getRequirements()
+ {
+ $array = array();
+ foreach ($this->requirements as $req) {
+ if (!$req->isOptional()) {
+ $array[] = $req;
+ }
+ }
+
+ return $array;
+ }
+
+ /**
+ * Returns the mandatory requirements that were not met.
+ *
+ * @return array Array of Requirement instances
+ */
+ public function getFailedRequirements()
+ {
+ $array = array();
+ foreach ($this->requirements as $req) {
+ if (!$req->isFulfilled() && !$req->isOptional()) {
+ $array[] = $req;
+ }
+ }
+
+ return $array;
+ }
+
+ /**
+ * Returns all optional recommmendations.
+ *
+ * @return array Array of Requirement instances
+ */
+ public function getRecommendations()
+ {
+ $array = array();
+ foreach ($this->requirements as $req) {
+ if ($req->isOptional()) {
+ $array[] = $req;
+ }
+ }
+
+ return $array;
+ }
+
+ /**
+ * Returns the recommendations that were not met.
+ *
+ * @return array Array of Requirement instances
+ */
+ public function getFailedRecommendations()
+ {
+ $array = array();
+ foreach ($this->requirements as $req) {
+ if (!$req->isFulfilled() && $req->isOptional()) {
+ $array[] = $req;
+ }
+ }
+
+ return $array;
+ }
+
+ /**
+ * Returns whether a php.ini configuration is not correct.
+ *
+ * @return Boolean php.ini configuration problem?
+ */
+ public function hasPhpIniConfigIssue()
+ {
+ foreach ($this->requirements as $req) {
+ if (!$req->isFulfilled() && $req instanceof PhpIniRequirement) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the PHP configuration file (php.ini) path.
+ *
+ * @return string|false php.ini file path
+ */
+ public function getPhpIniConfigPath()
+ {
+ return get_cfg_var('cfg_file_path');
+ }
+}
+
+/**
+ * This class specifies all requirements and optional recommendations that
+ * are necessary to run the Symfony Standard Edition.
+ *
+ * @author Tobias Schultze <http://tobion.de>
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class SymfonyRequirements extends RequirementCollection
+{
+ const REQUIRED_PHP_VERSION = '5.3.3';
+
+ /**
+ * Constructor that initializes the requirements.
+ */
+ public function __construct()
+ {
+ /* mandatory requirements follow */
+
+ $installedPhpVersion = phpversion();
+
+ $this->addRequirement(
+ version_compare($installedPhpVersion, self::REQUIRED_PHP_VERSION, '>='),
+ sprintf('PHP version must be at least %s (%s installed)', self::REQUIRED_PHP_VERSION, $installedPhpVersion),
+ sprintf('You are running PHP version "<strong>%s</strong>", but Symfony needs at least PHP "<strong>%s</strong>" to run.
+ Before using Symfony, upgrade your PHP installation, preferably to the latest version.',
+ $installedPhpVersion, self::REQUIRED_PHP_VERSION),
+ sprintf('Install PHP %s or newer (installed version is %s)', self::REQUIRED_PHP_VERSION, $installedPhpVersion)
+ );
+
+ $this->addRequirement(
+ version_compare($installedPhpVersion, '5.3.16', '!='),
+ 'PHP version must not be 5.3.16 as Symfony won\'t work properly with it',
+ 'Install PHP 5.3.17 or newer (or downgrade to an earlier PHP version)'
+ );
+
+ $this->addRequirement(
+ is_dir(__DIR__.'/../vendor/composer'),
+ 'Vendor libraries must be installed',
+ 'Vendor libraries are missing. Install composer following instructions from <a href="http://getcomposer.org/">http://getcomposer.org/</a>. ' .
+ 'Then run "<strong>php composer.phar install</strong>" to install them.'
+ );
+
+ $baseDir = basename(__DIR__);
+
+ $this->addRequirement(
+ is_writable(__DIR__.'/cache'),
+ "$baseDir/cache/ directory must be writable",
+ "Change the permissions of the \"<strong>$baseDir/cache/</strong>\" directory so that the web server can write into it."
+ );
+
+ $this->addRequirement(
+ is_writable(__DIR__.'/logs'),
+ "$baseDir/logs/ directory must be writable",
+ "Change the permissions of the \"<strong>$baseDir/logs/</strong>\" directory so that the web server can write into it."
+ );
+
+ $this->addPhpIniRequirement(
+ 'date.timezone', true, false,
+ 'date.timezone setting must be set',
+ 'Set the "<strong>date.timezone</strong>" setting in php.ini<a href="#phpini">*</a> (like Europe/Paris).'
+ );
+
+ if (version_compare($installedPhpVersion, self::REQUIRED_PHP_VERSION, '>=')) {
+ $this->addRequirement(
+ (in_array(date_default_timezone_get(), DateTimeZone::listIdentifiers())),
+ sprintf('Configured default timezone "%s" must be supported by your installation of PHP', date_default_timezone_get()),
+ 'Your default timezone is not supported by PHP. Check for typos in your <strong>php.ini</strong> file and have a look at the list of deprecated timezones at <a href="http://php.net/manual/en/timezones.others.php">http://php.net/manual/en/timezones.others.php</a>.'
+ );
+ }
+
+ $this->addRequirement(
+ function_exists('json_encode'),
+ 'json_encode() must be available',
+ 'Install and enable the <strong>JSON</strong> extension.'
+ );
+
+ $this->addRequirement(
+ function_exists('session_start'),
+ 'session_start() must be available',
+ 'Install and enable the <strong>session</strong> extension.'
+ );
+
+ $this->addRequirement(
+ function_exists('ctype_alpha'),
+ 'ctype_alpha() must be available',
+ 'Install and enable the <strong>ctype</strong> extension.'
+ );
+
+ $this->addRequirement(
+ function_exists('token_get_all'),
+ 'token_get_all() must be available',
+ 'Install and enable the <strong>Tokenizer</strong> extension.'
+ );
+
+ $this->addRequirement(
+ function_exists('simplexml_import_dom'),
+ 'simplexml_import_dom() must be available',
+ 'Install and enable the <strong>SimpleXML</strong> extension.'
+ );
+
+ if (function_exists('apc_store') && ini_get('apc.enabled')) {
+ $this->addRequirement(
+ version_compare(phpversion('apc'), '3.0.17', '>='),
+ 'APC version must be at least 3.0.17',
+ 'Upgrade your <strong>APC</strong> extension (3.0.17+).'
+ );
+ }
+
+ $this->addPhpIniRequirement('detect_unicode', false);
+
+ if (extension_loaded('suhosin')) {
+ $this->addPhpIniRequirement(
+ 'suhosin.executor.include.whitelist',
+ create_function('$cfgValue', 'return false !== stripos($cfgValue, "phar");'),
+ false,
+ 'suhosin.executor.include.whitelist must be configured correctly in php.ini',
+ 'Add "<strong>phar</strong>" to <strong>suhosin.executor.include.whitelist</strong> in php.ini<a href="#phpini">*</a>.'
+ );
+ }
+
+ if (extension_loaded('xdebug')) {
+ $this->addPhpIniRequirement(
+ 'xdebug.show_exception_trace', false, true
+ );
+
+ $this->addPhpIniRequirement(
+ 'xdebug.scream', false, true
+ );
+ }
+
+ $pcreVersion = defined('PCRE_VERSION') ? (float) PCRE_VERSION : null;
+
+ $this->addRequirement(
+ null !== $pcreVersion && $pcreVersion > 8.0,
+ sprintf('PCRE extension must be available and at least 8.0 (%s installed)', $pcreVersion ? $pcreVersion : 'not'),
+ 'Upgrade your <strong>PCRE</strong> extension (8.0+).'
+ );
+
+ /* optional recommendations follow */
+
+ $this->addRecommendation(
+ file_get_contents(__FILE__) === file_get_contents(__DIR__.'/../vendor/sensio/distribution-bundle/Sensio/Bundle/DistributionBundle/Resources/skeleton/app/SymfonyRequirements.php'),
+ 'Requirements file should be up-to-date',
+ 'Your requirements file is outdated. Run composer install and re-check your configuration.'
+ );
+
+ $this->addRecommendation(
+ version_compare($installedPhpVersion, '5.3.4', '>='),
+ 'You should use at least PHP 5.3.4 due to PHP bug #52083 in earlier versions',
+ 'Your project might malfunction randomly due to PHP bug #52083 ("Notice: Trying to get property of non-object"). Install PHP 5.3.4 or newer.'
+ );
+
+ $this->addRecommendation(
+ version_compare($installedPhpVersion, '5.3.8', '>='),
+ 'When using annotations you should have at least PHP 5.3.8 due to PHP bug #55156',
+ 'Install PHP 5.3.8 or newer if your project uses annotations.'
+ );
+
+ $this->addRecommendation(
+ version_compare($installedPhpVersion, '5.4.0', '!='),
+ 'You should not use PHP 5.4.0 due to the PHP bug #61453',
+ 'Your project might not work properly due to the PHP bug #61453 ("Cannot dump definitions which have method calls"). Install PHP 5.4.1 or newer.'
+ );
+
+ $this->addRecommendation(
+ class_exists('DomDocument'),
+ 'PHP-XML module should be installed',
+ 'Install and enable the <strong>PHP-XML</strong> module.'
+ );
+
+ $this->addRecommendation(
+ function_exists('mb_strlen'),
+ 'mb_strlen() should be available',
+ 'Install and enable the <strong>mbstring</strong> extension.'
+ );
+
+ $this->addRecommendation(
+ function_exists('iconv'),
+ 'iconv() should be available',
+ 'Install and enable the <strong>iconv</strong> extension.'
+ );
+
+ $this->addRecommendation(
+ function_exists('utf8_decode'),
+ 'utf8_decode() should be available',
+ 'Install and enable the <strong>XML</strong> extension.'
+ );
+
+ if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
+ $this->addRecommendation(
+ function_exists('posix_isatty'),
+ 'posix_isatty() should be available',
+ 'Install and enable the <strong>php_posix</strong> extension (used to colorize the CLI output).'
+ );
+ }
+
+ $this->addRecommendation(
+ class_exists('Locale'),
+ 'intl extension should be available',
+ 'Install and enable the <strong>intl</strong> extension (used for validators).'
+ );
+
+ if (class_exists('Collator')) {
+ $this->addRecommendation(
+ null !== new Collator('fr_FR'),
+ 'intl extension should be correctly configured',
+ 'The intl extension does not behave properly. This problem is typical on PHP 5.3.X x64 WIN builds.'
+ );
+ }
+
+ if (class_exists('Locale')) {
+ if (defined('INTL_ICU_VERSION')) {
+ $version = INTL_ICU_VERSION;
+ } else {
+ $reflector = new ReflectionExtension('intl');
+
+ ob_start();
+ $reflector->info();
+ $output = strip_tags(ob_get_clean());
+
+ preg_match('/^ICU version +(?:=> )?(.*)$/m', $output, $matches);
+ $version = $matches[1];
+ }
+
+ $this->addRecommendation(
+ version_compare($version, '4.0', '>='),
+ 'intl ICU version should be at least 4+',
+ 'Upgrade your <strong>intl</strong> extension with a newer ICU version (4+).'
+ );
+ }
+
+ $accelerator =
+ (function_exists('apc_store') && ini_get('apc.enabled'))
+ ||
+ function_exists('eaccelerator_put') && ini_get('eaccelerator.enable')
+ ||
+ function_exists('xcache_set')
+ ;
+
+ $this->addRecommendation(
+ $accelerator,
+ 'a PHP accelerator should be installed',
+ 'Install and enable a <strong>PHP accelerator</strong> like APC (highly recommended).'
+ );
+
+ $this->addPhpIniRecommendation('short_open_tag', false);
+
+ $this->addPhpIniRecommendation('magic_quotes_gpc', false, true);
+
+ $this->addPhpIniRecommendation('register_globals', false, true);
+
+ $this->addPhpIniRecommendation('session.auto_start', false);
+
+ $this->addRecommendation(
+ class_exists('PDO'),
+ 'PDO should be installed',
+ 'Install <strong>PDO</strong> (mandatory for Doctrine).'
+ );
+
+ if (class_exists('PDO')) {
+ $drivers = PDO::getAvailableDrivers();
+ $this->addRecommendation(
+ count($drivers),
+ sprintf('PDO should have some drivers installed (currently available: %s)', count($drivers) ? implode(', ', $drivers) : 'none'),
+ 'Install <strong>PDO drivers</strong> (mandatory for Doctrine).'
+ );
+ }
+ }
+}
16 app/autoload.php
@@ -0,0 +1,16 @@
+<?php
+
+use Doctrine\Common\Annotations\AnnotationRegistry;
+
+$loader = require __DIR__.'/../vendor/autoload.php';
+
+// intl
+if (!function_exists('intl_get_error_code')) {
+ require_once __DIR__.'/../vendor/symfony/symfony/src/Symfony/Component/Locale/Resources/stubs/functions.php';
+
+ $loader->add('', __DIR__.'/../vendor/symfony/symfony/src/Symfony/Component/Locale/Resources/stubs');
+}
+
+AnnotationRegistry::registerLoader(array($loader, 'loadClass'));
+
+return $loader;
55 app/check.php
@@ -0,0 +1,55 @@
+<?php
+
+require_once dirname(__FILE__).'/SymfonyRequirements.php';
+
+$symfonyRequirements = new SymfonyRequirements();
+
+$iniPath = $symfonyRequirements->getPhpIniConfigPath();
+
+echo "********************************\n";
+echo "* *\n";
+echo "* Symfony requirements check *\n";
+echo "* *\n";
+echo "********************************\n\n";
+
+echo $iniPath ? sprintf("* Configuration file used by PHP: %s\n\n", $iniPath) : "* WARNING: No configuration file (php.ini) used by PHP!\n\n";
+
+echo "** ATTENTION **\n";
+echo "* The PHP CLI can use a different php.ini file\n";
+echo "* than the one used with your web server.\n";
+if ('\\' == DIRECTORY_SEPARATOR) {
+ echo "* (especially on the Windows platform)\n";
+}
+echo "* To be on the safe side, please also launch the requirements check\n";
+echo "* from your web server using the web/config.php script.\n";
+
+echo_title('Mandatory requirements');
+
+foreach ($symfonyRequirements->getRequirements() as $req) {
+ echo_requirement($req);
+}
+
+echo_title('Optional recommendations');
+
+foreach ($symfonyRequirements->getRecommendations() as $req) {
+ echo_requirement($req);
+}
+
+/**
+ * Prints a Requirement instance
+ */
+function echo_requirement(Requirement $requirement)
+{
+ $result = $requirement->isFulfilled() ? 'OK' : ($requirement->isOptional() ? 'WARNING' : 'ERROR');
+ echo ' ' . str_pad($result, 9);
+ echo $requirement->getTestMessage() . "\n";
+
+ if (!$requirement->isFulfilled()) {
+ echo sprintf(" %s\n\n", $requirement->getHelpText());
+ }
+}
+
+function echo_title($title)
+{
+ echo "\n** $title **\n\n";
+}
59 app/config/config.yml
@@ -0,0 +1,59 @@
+imports:
+ - { resource: parameters.yml }
+ - { resource: security.yml }
+
+framework:
+ #esi: ~
+ #translator: { fallback: %locale% }
+ secret: %secret%
+ router:
+ resource: "%kernel.root_dir%/config/routing.yml"
+ strict_requirements: %kernel.debug%
+ form: true
+ csrf_protection: true
+ validation: { enable_annotations: true }
+ templating: { engines: ['twig'] } #assets_version: SomeVersionScheme
+ default_locale: %locale%
+ trust_proxy_headers: false # Whether or not the Request object should trust proxy headers (X_FORWARDED_FOR/HTTP_CLIENT_IP)
+ session: ~
+
+# Twig Configuration
+twig:
+ debug: %kernel.debug%
+ strict_variables: %kernel.debug%
+
+# Assetic Configuration
+assetic:
+ debug: %kernel.debug%
+ use_controller: false
+ bundles: [ ]
+ #java: /usr/bin/java
+ filters:
+ cssrewrite: ~
+ #closure:
+ # jar: %kernel.root_dir%/Resources/java/compiler.jar
+ #yui_css:
+ # jar: %kernel.root_dir%/Resources/java/yuicompressor-2.4.7.jar
+
+# Doctrine Configuration
+doctrine:
+ dbal:
+ driver: %database_driver%
+ host: %database_host%
+ port: %database_port%
+ dbname: %database_name%
+ user: %database_user%
+ password: %database_password%
+ charset: UTF8
+
+ orm:
+ auto_generate_proxy_classes: %kernel.debug%
+ auto_mapping: true
+
+# Swiftmailer Configuration
+swiftmailer:
+ transport: %mailer_transport%
+ host: %mailer_host%
+ username: %mailer_user%
+ password: %mailer_password%
+ spool: { type: memory }
26 app/config/config_dev.yml
@@ -0,0 +1,26 @@
+imports:
+ - { resource: config.yml }
+
+framework:
+ router: { resource: "%kernel.root_dir%/config/routing_dev.yml" }
+ profiler: { only_exceptions: false }
+
+web_profiler:
+ toolbar: true
+ intercept_redirects: false
+
+monolog:
+ handlers:
+ main:
+ type: stream
+ path: %kernel.logs_dir%/%kernel.environment%.log
+ level: debug
+ firephp:
+ type: firephp
+ level: info
+
+assetic:
+ use_controller: true
+
+#swiftmailer:
+# delivery_address: me@example.com
19 app/config/config_prod.yml
@@ -0,0 +1,19 @@
+imports:
+ - { resource: config.yml }
+
+#doctrine:
+# orm:
+# metadata_cache_driver: apc
+# result_cache_driver: apc
+# query_cache_driver: apc
+
+monolog:
+ handlers:
+ main:
+ type: fingers_crossed
+ action_level: error
+ handler: nested
+ nested:
+ type: stream
+ path: %kernel.logs_dir%/%kernel.environment%.log
+ level: debug
14 app/config/config_test.yml
@@ -0,0 +1,14 @@
+imports:
+ - { resource: config_dev.yml }
+
+framework:
+ test: ~
+ session:
+ storage_id: session.storage.mock_file
+
+web_profiler:
+ toolbar: false
+ intercept_redirects: false
+
+swiftmailer:
+ disable_delivery: true
15 app/config/parameters.yml
@@ -0,0 +1,15 @@
+parameters:
+ database_driver: pdo_mysql
+ database_host: localhost
+ database_port: ~
+ database_name: symfony
+ database_user: root
+ database_password: ~
+
+ mailer_transport: smtp
+ mailer_host: localhost
+ mailer_user: ~
+ mailer_password: ~
+
+ locale: en
+ secret: ThisTokenIsNotSoSecretChangeIt
4 app/config/routing.yml
@@ -0,0 +1,4 @@
+# Internal routing configuration to handle ESI
+#_internal:
+# resource: "@FrameworkBundle/Resources/config/routing/internal.xml"
+# prefix: /_internal
27 app/config/routing_dev.yml
@@ -0,0 +1,27 @@
+_welcome:
+ pattern: /
+ defaults: { _controller: AcmeDemoBundle:Welcome:index }
+
+_demo_secured:
+ resource: "@AcmeDemoBundle/Controller/SecuredController.php"
+ type: annotation
+
+_demo:
+ resource: "@AcmeDemoBundle/Controller/DemoController.php"
+ type: annotation
+ prefix: /demo
+
+_wdt:
+ resource: "@WebProfilerBundle/Resources/config/routing/wdt.xml"
+ prefix: /_wdt
+
+_profiler:
+ resource: "@WebProfilerBundle/Resources/config/routing/profiler.xml"
+ prefix: /_profiler
+
+_configurator:
+ resource: "@SensioDistributionBundle/Resources/config/routing/webconfigurator.xml"
+ prefix: /_configurator
+
+_main:
+ resource: routing.yml
43 app/config/security.yml
@@ -0,0 +1,43 @@
+jms_security_extra:
+ secure_all_services: false
+ expressions: true
+
+security:
+ encoders:
+ Symfony\Component\Security\Core\User\User: plaintext
+
+ role_hierarchy:
+ ROLE_ADMIN: ROLE_USER
+ ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
+
+ providers:
+ in_memory:
+ memory:
+ users:
+ user: { password: userpass, roles: [ 'ROLE_USER' ] }
+ admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] }
+
+ firewalls:
+ dev:
+ pattern: ^/(_(profiler|wdt)|css|images|js)/
+ security: false
+
+ login:
+ pattern: ^/demo/secured/login$
+ security: false
+
+ secured_area:
+ pattern: ^/demo/secured/
+ form_login:
+ check_path: /demo/secured/login_check
+ login_path: /demo/secured/login
+ logout:
+ path: /demo/secured/logout
+ target: /demo/
+ #anonymous: ~
+ #http_basic:
+ # realm: "Secured Demo Area"
+
+ access_control:
+ #- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
+ #- { path: ^/_internal/secure, roles: IS_AUTHENTICATED_ANONYMOUSLY, ip: 127.0.0.1 }
22 app/console
@@ -0,0 +1,22 @@
+#!/usr/bin/env php
+<?php
+
+// if you don't want to setup permissions the proper way, just uncomment the following PHP line
+// read http://symfony.com/doc/current/book/installation.html#configuration-and-setup for more information
+//umask(0000);
+
+set_time_limit(0);
+
+require_once __DIR__.'/bootstrap.php.cache';
+require_once __DIR__.'/AppKernel.php';
+
+use Symfony\Bundle\FrameworkBundle\Console\Application;
+use Symfony\Component\Console\Input\ArgvInput;
+
+$input = new ArgvInput();
+$env = $input->getParameterOption(array('--env', '-e'), getenv('SYMFONY_ENV') ?: 'dev');
+$debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(array('--no-debug', '')) && $env !== 'prod';
+
+$kernel = new AppKernel($env, $debug);
+$application = new Application($kernel);
+$application->run($input);
41 app/phpunit.xml.dist
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- http://www.phpunit.de/manual/current/en/appendixes.configuration.html -->
+<phpunit
+ backupGlobals = "false"
+ backupStaticAttributes = "false"
+ colors = "true"
+ convertErrorsToExceptions = "true"
+ convertNoticesToExceptions = "true"
+ convertWarningsToExceptions = "true"
+ processIsolation = "false"
+ stopOnFailure = "false"
+ syntaxCheck = "false"
+ bootstrap = "bootstrap.php.cache" >
+
+ <testsuites>
+ <testsuite name="Project Test Suite">
+ <directory>../src/*/*Bundle/Tests</directory>
+ <directory>../src/*/Bundle/*Bundle/Tests</directory>
+ </testsuite>
+ </testsuites>
+
+ <!--
+ <php>
+ <server name="KERNEL_DIR" value="/path/to/your/app/" />
+ </php>
+ -->
+
+ <filter>
+ <whitelist>
+ <directory>../src</directory>
+ <exclude>
+ <directory>../src/*/*Bundle/Resources</directory>
+ <directory>../src/*/*Bundle/Tests</directory>
+ <directory>../src/*/Bundle/*Bundle/Resources</directory>
+ <directory>../src/*/Bundle/*Bundle/Tests</directory>
+ </exclude>
+ </whitelist>
+ </filter>
+
+</phpunit>
56 composer.json
@@ -0,0 +1,56 @@
+{
+ "name": "symfony/framework-standard-edition",
+ "description": "The \"Symfony Standard Edition\" distribution",
+ "autoload": {
+ "psr-0": { "": "src/" }
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "symfony/symfony": "2.1.1",
+ "doctrine/orm": "2.2.3",
+ "doctrine/dbal": "2.2.2",
+ "doctrine/common": "2.2.3",
+ "twig/twig": "1.9.2",
+ "swiftmailer/swiftmailer": "4.2.1",
+ "doctrine/doctrine-bundle": "1.0.*",
+ "twig/extensions": "1.0.*",
+ "symfony/assetic-bundle": "2.1.*",
+ "symfony/swiftmailer-bundle": "2.1.*",
+ "symfony/monolog-bundle": "2.1.*",
+ "sensio/distribution-bundle": "2.1.*",
+ "sensio/framework-extra-bundle": "2.1.*",
+ "sensio/generator-bundle": "2.1.*",
+ "jms/security-extra-bundle": "1.2.*",
+ "jms/di-extra-bundle": "1.1.*",
+ "doctrine/data-fixtures": "*"
+ },
+ "require-dev": {
+ "behat/behat": ">=2.4.4",
+ "behat/mink-extension": "*",
+ "behat/mink-browserkit-driver": "*",
+ "behat/symfony2-extension": "*",
+ "phpspec/phpspec2": "*"
+ },
+ "scripts": {
+ "post-install-cmd": [
+ "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap",
+ "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache",
+ "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets",
+ "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile"
+ ],
+ "post-update-cmd": [
+ "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap",
+ "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache",
+ "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets",
+ "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile"
+ ]
+ },
+ "config": {
+ "bin-dir": "bin"
+ },
+ "minimum-stability": "dev",
+ "extra": {
+ "symfony-app-dir": "app",
+ "symfony-web-dir": "web"
+ }
+}
208 composer.lock
@@ -0,0 +1,208 @@
+{
+ "hash": "75295262d592cadb1c168bb888232708",
+ "packages": [
+ {
+ "package": "doctrine/common",
+ "version": "2.2.3"
+ },
+ {
+ "package": "doctrine/data-fixtures",
+ "version": "dev-master",
+ "source-reference": "379a5f19e23849cf082613e2e91ed02bd2ee4fb1",
+ "commit-date": "1347551292"
+ },
+ {
+ "package": "doctrine/dbal",
+ "version": "2.2.2"
+ },
+ {
+ "package": "doctrine/doctrine-bundle",
+ "version": "v1.0.0"
+ },
+ {
+ "package": "doctrine/orm",
+ "version": "2.2.3"
+ },
+ {
+ "package": "jms/aop-bundle",
+ "version": "1.0.0"
+ },
+ {
+ "package": "jms/cg",
+ "version": "1.0.0"
+ },
+ {
+ "package": "jms/di-extra-bundle",
+ "version": "1.1.x-dev",
+ "source-reference": "d3360b2eb98a1381b9a3fd86ea94a35a347afebb",
+ "commit-date": "1347584907"
+ },
+ {
+ "package": "jms/metadata",
+ "version": "1.1.1"
+ },
+ {
+ "package": "jms/security-extra-bundle",
+ "version": "1.2.x-dev",
+ "source-reference": "9ab6aceda50fc7a2b07d741ba4b3f0695508afcb",
+ "commit-date": "1346947943"
+ },
+ {
+ "package": "kriswallsmith/assetic",
+ "version": "dev-master",
+ "alias-pretty-version": "1.1.x-dev",
+ "alias-version": "1.1.9999999.9999999-dev"
+ },
+ {
+ "package": "kriswallsmith/assetic",
+ "version": "dev-master",
+ "source-reference": "22b57658cbcedc24bb9ad72f9cc05b7d83c228c9",
+ "commit-date": "1347558609"
+ },
+ {
+ "package": "monolog/monolog",
+ "version": "dev-master",
+ "alias-pretty-version": "1.3.x-dev",
+ "alias-version": "1.3.9999999.9999999-dev"
+ },
+ {
+ "package": "monolog/monolog",
+ "version": "dev-master",
+ "source-reference": "0f3dc95c4a0ed7d17bec237d07af3da6c0c1071a",
+ "commit-date": "1347363321"
+ },
+ {
+ "package": "sensio/distribution-bundle",
+ "version": "2.1.x-dev",
+ "source-reference": "2eee3cb4cd761c851f0d766649fb9ff6f4c97002",
+ "commit-date": "1347340208"
+ },
+ {
+ "package": "sensio/framework-extra-bundle",
+ "version": "2.1.x-dev",
+ "source-reference": "v2.1.0",
+ "commit-date": "1346234539"
+ },
+ {
+ "package": "sensio/generator-bundle",
+ "version": "dev-master",
+ "alias-pretty-version": "2.1.x-dev",
+ "alias-version": "2.1.9999999.9999999-dev"
+ },
+ {
+ "package": "sensio/generator-bundle",
+ "version": "dev-master",
+ "source-reference": "v2.1.0",
+ "commit-date": "1346138171"
+ },
+ {
+ "package": "swiftmailer/swiftmailer",
+ "version": "v4.2.1"
+ },
+ {
+ "package": "symfony/assetic-bundle",
+ "version": "dev-master",
+ "alias-pretty-version": "2.1.x-dev",
+ "alias-version": "2.1.9999999.9999999-dev"
+ },
+ {
+ "package": "symfony/assetic-bundle",
+ "version": "dev-master",
+ "source-reference": "ca999f55c18b23daf1dc148efe4c42122eb8fd3b",
+ "commit-date": "1347524781"
+ },
+ {
+ "package": "symfony/monolog-bundle",
+ "version": "dev-master",
+ "alias-pretty-version": "2.1.x-dev",
+ "alias-version": "2.1.9999999.9999999-dev"
+ },
+ {
+ "package": "symfony/monolog-bundle",
+ "version": "dev-master",
+ "source-reference": "b7318480e6f8bf5579d6b3cd856850302e7ba8d8",
+ "commit-date": "1347283885"
+ },
+ {
+ "package": "symfony/swiftmailer-bundle",
+ "version": "dev-master",
+ "alias-pretty-version": "2.1.x-dev",
+ "alias-version": "2.1.9999999.9999999-dev"
+ },
+ {
+ "package": "symfony/swiftmailer-bundle",
+ "version": "dev-master",
+ "source-reference": "d2eae9385c029cbac031a90e6d2abc74b889a562",
+ "commit-date": "1346243146"
+ },
+ {
+ "package": "symfony/symfony",
+ "version": "v2.1.1"
+ },
+ {
+ "package": "twig/extensions",
+ "version": "dev-master",
+ "alias-pretty-version": "1.0.x-dev",
+ "alias-version": "1.0.9999999.9999999-dev"
+ },
+ {
+ "package": "twig/extensions",
+ "version": "dev-master",
+ "source-reference": "f904575642b1213db69b4a98f08397e722ba1cae",
+ "commit-date": "1346770278"
+ },
+ {
+ "package": "twig/twig",
+ "version": "v1.9.2"
+ }
+ ],
+ "packages-dev": [
+ {
+ "package": "behat/behat",
+ "version": "v2.4.4"
+ },
+ {
+ "package": "behat/gherkin",
+ "version": "v2.2.4"
+ },
+ {
+ "package": "behat/mink",
+ "version": "v1.4.0"
+ },
+ {
+ "package": "behat/mink-browserkit-driver",
+ "version": "dev-master",
+ "source-reference": "97fa7d67ab5afb13d74515c15ef5c0cab12c0bc0",
+ "commit-date": "1341477260"
+ },
+ {
+ "package": "behat/mink-extension",
+ "version": "dev-master",
+ "source-reference": "43b36e2d6682a4b257cb2b0f994a0b45faf033ee",
+ "commit-date": "1347458052"
+ },
+ {
+ "package": "behat/symfony2-extension",
+ "version": "dev-master",
+ "source-reference": "3955aea7932b69aa35893c594ae76da9ce7e1e42",
+ "commit-date": "1343142072"
+ },
+ {
+ "package": "mockery/mockery",
+ "version": "0.7.2"
+ },
+ {
+ "package": "phpspec/phpspec2",
+ "version": "dev-master",
+ "source-reference": "bf0920392d6e3c8a1cb9ff1ef757147937cd8d53",
+ "commit-date": "1347602643"
+ }
+ ],
+ "aliases": [
+
+ ],
+ "minimum-stability": "dev",
+ "stability-flags": [
+
+ ]
+}
1  src/.htaccess
@@ -0,0 +1 @@
+deny from all
9 src/Acme/DemoBundle/AcmeDemoBundle.php
@@ -0,0 +1,9 @@
+<?php
+
+namespace Acme\DemoBundle;
+
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+
+class AcmeDemoBundle extends Bundle
+{
+}
57 src/Acme/DemoBundle/Controller/DemoController.php
@@ -0,0 +1,57 @@
+<?php
+
+namespace Acme\DemoBundle\Controller;
+
+use Symfony\Bundle\FrameworkBundle\Controller\Controller;
+use Symfony\Component\HttpFoundation\RedirectResponse;
+use Acme\DemoBundle\Form\ContactType;
+
+// these import the "@Route" and "@Template" annotations
+use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
+use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
+
+class DemoController extends Controller
+{
+ /**
+ * @Route("/", name="_demo")
+ * @Template()
+ */
+ public function indexAction()
+ {
+ return array();
+ }
+
+ /**
+ * @Route("/hello/{name}", name="_demo_hello")
+ * @Template()
+ */
+ public function helloAction($name)
+ {
+ return array('name' => $name);
+ }
+
+ /**
+ * @Route("/contact", name="_demo_contact")
+ * @Template()
+ */
+ public function contactAction()
+ {
+ $form = $this->get('form.factory')->create(new ContactType());
+
+ $request = $this->get('request');
+ if ('POST' == $request->getMethod()) {
+ $form->bindRequest($request);
+ if ($form->isValid()) {
+ $mailer = $this->get('mailer');
+ // .. setup a message and send it
+ // http://symfony.com/doc/current/cookbook/email.html
+
+ $this->get('session')->setFlash('notice', 'Message sent!');
+
+ return new RedirectResponse($this->generateUrl('_demo'));
+ }
+ }
+
+ return array('form' => $form->createView());
+ }
+}
69 src/Acme/DemoBundle/Controller/SecuredController.php
@@ -0,0 +1,69 @@
+<?php
+
+namespace Acme\DemoBundle\Controller;
+
+use Symfony\Bundle\FrameworkBundle\Controller\Controller;
+use Symfony\Component\Security\Core\SecurityContext;
+use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
+use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
+use JMS\SecurityExtraBundle\Annotation\Secure;
+
+/**
+ * @Route("/demo/secured")
+ */
+class SecuredController extends Controller
+{
+ /**
+ * @Route("/login", name="_demo_login")
+ * @Template()
+ */
+ public function loginAction()
+ {
+ if ($this->get('request')->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) {
+ $error = $this->get('request')->attributes->get(SecurityContext::AUTHENTICATION_ERROR);
+ } else {
+ $error = $this->get('request')->getSession()->get(SecurityContext::AUTHENTICATION_ERROR);
+ }
+
+ return array(
+ 'last_username' => $this->get('request')->getSession()->get(SecurityContext::LAST_USERNAME),
+ 'error' => $error,
+ );
+ }
+
+ /**
+ * @Route("/login_check", name="_security_check")
+ */
+ public function securityCheckAction()
+ {
+ // The security layer will intercept this request
+ }
+
+ /**
+ * @Route("/logout", name="_demo_logout")
+ */
+ public function logoutAction()
+ {
+ // The security layer will intercept this request
+ }
+
+ /**
+ * @Route("/hello", defaults={"name"="World"}),
+ * @Route("/hello/{name}", name="_demo_secured_hello")
+ * @Template()
+ */
+ public function helloAction($name)
+ {
+ return array('name' => $name);
+ }
+
+ /**
+ * @Route("/hello/admin/{name}", name="_demo_secured_hello_admin")
+ * @Secure(roles="ROLE_ADMIN")
+ * @Template()
+ */
+ public function helloadminAction($name)
+ {
+ return array('name' => $name);
+ }
+}
18 src/Acme/DemoBundle/Controller/WelcomeController.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Acme\DemoBundle\Controller;
+
+use Symfony\Bundle\FrameworkBundle\Controller\Controller;
+
+class WelcomeController extends Controller
+{
+ public function indexAction()
+ {
+ /*
+ * The action's view can be rendered using render() method
+ * or @Template annotation as demonstrated in DemoController.
+ *
+ */
+ return $this->render('AcmeDemoBundle:Welcome:index.html.twig');
+ }
+}
22 src/Acme/DemoBundle/DependencyInjection/AcmeDemoExtension.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace Acme\DemoBundle\DependencyInjection;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
+use Symfony\Component\HttpKernel\DependencyInjection\Extension;
+use Symfony\Component\Config\FileLocator;
+
+class AcmeDemoExtension extends Extension
+{
+ public function load(array $configs, ContainerBuilder $container)
+ {
+ $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
+ $loader->load('services.xml');
+ }
+
+ public function getAlias()
+ {
+ return 'acme_demo';
+ }
+}
25 src/Acme/DemoBundle/EventListener/ControllerListener.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace Acme\DemoBundle\EventListener;
+
+use Symfony\Component\EventDispatcher\Event;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
+use Acme\DemoBundle\Twig\Extension\DemoExtension;
+
+class ControllerListener
+{
+ protected $extension;
+
+ public function __construct(DemoExtension $extension)
+ {
+ $this->extension = $extension;
+ }
+
+ public function onKernelController(FilterControllerEvent $event)
+ {
+ if (HttpKernelInterface::MASTER_REQUEST === $event->getRequestType()) {
+ $this->extension->setController($event->getController());
+ }
+ }
+}
20 src/Acme/DemoBundle/Form/ContactType.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace Acme\DemoBundle\Form;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\FormBuilderInterface;
+
+class ContactType extends AbstractType
+{
+ public function buildForm(FormBuilderInterface $builder, array $options)
+ {
+ $builder->add('email', 'email');
+ $builder->add('message', 'textarea');
+ }
+
+ public function getName()
+ {
+ return 'contact';
+ }
+}
18 src/Acme/DemoBundle/Resources/config/services.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" ?>
+
+<container xmlns="http://symfony.com/schema/dic/services"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
+
+ <services>
+ <service id="twig.extension.acme.demo" class="Acme\DemoBundle\Twig\Extension\DemoExtension" public="false">
+ <tag name="twig.extension" />
+ <argument type="service" id="twig.loader" />
+ </service>
+
+ <service id="acme.demo.listener" class="Acme\DemoBundle\EventListener\ControllerListener">
+ <tag name="kernel.event_listener" event="kernel.controller" method="onKernelController" />
+ <argument type="service" id="twig.extension.acme.demo" />
+ </service>
+ </services>
+</container>
294 src/Acme/DemoBundle/Resources/public/css/demo.css
@@ -0,0 +1,294 @@
+/*
+Copyright (c) 2010, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.8.2r1
+
+Reset
+*/
+
+html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var,optgroup{font-style:inherit;font-weight:inherit;}del,ins{text-decoration:none;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:baseline;}sub{vertical-align:baseline;}legend{color:#000;}input,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;}input,button,textarea,select{*font-size:100%;}
+
+html, body
+{
+ background-color: #EFEFEF;
+}
+
+body
+{
+ font-size: 14px;
+ font-family: "Lucida Sans Unicode", "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
+ color: #313131;
+}
+
+a
+{
+ color: #08C;
+ text-decoration: none;
+}
+
+a:hover
+{
+ text-decoration: underline;
+}
+
+strong
+{
+ font-weight: bold;
+}
+
+em
+{
+ font-style: italic;
+}
+
+h1, h2, h3
+{
+ font-family: Georgia, "Times New Roman", Times, serif;
+ color: #404040;
+}
+
+h1
+{
+ font-size: 45px;
+ padding-bottom: 30px;
+}
+
+h2
+{
+ font-weight: bold;
+ color: #FFFFFF;
+ /* Font is duplicated of body (sans-serif) */
+ font-family: "Lucida Sans Unicode", "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
+
+ margin-bottom: 10px;
+ background-color: #aacd4e;
+ padding: 2px 4px;
+ display: inline-block;
+ text-transform: uppercase;
+
+}
+
+p
+{
+ line-height: 20px;
+ padding-bottom: 20px;
+}
+
+ul#demo-list a
+{
+ background: url(../images/blue-arrow.png) no-repeat right 6px;
+ padding-right: 10px;
+ margin-right: 30px;
+}
+
+ul, ol
+{
+ padding-left: 20px;
+}
+
+li
+{
+ padding-bottom: 18px;
+}
+
+ol li
+{
+ list-style-type: decimal;
+}
+
+ul li
+{
+ list-style-type: none;
+}
+
+#symfony-header
+{
+ position: relative;
+ padding: 30px 30px 20px 30px;
+}
+
+#symfony-wrapper
+{
+ width: 970px;
+ margin: 0 auto;
+}
+
+.symfony-content
+{
+ background-color: white;
+ border: 1px solid #DFDFDF;
+ padding: 50px;
+ -moz-border-radius: 16px;
+ -webkit-border-radius: 16px;
+ border-radius: 16px;
+ margin-bottom: 20px;
+ word-wrap: break-word;
+}
+
+#symfony-search
+{
+ position: absolute;
+ top: 50px;
+ right: 30px;
+}
+
+#symfony-search input[type="search"]
+{
+ -webkit-appearance: textfield;
+}
+
+#symfony-search-field
+{
+ width: 190px;
+}
+
+#symfony-search label
+{
+ display: block;
+ float: left;
+ width: 20px;
+ height: 25px;
+ background: url(../images/search.png) no-repeat left 5px;
+}
+
+#symfony-search label span
+{
+ display: none;
+}
+
+input[type=text], input[type=password]
+{
+ border: 1px solid #DADADA;
+ background: white url(../images/field-background.gif) repeat-x left top;
+ padding: 5px 6px;
+ color: #565656;
+ font-family: 'Lucida Sans Unicode', 'Lucida Grande', Verdana, Arial, Helvetica, sans-serif;
+ font-size: 12px;
+}
+
+.symfony-button-grey,
+.symfony-button-green
+{
+ font-size: 0.85em;
+ font-weight: bold;
+
+ cursor: pointer;
+
+ display: inline-block;
+ outline: none;
+
+ text-align: center;
+ text-transform: uppercase;
+
+ padding: 3px 10px;
+
+ text-shadow: 0 1px 1px rgba(0,0,0,.3);
+
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+
+.symfony-button-grey
+{
+ color: #868686;
+ font-weight: normal;
+
+ padding: 5px 10px;
+ border: solid 1px #d7d7d7;
+ background: #ffffff;
+ background: -webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#d7d7d7));
+ background: -moz-linear-gradient(top, #ffffff, #d7d7d7);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#d7d7d7');
+}
+
+.symfony-button-green
+{
+ padding: 5px 12px;
+
+ color: white;
+
+ border: solid 1px #a7da39;
+ background: #a7da39;
+ background: -webkit-gradient(linear, left top, left bottom, from(#a7da39), to(#6a9211));
+ background: -moz-linear-gradient(top, #a7da39, #6a9211);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#a7da39', endColorstr='#6a9211');
+}
+
+.symfony-blocks-welcome
+{
+ overflow: hidden;
+}
+
+.symfony-blocks-welcome > div
+{
+ background-color: whitesmoke;
+ float: left;
+ width: 240px;
+ margin-right: 14px;
+ text-align: center;
+ padding: 26px 20px;
+}
+
+.symfony-blocks-welcome > div.block-demo
+{
+ margin-right: 0;
+}
+
+.symfony-blocks-welcome .illustration
+{
+ padding-bottom: 20px;
+}
+
+.symfony-blocks-help
+{
+ overflow: hidden;
+}
+
+.symfony-blocks-help
+{
+ margin-top: 30px;
+ padding: 18px;
+ border: 1px solid #E6E6E6;
+}
+
+.symfony-blocks-help > div
+{
+ width: 254px;
+ float: left;
+}
+
+.flash-message
+{
+ padding: 10px;
+ margin: 5px;
+ margin-top: 15px;
+ background-color: #ffe;
+}
+
+.error
+{
+ color: red;
+}
+
+#login label, #contact_form label
+{
+ display: block;
+ float: left;
+ width: 90px;
+}
+
+ul#menu
+{
+ float: right;
+ margin-bottom: 20px;
+ padding-left: 0;
+}
+
+#menu li
+{
+ padding-left: 0;
+ margin-right: 10px;
+ display: inline;
+}
BIN  src/Acme/DemoBundle/Resources/public/images/blue-arrow.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  src/Acme/DemoBundle/Resources/public/images/field-background.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  src/Acme/DemoBundle/Resources/public/images/logo.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  src/Acme/DemoBundle/Resources/public/images/search.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  src/Acme/DemoBundle/Resources/public/images/welcome-configure.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  src/Acme/DemoBundle/Resources/public/images/welcome-demo.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  src/Acme/DemoBundle/Resources/public/images/welcome-quick-tour.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 src/Acme/DemoBundle/Resources/views/Demo/contact.html.twig
@@ -0,0 +1,15 @@
+{% extends "AcmeDemoBundle::layout.html.twig" %}
+
+{% block title "Symfony - Contact form" %}
+
+{% block content %}
+ <form action="{{ path('_demo_contact') }}" method="POST" id="contact_form">
+ {{ form_errors(form) }}
+
+ {{ form_row(form.email) }}
+ {{ form_row(form.message) }}
+
+ {{ form_rest(form) }}
+ <input type="submit" value="Send" class="symfony-button-grey" />
+ </form>
+{% endblock %}
9 src/Acme/DemoBundle/Resources/views/Demo/hello.html.twig
@@ -0,0 +1,9 @@
+{% extends "AcmeDemoBundle::layout.html.twig" %}
+
+{% block title "Hello " ~ name %}
+
+{% block content %}
+ <h1>Hello {{ name }}!</h1>
+{% endblock %}
+
+{% set code = code(_self) %}
14 src/Acme/DemoBundle/Resources/views/Demo/index.html.twig
@@ -0,0 +1,14 @@
+{% extends "AcmeDemoBundle::layout.html.twig" %}
+
+{% block title "Symfony - Demos" %}
+
+{% block content_header '' %}
+
+{% block content %}
+ <h1>Available demos</h1>
+ <ul id="demo-list">
+ <li><a href="{{ path('_demo_hello', {'name': 'World'}) }}">Hello World</a></li>
+ <li><a href="{{ path('_demo_secured_hello', {'name': 'World'}) }}">Access the secured area</a> <a href="{{ path('_demo_login') }}">Go to the login page</a></li>
+ {# <li><a href="{{ path('_demo_contact') }}">Send a Message</a></li> #}
+ </ul>
+{% endblock %}
11 src/Acme/DemoBundle/Resources/views/Secured/hello.html.twig
@@ -0,0 +1,11 @@
+{% extends "AcmeDemoBundle:Secured:layout.html.twig" %}
+
+{% block title "Hello " ~ name %}
+
+{% block content %}
+ <h1>Hello {{ name }}!</h1>
+
+ <a href="{{ path('_demo_secured_hello_admin', { 'name': name }) }}">Hello resource secured for <strong>admin</strong> only.</a>
+{% endblock %}
+
+{% set code = code(_self) %}
9 src/Acme/DemoBundle/Resources/views/Secured/helloadmin.html.twig
@@ -0,0 +1,9 @@
+{% extends "AcmeDemoBundle:Secured:layout.html.twig" %}
+
+{% block title "Hello " ~ name %}
+
+{% block content %}
+ <h1>Hello {{ name }} secured for Admins only!</h1>
+{% endblock %}
+
+{% set code = code(_self) %}
6 src/Acme/DemoBundle/Resources/views/Secured/layout.html.twig
@@ -0,0 +1,6 @@
+{% extends "AcmeDemoBundle::layout.html.twig" %}
+
+{% block content_header_more %}
+ {{ parent() }}
+ <li>logged in as <strong>{{ app.user ? app.user.username : 'Anonymous' }}</strong> - <a href="{{ path('_demo_logout') }}">Logout</a></li>
+{% endblock %}
29 src/Acme/DemoBundle/Resources/views/Secured/login.html.twig
@@ -0,0 +1,29 @@
+{% extends 'AcmeDemoBundle::layout.html.twig' %}
+
+{% block content %}
+ <h1>Login</h1>
+
+ <p>
+ Choose between two default users: <em>user/userpass</em> <small>(ROLE_USER)</small> or <em>admin/adminpass</em> <small>(ROLE_ADMIN)</small>
+ </p>
+
+ {% if error %}
+ <div class="error">{{ error.message }}</div>
+ {% endif %}
+
+ <form action="{{ path("_security_check") }}" method="post" id="login">
+ <div>
+ <label for="username">Username</label>
+ <input type="text" id="username" name="_username" value="{{ last_username }}" />
+ </div>
+
+ <div>
+ <label for="password">Password</label>
+ <input type="password" id="password" name="_password" />
+ </div>
+
+ <input type="submit" class="symfony-button-grey" value="LOGIN" />
+ </form>
+{% endblock %}
+
+{% set code = code(_self) %}
65 src/Acme/DemoBundle/Resources/views/Welcome/index.html.twig
@@ -0,0 +1,65 @@
+{% extends 'AcmeDemoBundle::layout.html.twig' %}
+
+{% block title %}Symfony - Welcome{% endblock %}
+
+{% block content_header '' %}
+
+{% block content %}
+ {% set version = constant('Symfony\\Component\\HttpKernel\\Kernel::MAJOR_VERSION') ~ '.' ~ constant('Symfony\\Component\\HttpKernel\\Kernel::MINOR_VERSION')%}
+
+ <h1>Welcome!</h1>
+
+ <p>Congratulations! You have successfully installed a new Symfony application.</p>
+
+ <div class="symfony-blocks-welcome">
+ <div class="block-quick-tour">
+ <div class="illustration">
+ <img src="{{ asset('bundles/acmedemo/images/welcome-quick-tour.gif') }}" alt="Quick tour" />
+ </div>
+ <a class="symfony-button-green" href="http://symfony.com/doc/{{ version }}/quick_tour/index.html">Read the Quick Tour</a>
+ </div>
+ {% if app.environment == 'dev' %}
+ <div class="block-configure">
+ <div class="illustration">
+ <img src="{{ asset('bundles/acmedemo/images/welcome-configure.gif') }}" alt="Configure your application" />
+ </div>
+ <a class="symfony-button-green" href="{{ path('_configurator_home') }}">Configure</a>
+ </div>
+ {% endif %}
+ <div class="block-demo">
+ <div class="illustration">
+ <img src="{{ asset('bundles/acmedemo/images/welcome-demo.gif') }}" alt="Demo" />
+ </div>
+ <a class="symfony-button-green" href="{{ path('_demo') }}">Run The Demo</a>
+ </div>
+ </div>
+
+ <div class="symfony-blocks-help">
+ <div class="block-documentation">
+ <ul>
+ <li><strong>Documentation</strong></li>
+ <li><a href="http://symfony.com/doc/{{ version }}/book/index.html">The Book</a></li>
+ <li><a href="http://symfony.com/doc/{{ version }}/cookbook/index.html">The Cookbook</a></li>
+ <li><a href="http://symfony.com/doc/{{ version }}/components/index.html">The Components</a></li>
+ <li><a href="http://symfony.com/doc/{{ version }}/reference/index.html">Reference</a></li>
+ <li><a href="http://symfony.com/doc/{{ version }}/glossary.html">Glossary</a></li>
+ </ul>
+ </div>
+ <div class="block-documentation-more">
+ <ul>
+ <li><strong>Sensio</strong></li>
+ <li><a href="http://trainings.sensiolabs.com">Trainings</a></li>
+ <li><a href="http://books.sensiolabs.com">Books</a></li>
+ </ul>
+ </div>
+ <div class="block-community">
+ <ul>
+ <li><strong>Community</strong></li>
+ <li><a href="http://symfony.com/irc">IRC channel</a></li>
+ <li><a href="http://symfony.com/mailing-lists">Mailing lists</a></li>
+ <li><a href="http://forum.symfony-project.org">Forum</a></li>
+ <li><a href="http://symfony.com/doc/{{ version }}/contributing/index.html">Contributing</a></li>
+ </ul>
+ </div>
+ </div>
+{% endblock %}
49 src/Acme/DemoBundle/Resources/views/layout.html.twig
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html lang="en">