Liste de toutes les commandes consoles disponibles

php bin/console

Symfony 3 > Installation avec Composer

Pré-requis

Vérifier qu'on peut exécuter des commandes Php avec la console

php -v

Si le message "php n'est pas reconnu en tant que commande interne" apparaît, il faut ajouter le répertoire où se trouve la commande php à la variable d'environnement PATH :
Aller dans Démarrer > Panneau de configuration > Système et sécurité > Système > Paramètres systèmes avancés > Variables d'environnement.
Dans le panneau "Variables systèmes", double-cliquer sur l'entrée Path.
Dans "Valeur de la variable", ajouter le répertoire Php : ;C:\wamp\bin\php\php5.5.12 Confirmer en cliquant sur OK.
Redémarrer l'ordinateur et exécuter à nouveau la commande :

php -v

La version de Php apparaît :

Php 5.5.12 (...) Copyright (...) Zend engine (...)

Vérifier qu'on a Git

git version

Si ce n'est pas le cas, aller sur :

https://git-scm.com/

Télécharger et exécuter l'installeur.

Afficher la documentation Git

git help

Installer Composer

Ouvrir une fenêtre de commandes dans le dossier www pour y télécharger le fichier composer.phar

php -r "eval('?>'.file_get_contents('http://getcomposer.org/installer'));

Installer l'application Symfony

Créer un dossier vide dans www qui va contenir le projet dont le nom est (par exemple) "site_stretching"

Ouvrir une fenêtre de commandes dans www.

Pour télécharger une application complète Symfony exécuter :

php composer.phar create-project symfony/framework-standard-edition site_stretching

Laisser charger puis faire ok pour tout (database et mailer) sauf pour database_name (indiquer le nom "stretching" par exemple)

Installer les ressources dans le dossier web

Rendre disponibles les nouveaux fichiers JS et CSS du bundle
Charger les fichiers CSS, copier les fichiers statiques des bundles dans web (utiliser --symlink pour des liens symboliques à la place de copies)

php bin/console assets:install

Vérifier l'intallation

Vérifier que l'application tourne

http://localhost/site_stretching/web/

Solution 1 pour vérifier la configuration et suivre les indications

http://localhost/site_stretching/web/config.php

Solution 2 pour vérifier la configuration et suivre les indications

php bin/symfony_requirements

Vérifier l'environnement de développement

http://localhost/site_stretching/web/app_dev.php/

Vérifier l'environnement de production

http://localhost/site_stretching/web/app.php

Vérifier le profiler

http://localhost/site_stretching/web/app_dev.php/_profiler

Symfony 3 > Bundles

Créer un bundle

Ouvrir une fenêtre de commandes dans le dossier site_stretching

php bin/console generate:bundle
Multiples applications : yes
Namespace : Sofictif/StretchingBundle
Bundle name : SofictifStretchingBundle
Target directory : src
Configuration format : annotation

Retourner dans l'environnement de développement

http://localhost/site_stretching/web/app_dev.php/

Que s'est-il passé ?

1. Le Kernel a chargé le bundle :
Dans le fichier app/AppKernel.php est apparue la ligne :
new Sofictif\StretchingBundle\SofictifStretchingBundle(),

2. Le routing a pris en compte le bundle :
Dans le fichier app/config/routing.yml sont apparues les lignes :

sofictif_stretching:
resource: "@SofictifStretchingBundle/Controller/"
type: annotation
prefix: /

3. Dans le dossier src a été créé un dossier "Sofictif" qui comporte un sous-dossier "StretchingBundle".
Dans ce dernier a été créée une arborescence type dans laquelle on peut travailler (dont les dossiers "Controller", "DependencyInjection", "Entity", "Repository", "Resources", "Tests", et un fichier "SofictifStrectchingBundle.php")

Supprimer le Appbundle

Supprimer le dossier /src/Appbundle
Supprimer du fichier /app/AppKernel.php la ligne :

new AppBundle\AppBundle(),

Supprimer les chemins du bundle dans /app/config/routing.yml qui correspondent à ces lignes :

app:
resource: "@AppBundle/Controller/"
type: annotation

Nettoyer le cache :

php bin/console cache:clear

Retourner dans l'environnement de développement

http://localhost/site_stretching/web/app_dev.php/

Bundles de la communauté Symfony

Ils sont regroupés sur http://knpbundles.com.

Exemples de bundles :

  • FOSUserBundle pour gérer les utilisateurs
  • FOSCommentBundle pour gérer des commentaires
  • GravatarBundle pour gérer les avatars depuis le service web Gravatar
  • etc.

Symfony 3 > Entités

Créer une entité

Pour une entité "Image", créer une base de donnée vide dans PhpMyadmin, puis exécuter dans la console :

php bin/console doctrine:generate:entity
shortcutname : SofictifStretchingBundle:Image
configuration format : annotation

Si on ne veut pas utiliser la console pour générer les propriétés, cliquer sur "entrée" tout le temps, ensuite entrer "à la main" les paramètres dans le fichier de l'entité

Que s'est-il passé ?

Dans le dossier /src/Sofictif/StretchingBundle/Entity a été créé la classe Image.php, fichier php de l'entité Image.

Générer les getters, setters et repository de cette entité

php bin/console doctrine:generate:entities SofictifStretchingBundle:Image

Que s'est-il passé ?

1. Les getters et setters ont été générés dans /src/Sofictif/StretchingBundle/Entity/Image.php
Un fichier Image.php~ reste à côté de Image.php, il contient le fichier initial qu'on peut supprimer si tout est ok.

2. Un fichier ImageRepository.php a été créé dans /src/Sofictif/StretchingBundle/Repository/

Générer toutes les entités d'un bundle

php bin/console doctrine:generate:entities SofictifStretchingBundle

Génerer des entités à partir d'une base existante

http://symfony.com/doc/current/cookbook/doctrine/reverse_engineering.html

Relations entre les entités

OneToOne, Unidirectional

Dans l'entité Book.php :

/**
* @ORM\OneToOne(targetEntity="Illustration", cascade={"persist"})
* @ORM\JoinColumn(name="illustration_id", referencedColumnName="id")
*/
private $illustration;

OneToOne, Bidirectional

Dans l'entité Book.php :

/**
* @ORM\OneToOne(targetEntity="Illustration", inversedBy="book", cascade={"persist"})
* @ORM\JoinColumn(name="illustration_id", referencedColumnName="id")
*/
private $illustration;

Dans l'entité Illustration.php :

/**
* @ORM\OneToOne(targetEntity="Book", mappedBy="illustration")
*/
private $book;

ManyToOne

Dans l'entité Book.php :

/**
* @ORM\ManyToOne(targetEntity="Collection", inversedBy="books", cascade={"persist"})
* @ORM\JoinColumn(name="collection_id", referencedColumnName="id")
*/
private $collection;

Dans l'entité Collection.php :

/**
* @ORM\OneToMany(targetEntity="Book", mappedBy="collection", cascade={"persist"})
*/
private $books;

ManyToMany

Dans l'entité Family.php :

/**
* @ORM\ManyToMany(targetEntity="Person", mappedBy="families", cascade={"persist"})
*/
private $persons;

Dans l'entité Person.php :

/**
* @ORM\ManyToMany(targetEntity="Family", inversedBy="persons", cascade={"persist"})
* @ORM\JoinTable(name="persons_families")
*/
private $families;

Supprimer une entité complète et son équivalent dans la base de données quand elle a une foreign key

1. Supprimer manuellement tous les fichiers dans les dossiers : entity, repository, form

2. Dans phpmyadmin supprimer constrainte la foreign key :
Afficher la structure de la table parente, cliquer sur "vue relationnelle"
À droite du nom du champ, garder le même nom de base de donnée mais mettre des valeurs vides pour la table et le champ
Au lieu d'avoir audio_id podcasts audio id
Mettre audio_id podcasts rien rien

3. Supprimer manuellement les champs et tables concernés

Symfony 3 > Doctrine

Créer une base de données

Vérifier les informations de configuration sur la base de données dans le fichier app/config/parameters.yml

php bin/console doctrine:database:create

Générer des commandes SQL à partir des entités pour pouvoir créer et/ou mettre à jour les tables

Pour les entités complètes

php bin/console doctrine:schema:create --dump-sql

Pour les éléments modifiés des entitiés

php bin/console doctrine:schema:update --dump-sql

Créer et/ou mettre à jour concrètement les tables de la base de données dans PhpMyAdmin

Envoyer les modifications SQL à la base de données

php bin/console doctrine:schema:update --force

Récupérer des infos sur la base de données

php bin/console doctrine:mapping:info

Supprimer une base de données

php bin/console doctrine:database:drop --force

Symfony 3 > Contrôleurs

Générer les contrôleurs, les formulaires et les vues à partir d'une entité

http://symfony.com/doc/current/bundles/SensioGeneratorBundle/commands/generate_doctrine_crud.html php bin/console generate:doctrine:crud
The entity shortcut name : SofictifStretchingBundle:Image
Do you want to generate the "write" actions ? yes
Configuration format : annotation
Route prefix : image
Du you confirm ? yes

Que s'est-il passé ?

1. Le contrôleur est généré dans src/Sofictif/StretchingBundle/Controller.
Il liste tous les enregistrements, en affiche un en fonction de son id, crée, modifie et supprime un nouvel enregistrement (actions list, show, new, update, delete)

2. Les vues sont créées dans le dossier app/Resources/views.

3. Le type de formulaire est généré dans src/Sofictif/StretchingBundle/Form

Déplacer les vues dans le bundle Sofictif

Déplacer le dossier des vues dans le dossier src/Sofictif/StretchingBundle/Resources/views
Dans chaque vue, faire hériter de la vue de base du bundle :

{% extends 'SofictifStretchingBundle::base.html.twig' %}

Dans le contrôleur, modifier chaque lien des rendus des vues :

return $this->render('SofictifStretchingBundle::image/index.html.twig', array(...)); Télécharger le pack minimum

Retours d'un contrôleur

Retour simple

use Symfony\Component\HttpFoundation\Response;
return new Response('My training');

Retour avec html

use Symfony\Component\HttpFoundation\Response;
return new Response(
'<html><body>Duration: '.$secondes.'</body></html>'
);

Retour dans un template

return $this->render('SofictifStretchingBundle::body/upper.html.twig', array(
'member' => $arms,
'duration' => $secondes,
));

Redirection vers une route d'un contrôleur

return $this->redirectToRoute('home');

Redirection vers une route d'un contrôleur avec des paramètres

return $this->redirectToRoute('body_show', array('member' => 'legs'));

Forward à un autre contrôleur

$response = $this->forward('SofictifStretchingBundle:Body:lower', array(
'member' => $legs,
'duration' => $secondes,
));
return $response;

public function bodyAction($member, $duration) {}

Redirection permanente 301

return $this->redirectToRoute('home', array(), 301);

Redirection externe

return $this->redirect('http://symfony.com/doc');

Symfony 3 > Repositories

Surcharge de la méthode findAll() avec un ordre d'affichage des éléments

La méthode createQueryBuilder() retourne une instance de QueryBuilder qui permet de construire une Query.
Faire une requête sur l'entité gérée par ce repository.

public function findAll() {
return $this
->createQueryBuilder('a')
->orderBy('a.name', 'ASC')
->getQuery()
->getResult()
;
}

Autre solution :

public function findAll() {
return $this->findBy(array(), array('name' => 'ASC'));
}

Symfony 3 > Cache

Nettoyer le cache

php bin/console cache:clear

Supprimer physiquement les fichiers du dossier var > cache > dev

Supprimer physiquement les fichiers du dossier var > cache > prod

Vider spécifiquement le cache de l’environnement de production

php bin/console cache:clear --env=prod

Symfony 3 > Formulaires

Générer un formulaire depuis une entité

Pas besoin de le faire si on génère les contrôleurs en ligne de commande.

php bin/console doctrine:generate:form SofictifStretchingBundle:Categorie

Builder dans src > Sofictif > StretchingBundle > Form > PositionType.php

TextType

use Symfony\Component\Form\Extension\Core\Type\TextType;
$builder->add('title', TextType::class, array(
'required' => true,
'label' => 'Titre',
));

Correspondance dans src > Sofictif > StretchingBundle > Entity > Position.php

* @ORM\Column(type="string", length=255)

TextareaType

use Symfony\Component\Form\Extension\Core\Type\TextareaType;
$builder->add('description', TextareaType::class, array(
'required' => true,
'label' => 'Description',
));

Correspondance dans src > Sofictif > StretchingBundle > Entity > Position.php

* @ORM\Column(type="text", nullable=true)

MoneyType

use Symfony\Component\Form\Extension\Core\Type\MoneyType;
$builder->add('sellingprice', MoneyType::class, array(
'required' => true,
'label' => 'Prix',
));

Correspondance dans src > Sofictif > StretchingBundle > Entity > Position.php

* @ORM\Column(type="float", nullable=true)

TimeType

use Symfony\Component\Form\Extension\Core\Type\TimeType;
$builder->add('startime', TimeType::class, array(
'required' => false,
'label' => 'Heure de début',
'input' => 'datetime',
'widget' => 'choice',
'placeholder' => array(
'hour' => 'Heure', 'minute' => 'Minute', 'second' => 'Second',
)
));

Correspondance dans src > Sofictif > StretchingBundle > Entity > Position.php

* @ORM\Column(name="startime", type="time", nullable=true)

ChoiceType

use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
$builder->add('acquired', ChoiceType::class, array(
'required' => true,
'label' => 'Acquis',
'choices' => array(
'oui' => true,
'non' => false,
),
'placeholder' => false,
'multiple' => false,
'expanded' => true,
));

Correspondance dans src > Sofictif > StretchingBundle > Entity > Position.php

* @ORM\Column(type="boolean", options={"default":false})

FileType

use Symfony\Component\Form\Extension\Core\Type\FileType;
$builder->add('file', FileType::class, array(
'required' => false,
'label' => 'Fichier',
'data_class' => null,
));

Correspondance dans src > Sofictif > StretchingBundle > Entity > Position.php

* @ORM\Column(name="file", type="string", length=255, nullable=true)

EntityType (si relation avec une entité)

use Symfony\Bridge\Doctrine\Form\Type\EntityType;
$builder->add('family', EntityType::class, array(
'required' => false,
'label' => 'Famille',
'class' => 'SofictifStretchingBundle:Family',
'multiple' => true,
'expanded' => true,
'placeholder' => false,
'choice_label' => 'name',
));

Correspondance dans src > Sofictif > StretchingBundle > Entity > Position.php

* @ORM\OneToOne(targetEntity="Member", cascade={"persist"})
* @ORM\JoinColumn(name="holder_id", referencedColumnName="id")

EntityType avec label multiple

use Symfony\Bridge\Doctrine\Form\Type\EntityType;
$builder->add('family', EntityType::class, array(
'required' => false,
'label' => 'Famille',
'class' => 'SofictifStretchingBundle:Family',
'multiple' => true,
'expanded' => true,
'choice_label' => function ($member) {
return $member->getName().' '.$member->getSurname();
},
));

EntityType avec label multiple et affichage dans un ordre particulier (si relation avec une entité)

use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
$builder->add('family', EntityType::class, array(
'required' => false,
'label' => 'Famille',
'class' => 'SofictifStretchingBundle:Family',
'multiple' => true,
'expanded' => true,
'choice_label' => function ($member) {
if ($member->getType() == 0) {
$type = 'femme';
} else {
$type = 'homme';
}
return $member->getName().' '.$member->getSurname().' ('.$type.')';
},
'query_builder' => function (EntityRepository $family) {
return $family->createQueryBuilder('f')
->orderBy('f.id, f.name', 'ASC');
->add('where', 'f.registration = 1 and f.id != 12');
},
));

Récupérer l’id d’un objet de formulaire et le réutiliser dans le QueryBuilder

public function buildForm(FormBuilderInterface $builder, array $options)
{
$idConferenceSpeaker = $builder->getData()->getSpeaker()->getId();

$builder
->add('additionalspeakers', EntityType::class, array(
'required' => false,
'label' => false,
'class' => 'SofictifPodcastBundle:Speaker',
'choice_label' => function ($speaker) {
return $speaker->getSurname().' '.$speaker->getName();
},
'query_builder' => function (EntityRepository $speaker) use ($idConferenceSpeaker) {
return $speaker->createQueryBuilder('s')
->add('where', 's.id != '.$idConferenceSpeaker)
->orderBy('s.surname', 'ASC');
},
'multiple' => true,
'expanded' => true,
'placeholder' => false,
))
;
}

Passer un paramètre du controller au formulaire

Dans le controller

$type = $em->getRepository('SofictifStretchingBundle:Type')->findOneBySlug('slug');

$form = $this->createForm('Sofictif\StretchingBundle\Form\CategorieMenusSortableType', $categorie, array(
'attr' => array('typeid' => $type->getId()),
));
$form->handleRequest($request);

Dans le formulaire

public function buildForm(FormBuilderInterface $builder, array $options)
{
$typeid = $options['attr']['typeid'];
var_dump($typeid);

$builder->add(...);
}

Trier les champs du formulaire dans l'ordre des Id depuis le formaulaire

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;

public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('menus', CollectionType::class, array(
'entry_type' => MenuType::class,
))
;
}

public function finishView(FormView $view, FormInterface $form, array $options)
{
usort($view['menus']->children, function (FormView $a, FormView $b) {

$objectA = $a->vars['data'];
$objectB = $b->vars['data'];

$posA = $objectA->getId();
$posB = $objectB->getId();

if ($posA == $posB) {
return 0;
}

return ($posA < $posB) ? -1 : 1;

});

}

Query_builder avec une variable pour un EntityType

L'EntityType du fomulaire va afficher tous les chapitres du même livre et non tous les chapitres existants en base de données

Télécharger le pack minimum

Héritage des formulaires

Télécharger le pack minimum

Cacher un champ texte

use Symfony\Bridge\Doctrine\Form\Type\HiddenType;
$builder->add('name', HiddenType::class);

Cacher un champ date

$builder->add('startdate', null, array(
'label' => false,
'attr' => array('style'=>'display:none;')
));

Cacher un champ file

$builder->add('file', null, array(
'label' => false,
'attr' => array('style'=>'display:none;')
));

Cacher un champ entity

$builder->add('workshops', EntityType::class, array(
'class' => 'SofictifStretchingBundle:Workshop',
'label' => false,
'choice_label' => false,
'multiple' => true,
'attr' => array('style'=>'display:none;'),
));

Désactiver les validations de l'entitié (Assert) dans un formulaire (erreur "The file could not be found.")

use Symfony\Component\OptionsResolver\OptionsResolver;

public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'validation_groups' => false,
));
}

Affichage simple dans twig

{{ form_start(edit_form) }}
{{ form_widget(edit_form) }}
<input type="submit" value="enregistrer" />
{{ form_end(edit_form) }}

Affichage personnalisable dans twig

{{ form_start(edit_form) }}
<div>
{{ form_label(edit_form.name) }}
{{ form_errors(edit_form.name) }}
{{ form_widget(edit_form.name) }}
</div>
<input type="submit" value="enregistrer" />
{{ form_end(edit_form) }}

Affichage personnalisable dans twig - Modification du label

{{ form_start(edit_form) }}
<div>
{{ form_label(edit_form.name, 'Nouveau label') }}
{{ form_errors(edit_form.name) }}
{{ form_widget(edit_form.name) }}
</div>
<input type="submit" value="enregistrer" />
{{ form_end(edit_form) }}

Cacher un champ dans twig

{{ form_start(edit_form) }}
<div style="display:none;">
{{ form_row(edit_form.title) }}
</div>
{{ form_end(edit_form) }}

Cacher le label d'un champ dans twig

{{ form_start(edit_form) }}
<div>
{{ form_label(edit_form.themes, null, {'label_attr': {'class':'hidden'}}) }}
{{ form_errors(edit_form.themes) }}
{{ form_widget(edit_form.themes) }}
</div>
{{ form_end(edit_form) }}

Symfony 3 > Bibliothèques

Mettre à jour uniquement une bibliothèque

php composer.phar update jasig/phpcas

Mettre à jour toutes les bibliothèques

php composer.phar update

Symfony 3 > Upload

Configurer le dossier des uploads

Dans app > config > config.yml :

parameters:
images_directory: '%kernel.root_dir%/../web/uploads/images'

Créer un dossier "uploads" vide dans web

Paramétrer l'entité

Dans src > Sofictif > StretchingBundle > Entity > Position.php

use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @Assert\File(
*  maxSize = "10M",
*  maxSizeMessage = "Ce fichier est trop lourd, le maximum est : 10 Mo",
*  mimeTypes = {"image/png", "image/gif", "image/jpg", "image/jpeg"},
*  mimeTypesMessage = "Choisissez un nouveau fichier : seuls les png, gif et jpg sont possibles"
*  uploadIniSizeErrorMessage = "Choisissez un nouveau fichier : le fichier que vous avez chargé est trop lourd, le maximum pour le serveur est de 500 Mo",
* )
*/
private $image;

Gérer le formulaire

Dans src > Sofictif > StretchingBundle > Form > PositionType.php

use Symfony\Component\Form\Extension\Core\Type\FileType;
$builder->add('file', FileType::class, array(
'required' => false,
'label' => 'Fichier de l\'image',
'data_class' => null
));

Gérer le contrôleur

Dans src > Sofictif > StretchingBundle > Controller > PositionController.php

Symfony 3 > Services

Créer un service qui formate une chaîne de caractères depuis un contrôleur

Enregistrer le sercice
Dans src > Sofictif > StretchingBundle > Resources > config > service.yml

services:
   sofictif_stretching.title:
       class: Sofictif\StretchingBundle\Service\Title

Dans src > Sofictif > StretchingBundle > Service > Title.php

namespace Sofictif\StretchingBundle\Service;

class Title
{
/**
 * Supprimer les éléments inutiles d'une chaine de caractère
 *
 * @param string $text
 * @return string
 */
public function cleanTitle($text)
{
// Supprimer les espaces en début et fin de chaîne
$text = trim($text);

// Remplacer les espaces multiples en milieu de chaîne par un espace unique
$text = preg_replace('/ +/', ' ', $text);

// Supprimer les tirets en début et fin de chaîne
$text = trim($text, '-');

return $text;
}
}

Dans src > Sofictif > StretchingBundle > Controller > BookController.php

$servicetitle = $this->get('sofictif_stretching.title');
$title = $servicetitle->cleanTitle('titre');

Créer une extension Twig avec une fonction qui peut être utilisé directement dans le template

Enregistrer le sercice
Dans src > Sofictif > StretchingBundle > Resources > config > service.yml

services:
   sofictif_stretching.calcul:
       class: Sofictif\StretchingBundle\Service\Calcul
       tags:
       -  { name: twig.extension }

Dans src > Sofictif > StretchingBundle > Service > Calcul.php

namespace Sofictif\StretchingBundle\Service;

/**
 * Description de Calcul
 *
 */
class Calcul extends \Twig_Extension
{

public function getName()
{
return 'calculsofictif_extension';
}

public function getFunctions(){
return array(
new \Twig_SimpleFunction('multiplierpartrois', array($this, 'multiplier')),
);
}

public function multiplier($number){
$number = $number * 3;
return $number;
}

}

Dans src > Sofictif > StretchingBundle > Resources > views > base.html.twig

{{ multiplierpartrois(4) }}

Créer une extension Twig qui exécute une requête doctrine pour être utilisée dans le template

Enregistrer l'extension Twig comme un sercice
Dans src > Sofictif > StretchingBundle > Resources > config > service.yml

services:
   sofictif_stretching.query:
       class: Sofictif\StretchingBundle\Service\Query
       tags:
       -  { name: twig.extension }
       arguments:
            doctrine: "@doctrine"

Dans src > Sofictif > StretchingBundle > Service > Query.php

namespace Sofictif\StretchingBundle\Service;

class Query extends \Twig_Extension
{
protected $doctrine;

public function __construct($doctrine)
{
$this->doctrine = $doctrine;
}

public function getName()
{
return 'querysofictif_extension';
}

public function getFunctions(){
return array(
new \Twig_SimpleFunction('listofbookswithtwig', array($this, 'retrieveallthebooks')),
new \Twig_SimpleFunction('retrieveabookwithtwig', array($this, 'retrieveabook')), );
}

public function retrieveallthebooks(){
$em = $this->doctrine->getManager();
$books = $em->getRepository('SofictifStretchingBundle:Book')->findAll();
return $books;
}

public function retrieveabook($id){
$em = $this->doctrine->getManager();
$book = $em->getRepository('SofictifStretchingBundle:Book')->find($id);
return $book;
}

}

Utilisation dans Twig

Récupération de la liste complète

{% for book in listofbookswithtwig() %}
{{book.title}}
{% endfor %}

Récupération d'un élément

{{ retrieveabookwithtwig(3).title }}

Symfony 3 > Twig

Hériter d'un autre template

{% extends 'SofictifStrecthingBundle::base.html.twig' %}

N'afficher un élément que s'il existe

{% if position.description is defined %}
{{ position.description }}
{% else %}
Pas de position trouvée
{% endif %}

N'afficher un élément que si une variable est définie

{% if position.description is defined %}
{{ position.description }}
{% endif %}

Boucler sur des éléments

{% for position in positions %}
{{ position.name }}{% if loop.last == false %}, {% endif %}
{% else %}
Pas de position trouvée
{% endfor %}

Afficher une entité liée

{{ position.member.name }}

Lien sans paramètres

<a href="{{ path('position_new') }}">ajouter une nouvelle position</a>

Lien avec paramètres

<a href="{{ path('position_show', { 'id': position.id }) }}">{{ position.name }}</a>

Inclure une autre page

{% include 'SofictifStretchingBundle::position/content.html.twig' %}

Variables

Définir des variables

{% set variablesgenerales = {
'titre': 'Stretching',
'description': 'Catalogue d'exercices'
} %}

Utiliser dans la même page

{{variablesgenerales.titre}}

Inclure une autre page avec ces variables

{% include 'CanopeEdelegueBundle::include/header.html.twig' with variablesgenerales %}

Utiliser ces variables dans la page inclue

{{titre}}

Inclure une autre page avec un paramètre et détecter ce paramètre

Page qui inclue une autre

{% include 'SofictifStretchingBundle::position/content.html.twig' with {'holder': true} %}

Page à inclure

{% if holder is not defined %}
{{ position.holder.name }}
{% endif %}

Afficher un booléen

{% if position.acquired %}Oui{% else %}Non{% endif %}

Afficher une image stockée dans le dossier web

<img src="{{ asset('images/canope.png') }}" alt="" title="" />

Insérer une variable dans la valeur d'un attribut html

Dans un simple attribut

<a href="http://maps.google.com/?q= ~ {{ editor.address }} ~) }}">{{ editor.address }}</a>
<div style="background-color:{{ module.color }};"></div>
<img src="{{ asset('images/' ~ module.image ~ '') }}">
<video id="" controls poster="{{ asset('uploads/teaser/' ~ labtwig(1).poster) }}">
<source src="{{ asset('uploads/teaser/' ~ labtwig(1).teaser) }}" type="video/mp4">
Votre navigateur ne supporte pas la balise vidéo
</video>

Dans un attribut avec une valeur contenant un asset

<link rel="stylesheet" href="{{ asset('bundles/canopepreac/css/styles-' ~ categoriechoisie.slug ~ '.css') }}" />

Récupérer des variables issues de la configuration de l'application

Paramètres de l'application : dans app/config/config.yml

parameters:
$nbsp;$nbsp;$nbsp;$nbsp;app.version: 0.1.0

Configuration de Twig : dans app/config/config.yml

twig:
$nbsp;$nbsp;$nbsp;$nbsp;globals:
$nbsp;$nbsp;$nbsp;$nbsp;$nbsp;$nbsp;$nbsp;$nbsp;version: '%app.version%'

Dans le template Twig

{{ version }}

Les variables globales

http://alexandre.clain.info/twig-les-variables-globales/

Récupérer l'url courante

{{ app.request.schemeAndHttpHost }}
{{ app.request.requestUri }}
{{ app.request.schemeAndHttpHost ~ app.request.requestUri }}

Récupérer l'hôte avec http

{{ app.request.schemeAndHttpHost }}

Récupérer le nom du serveur hôte qui exécute le script

{{ app.request.server.get("SERVER_NAME") }}

Récupérer l’url de base de l’application

{{ app.request.baseUrl }}

Récupérer le chemin de base

{{ app.request.basepath }}

Récupérer le chemin de la page courante sans le nom de domaine

{{ app.request.requestUri }}

Récupérer le chemin d’accès de l’application sans le nom de domaine

{{ app.request.pathInfo }}

Récupérer les méthodes de requêtes qui ont été utilisés à l’appel de la page (POST, GET)

{{ app.request.method }}

Récupérer l’environnement actuel (production, développement)

{{ app.environment }}

Savoir si le mode debug est activé ou non (retourne un boolean)

{{ app.debug }}

Récupérer les informations de l’utilisateur courant (entité User)

{{ app.user }}

Retourner la requête HTTP complète

{{ app.request }}

Récupérer le nom de la route utilisée

{{ app.request.attributes.get("_route") }}

Accéder à un paramètre d’une requête GET

{{ app.request.query.get("nom_du_parametre") }}

Accéder à un paramètre d’une requête POST

{{ app.request.parameter.get("nom_du_parametre") }}

Retourner une séquence des éléments téléchargé par le serveur lors d’un envoi de fichier(s)

{{ dump(app.request.files) }}

Accéder à un paramètre contenu dans un cookie

{{ app.request.cookies.get("nom_du_parametre") }}

Retourner toutes les informations du header de la requête HTTP (dont le user-agent, le referer, etc.)

{{ app.request.headers }}

Retourner toutes les informations du contenu de la requête HTTP

{{ app.request.content }}

Récupérer la séquence des langages acceptés par le navigateur

{{ dump(app.request.languages) }}

Récupérer la séquence des jeux de caractères acceptés par le navigateur

{{ dump(app.request.charsets) }}

Récupérer la séquence des types de contenus acceptés par le navigateur

{{ dump(app.request.acceptableContentTypes) }}

Récupérer la séquence listant toute les informations relative à la sécurité de la page de l’applicatio

{{ dump(app.security) }}

Récupérer des informations précises relatives à la sécurité

{{ app.security.token }}
{{ app.security.key }}
{{ app.security.user }}
{{ app.security.roles }}
{{ app.security.authenticated }}
{{ app.security.attributes }}
{{ app.security.alwaysAuthenticate }}

Afficher une session

{{ dump(app.request.session) }}

Accéder à un paramètre contenu dans une session

{{ app.request.session.get("nom_du_parametre") }}

Les filtres

http://alexandre.clain.info/twig-les-filtres-disponibles/#twig_title

Symfony 3 > Librairie Phpcas

Liens

https://packagist.org/packages/jasig/phpcas
https://wiki.jasig.org/display/CASC/Symfony+CAS+Client

Déclarer la dépendance dans le fichier composer.json

Ce fichier au premier niveau de l'application répertorie la liste des bibliothèques dont le projet dépend.

Préciser dans "require" la version de la librairie externe :

"require": {
"jasig/phpcas": "^1.3",
},

Installer le dossier de cette bibliothèques et ceux de ses dépendances dans le dossier "vendor"

php composer.phar require jasig/phpcas

Enregistrer le bundle dans le Kernel

Ajouter dans app/AppKernel.php :

$bundles = [
new Stfalcon\Bundle\TinymceBundle\StfalconTinymceBundle(),
];

Composer a donné à Symfony les informations de namespaces pour l'autoload

Installer les ressources dans le dossier web

Rendre disponibles les nouveaux fichiers JS et CSS du bundle
Charger les fichiers CSS, copier les fichiers statiques des bundles dans web (utiliser --symlink pour des liens symboliques à la place de copies)

php bin/console assets:install

Mettre à jour cette bibliothèque

php composer.phar update jasig/phpcas

Symfony 3 > Librairie CKEditor

Liens

http://ckeditor.com/
https://packagist.org/packages/egeloen/ckeditor-bundle
http://symfony.com/doc/current/bundles/IvoryCKEditorBundle/index.html

Installer la librairie externe

Déclarer la dépendance dans le fichier composer.json
Il répertorie la liste des bibliothèques dont le projet dépend)
Préciser dans "require" sa version :

"require": {
"egeloen/ckeditor-bundle": "~4.0"
},

Installer le dossier de cette bibliothèques et ceux de ses dépendancesdans le dossier "vendor" :

php composer.phar require egeloen/ckeditor-bundle

Enregistrer le bundle dans le Kernel (permet à Composer de donner à Symfony les informations de namespaces pour l'autoload en ajoutant dans AppKernel.php :

$bundles = [
new Ivory\CKEditorBundle\IvoryCKEditorBundle(),
];

Installer les fichiers JS et CSS du bundle
Utiliser --symlink pour des liens symboliques à la place de copies
Il se crée dans web/bundles un dossier "ivoryckeditor" dans lesquels sont copiés les fichiers statiques.

php bin/console assets:install web

Mettre à jour uniquement de cette bibliothèque

php composer.phar update egeloen/ckeditor-bundle

Configurer les boutons

Dans app/config/config.yml :

ivory_ck_editor:
    default_config: my_config
    configs:
        my_config:
            toolbar: "my_toolbar"
            language: fr
            skin: '../../../ckeditor/skins/moono-dark'
    toolbars:
        configs:
            my_toolbar: [ "@my_clipboard","@my_editing","@my_document","@my_tools","/","@my_paragraph","@my_styles","@my_basicstyles","@my_links","@my_insert" ]
        items:
            my_clipboard: [ 'Cut','Copy','PasteText' ]
            my_editing: [ 'Find','-','Scayt' ]
            my_document: [ 'Undo','Redo','-','Preview','Source','-','Print' ]
            my_tools: [ 'ShowBlocks','-','About' ]
            my_paragraph: [ 'JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock','-','NumberedList','BulletedList','-','Blockquote' ]
            my_styles: [ 'Format' ]
            my_basicstyles: [ 'Bold','Italic','Underline','Subscript','Superscript','-','RemoveFormat' ]
            my_links: [ 'Link','Unlink','Anchor' ]
            my_insert: [ 'Image','Table','HorizontalRule','PageBreak','SpecialChar' ]

Gérer le formulaire

Dans src > Sofictif > StretchingBundle > Form > PositionType.php :

use Ivory\CKEditorBundle\Form\Type\CKEditorType;
$builder->add('description', CKEditorType::class, array(
'required' => false,
'label' => ' ',
'config_name' => 'my_config',
));

Paramétrer l'entité

Correspondance dans l'entité src > Sofictif > StretchingBundle > Entity > Position.php :

/**
 * @ORM\Column(name="content", type="text", nullable=true)
*/
private $content;

Modifier le skin

Pour charger le skin "moono-dark", placer un dossier ckeditor (Télécharger le pack minimum) dans le dossier web

Télécharger d'autres skins ici :

http://ckeditor.com/addons/skins/all

Symfony 3 > Datepicker

Liens

http://www.malot.fr/bootstrap-datetimepicker/
https://bootstrap-datepicker.readthedocs.io/

Télécharger les sources

Télécharger le pack minimum et le placer dans le dossier web

Charger les scripts

<script src="{{ asset('bootstrap-3.3.7-dist/js/bootstrap.js') }}"></script>
<script src="{{ asset('bootstrap-datetimepicker-master/js/bootstrap-datetimepicker.min.js') }}"></script>
<script src="{{ asset('bootstrap-datetimepicker-master/js/locales/bootstrap-datetimepicker.fr.js') }}"></script>
<script src="{{ asset('js/jquery-datepicker-addicons.js') }}"></script>
<script type="text/javascript">
(function($) {
$(document).ready(function(){
$(".datepickeryearmonthday").datetimepicker({
pickerPosition: "bottom-right",
language: 'fr',
weekStart: 1, // commencer avec le lundi
// daysOfWeekDisabled: '0,6', // rendre insélectionnable les samedi et dimanche
startView: 3, // démarrer avec la vue d'une année avec ses mois
format: 'yyyy-mm-dd',
minView: 2,
autoclose: true,
});
$(".datestimepicker").addicons();
});
})(jQuery);
</script>

Charger les css

<link href="{{ asset('bootstrap-3.3.7-dist/css/bootstrap.css') }}" rel="stylesheet" />
<link href="{{ asset('bootstrap-datetimepicker-master/css/bootstrap-datetimepicker.css') }}" rel="stylesheet" />

Paramétrer l'entité

Correspondance dans l'entité src > Sofictif > StretchingBundle > Entity > Position.php :

/**
 * @ORM\Column(name="datestart", type="date", nullable=true)
 */
private $datestart;

Gérer le formulaire

Dans src > Sofictif > StretchingBundle > Form > PositionType.php :

use Symfony\Component\Form\Extension\Core\Type\DateType;
$builder->add('datestart', DateType::class, array(
'required' => false,
'label' => 'Début de l\'événement',
'attr' => array('class' => 'datepickeryearmonthday'),
'widget' => 'single_text',
'format' => 'yyyy-MM-dd',
));

Symfony 3 > ConsoleBundle

Pour utiliser la console sur un hébergement mutualisé qui n'offre pas d'accès SSH pour utiliser, installer CoreSphereConsoleBundle qui permet d'utiliser les commandes depuis le navigateur.

Liens

https://packagist.org/packages/coresphere/console-bundle
https://github.com/CoreSphere/ConsoleBundle

Déclarer la dépendance dans le fichier composer.json

Ce fichier au premier niveau de l'application répertorie la liste des bibliothèques dont le projet dépend.

Préciser dans "require" la version de la librairie externe :

"require": {
"coresphere/console-bundle": "~0.4",
},

Installer le dossier de cette bibliothèques et ceux de ses dépendances dans le dossier "vendor"

php composer.phar require coresphere/console-bundle

Enregistrer le bundle dans l'environnement de développement du Kernel

Ajouter dans app/AppKernel.php :

if (in_array($this->getEnvironment(), ['dev', 'test'], true)) {
...
$bundles[] = new CoreSphere\ConsoleBundle\CoreSphereConsoleBundle();
}

Composer a donné à Symfony les informations de namespaces pour l'autoload

Enregistrer les routes

Dans le fichier app/config/routing_dev.yml (pas dans routing.yml, car la console ne doit être accessible qu'en mode dev).

coresphere_console:     resource: .     type: extra

Installer les ressources dans le dossier web

Rendre disponibles les nouveaux fichiers JS et CSS du bundle
Charger les fichiers CSS, copier les fichiers statiques des bundles dans web (utiliser --symlink pour des liens symboliques à la place de copies)

php bin/console assets:install

Mettre à jour cette bibliothèque

php composer.phar update coresphere/console-bundle

Utiliser la console depuis le navigateur

Ne pas mettre "php bin/console"

http://localhost/site_stretching/web/app_dev.php/_console

Vider le cache depuis la console du navigateur

cache:clear cache:clear --env=prod

Mettre à jour la base de données après modification des entités depuis la console du navigateur

doctrine:schema:update --dump-sql doctrine:schema:update --force

Symfony 3 > Url

Masquer web/ de l'url

Placer un fichier .htaccess à la racine du site dans lequel il y a :

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ web/$1 [QSA,L]
</IfModule>

Ne fonctionne pas en local mais sur serveur, une fois les caches bien vidés.

Symfony 3 > Déploiement sur le serveur

Migrer la base de données

Dans le fichier app/config/parameters.yml, adapter les valeurs des paramètres "database_name", "database_user" et "database_password" pour pouvoir accéder au phpMyAdmin du serveur.

Solution 1 : exporter la base de données depuis http://localhost/phpmyadmin/ dans un fichier avec un format .sql
Puis importer ce même fichier dans le phpMyAdmin du serveur (dans lequel on a préalablement créé une base de données du même nom vide)

Solution 2 : créer la base de données renseignée dans le fichier parameters.yml, en exécutant la commande :

php bin/console doctrine:database:create

Puis la remplir avec les tables correspondant aux entités :

php bin/console doctrine:schema:update --force

Vérifier la configuration de Php sur le serveur

Envoyer un fichier phpinfo.php (contenant la fonction phpinfo(); pour vérifier que JSON, Ctype, Sqlite3, PDO et le mode rewrite sont bien activés, que le Php.ini a bien le paramètre date.timezone défini à Europe/Paris

Mises à jour de Composer et des dépendances Vendor

php composer.phar self-update
php composer.phar update
php composer.phar install --optimize-autoloader

L'option --optimize-autoloader rend l'autoloader de Composer plus performant en construisant une map

Vérifier la sécurité des dépendances

Solution 1

Envoyer manuellement le fichier "composer.lock" sur l'interface en ligne security.sensiolabs.org
composer.lock contient tous les numéros des versions des dépendances que j'ai installées en local
Si le message suivant s'affiche : "Great! etc.", les dépendances ne contiennent pas de faille de sécurité : on peut continuer.

Solution 2

php bin/console security:check

Si le message "No packages have know vulnerabilities" apparaît, on peut continuer.

Si une dépendance a une faille connue, la plupart du temps, mettre à jour la bibliothèque dans une version plus récente résoudra le problème.

Installer les ressources dans le dossier web

Rendre disponibles les nouveaux fichiers JS et CSS du bundle
Charger les fichiers CSS, copier les fichiers statiques des bundles dans web (utiliser --symlink pour des liens symboliques à la place de copies)

php bin/console assets:install

Tester l'environnement de production

Activer le mode debugger pour la partie production : modifier le fichier web/app.php en définissant le deuxième argument de AppKernel à true :

$kernel = new AppKernel('prod', true);

Cela permet d'afficher les erreurs de cet environnement à l'écran.
Tester en utilisant le contrôleur frontal app.php (sans app_dev.php dans l'url) :

http://localhost/site_stretching/web/

Si tout est ok, remettre à false : les erreurs sont à nouveau répertoriées dans le fichier var/logs/prod. Ce sont elles qui'il faut consulter en cas de soucis sur le site en production.

Vider le cache de l'application

Vider le cache de l'environnement de développement

php bin/console cache:clear

Vider le cache de l'environnement de production

php bin/console cache:clear --env=prod

Puis supprimer physiquement tout le contenu des dossiers du cache (la commandecache:clearne fait pas que supprimer le cache, elle le reconstruit en partie).

Points obligatoires qu'il faut que votre serveur respecte pour pouvoir faire tourner Symfony

- La version de PHP doit être supérieure ou égale à PHP 5.5.9
- L'extension SQLite 3 doit être activée
- L'extension JSON doit être activée
- L'extension Ctype doit être activée
- Le paramètre date.timezone doit être défini dans le php.ini

Vérifier la compatibilité de Symfony sur le serveur

Commenter les lignes du fichier web/config.php :

// if (!in_array(@$_SERVER['REMOTE_ADDR'], array(
// '127.0.0.1',
// '::1',
// ))) {
// header('HTTP/1.0 403 Forbidden');
// exit('This script is only accessible from localhost.');
// }

L'envoyer sur le serveur par Ftp et allez voir :

http://www.crdp-lyon.fr/stretching/web/config.php

S'il n'y a pas de partie « Major Problems », le serveur est compatible avec Symfony, décommenter et renvoyer le fichier.

Installer un accélérateur APC sur le serveur

Il permet de booster les performances de l'application en production, obtenir des temps d'exécution plus rapides.
Il faut dé-commenter la ligne extension=Php_apc.dll dans le Php.ini et ajouter [APC] apc.enabled=1 à la fin de ce même fichier

S'autoriser l'accès à l'environnement de développement sur le serveur

Pour exécuter les commandes Symfony, notamment celles pour créer la base de données

http://www.crdp-lyon.fr/stretching/web/app_dev.php

Ce message apparaît : "You are not allowed to access this file. Check app_dev.php for more information."
Dans le fichier web/app_dev.php, ne pas supprimer la condition (car on aura besoin d'accéder à l'environnement de développement ultérieurement), mais compléter la condition avec notre adresse IP (www.whatismyip.com)

if (!in_array(@$_SERVER['REMOTE_ADDR'], array(
'127.0.0.1',
'::1',
'193.49.39.141'
))) {
header('HTTP/1.0 403 Forbidden');
exit('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.');
}

Envoyer à nouveau le fichier app_dev.php par Ftp et verifier :

http://www.crdp-lyon.fr/stretching/web/app_dev.php

Suppimer web/ des Url

Pour avoir http://stretching.crdp-lyon.fr/ au lieu de http://stretching.crdplyon.fr/web/
Utiliser un VirtualHost (domaine virtuel) pour indiquer à Apache de créer un raccourci
http://preac.crdplyon.fr/ pointe directement vers le répertoire preac/web

Envoyer les fichiers sur le serveur

Possible avec un client FTP (Filezilla)

Donner les permissions en écriture du cache, des logs, et du dossier upload

Les répertoires concernés sont var/cache, var/log, web/uploads

Installer les dépendances dans le dossier vendor

Vérifier que les deux fichiers composer.json et composer.lock sont bien présents au premier niveau sur le serveur
Installer les dépendances sur le serveur avec les mêmes versions que celles en local (composer.lock contient tous les numéros des versions installée)

php composer.phar install

Dernière vérifications

1. Tout fonctionne correctement dans l'environnement de production
2. L'accès à l'environnement de développement sur le serveur est bien inaccessible à tous