Skip to content

Instantly share code, notes, and snippets.

@KaduNovoK
Created October 27, 2014 17:33
Show Gist options
  • Save KaduNovoK/9944e5195bcd758897e0 to your computer and use it in GitHub Desktop.
Save KaduNovoK/9944e5195bcd758897e0 to your computer and use it in GitHub Desktop.
symfony 2 - best practices
01 - Always use Composer to install Symfony
test: $ composer --version
install: $ curl -sS https:://getcomposer.org/installer | php
$ sudo mv composer.phar /usr/local/bin/composer
02 - Creating a application
$ cd projects/
$ composer create-project symfony/framework-standard-edition blog/
$ cd blog/
$ php app/console --version
$ php app/check.php
03 - Create ony one Bundle called AppBundle for your application logic
$ php app/console generate:bundle --namespace=AppBundle --dir=src --format=annotation --no-interation
04 - Define the infrastructure-related configuration options in the app/config/parameters.yml file
05 - Define all your application's parameters in the app/config/parameters.yml.dist
06 - Define the application behavior related configuration options in the app/config/config.yml file
07 - Use constants to define configuration options that rarely change
08 - Don't define a semantic dependency injection configuration for your bundles
09 - The name of your application's services should be as short as possible, ideally just one simple word
php:
namespace AppBundle\Utils;
class Slugger
{
public function slugify($string)
{
return pre_replace(
'/[^a-z0-9]/', '-', strtolower(trim(strip_tags($string)))
);
}
}
yml:
# app/config/services.yml
services:
slugger: # instead app.utils.slugger
class: AppBundle\Utils\Slugger
into controller:
// ...
$slug = $this->get('slugger')->slugify($string);
10 - Use the YAML format to define your own services
11 - Don't define parameters for the classes of your services
12 - Use notations to define the mapping information of the Doctrine entities
13 - Use fixtures
$ composer require "doctrine/doctrine-fixtures-bundle"
enable the bundle:
if (in_array($this->getEnvironment(), array('dev', 'test'))) {
// ...
$bundles[] = new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle(),
}
loading fixtures:
$ php app/console doctrine:fixtures:load
14 - Use the 5-10-20 rule, your controllers should define 5 variables or less, contain 10 actions or less and include 20 lines or less in each action.
15 - Make your controller extend the FrameworkBundle base controller and use annotations to configure routing, caching and security whenever possible.
to load route anotations of controlers:
# app/config/routing.yml
app:
resource: "@AppBundle/Controller"
type: annotation
16 - Don't use the @Template() annotation to configure the template used by the controller
use: $this->render('path/file.html.twig', array('foo' => 'bar'));
17 - Use the ParamConverter trick to automatically query for Doctrine entities when it's simple and convenient
sample:
/**
* @Route("/comment/{postSlug}/new", name = "comment_new")
*/
public function newAction(Request $request, $postSlug)
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
/**
* @Route("/comment/{postSlug}/new", name = "comment_new")
* @ParamConverter("post", options={"mapping": {"postSlug": "slug"}})
*/
public function newAction(Request $request, Post $post)
18 - Use Twig
19 - Store all your application's templates in app/Resources/views/ directory
20 - Define your twig extensions in the AppBundle/Twig/ directory and configure them using the app/config/services.yml file
$ composer require erusev/parsedown
# app/config/services.yml
services:
# ...
markdown:
class: AppBundle\Utils\Markdown
namespace AppBundle\Utils;
class Markdown
{
private $parser;
public function __construct()
{
$this->parser = new \Parsedown();
}
public function toHtml($text)
{
$html = $this->parser->text($text);
return $html;
}
}
namespace AppBundle\Twig;
use AppBundle\Utils\Markdown;
class AppExtension extends \Twig_Extension
{
private $parser;
public function __construct(Markdown $parser)
{
$this->parser = $parser;
}
public function getFilters()
{
return array(
new \Twig_SimpleFilter(
'md2html',
array($this, 'markdownToHtml'),
array('is_safe' => array('html'))
),
);
}
public function markdownToHtml($content)
{
return $this->parser->toHtml($content);
}
public function getName()
{
return 'app_extension';
}
}
# app/config/services.yml
services:
app.twig.app_extension:
class: AppBundle\Twig\AppExtension
arguments: ["@markdown"]
tags:
- { name: twig.extension }
21 - Add buttons in the templates, not in the form classes or the controllers
22 - Don't use the form() or form_start() functions to render the starting and ending
form tags (the delete is exception)
23 - Use the XLIFF format for your translation files
24 - Store the translation files in the app/Resources/translations/ directory
25 - Always use keys for translations instead of content strings
26 - Unless you have two legitimately different authentication systems and users (e.g. form
login for the main site and a token system for your API only), we recommend having
only one firewall entry with the anonymous key enabled
27 - Use the bcrypt encoder for encoding your users' passwords
security:
encoders:
AppBundle\Entity\User: bcrypt
providers:
database_users:
entity: { class: AppBundle:User, property: username }
firewalls:
secured_area:
pattern: ^/
anonymous: true
form_login:
check_path: security_login_check
login_path: security_login_form
logout:
path: security_logout
target: homepage
28 - For protecting broad URL patterns, use access_control
29 - Whenever possible, use the @Security annotation
30 - Check security directly on the security.context service whenever you
have a more complex situation
31 - For fine-grained restrictions, define a custom security voter
32 - For restricting access to any object by any user via an admin interface, use
the Symfony ACL
33 - Use the security annotation:
/**
* Displays a form to create a new Post entity.
*
* @Route("/new", name="admin_post_new")
* @Security("has_role('ROLE_ADMIN')")
*/
public function newAction()
use AppBundle\Entity\Post;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
/**
* @Route("/{id}/edit", name="admin_post_edit")
* @Security("user.getEmail() == post.getAuthorEmail()")
*/
public function editAction(Post $post)
34 - Use Assetic to compile, combine and minimize web assets, unless you're comfortable
with frontend tools like GruntJS
35 - Define a functional test that at least checks if your application pages are successfully
loading
/** @dataProvider provideUrls */
public function testPageIsSuccessful($url)
{
$client = self::createClient();
$client->request('GET', $url);
$this->assertTrue($client->getResponse()->isSuccessful());
}
public function provideUrls()
{
return array(
array('/'),
array('/posts'),
array('/post/fixture-post-1'),
array('/blog/category/fixture-category'),
array('/archives'),
// ...
);
}
36 - Hardcode the URLs used in the functional tests instead of using the URL generator
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment