@ -1,3 +0,0 @@ | |||||
body { | |||||
background-color: skyblue; | |||||
} |
@ -0,0 +1,8 @@ | |||||
version: '3' | |||||
services: | |||||
###> doctrine/doctrine-bundle ### | |||||
database: | |||||
ports: | |||||
- "5432" | |||||
###< doctrine/doctrine-bundle ### |
@ -0,0 +1,26 @@ | |||||
version: '3' | |||||
services: | |||||
###> doctrine/doctrine-bundle ### | |||||
database: | |||||
image: postgres:${POSTGRES_VERSION:-16}-alpine | |||||
environment: | |||||
POSTGRES_DB: ${POSTGRES_DB:-app} | |||||
# You should definitely change the password in production | |||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-!ChangeMe!} | |||||
POSTGRES_USER: ${POSTGRES_USER:-app} | |||||
healthcheck: | |||||
test: ["CMD", "pg_isready", "-d", "${POSTGRES_DB:-app}", "-U", "${POSTGRES_USER:-app}"] | |||||
timeout: 5s | |||||
retries: 5 | |||||
start_period: 60s | |||||
volumes: | |||||
- database_data:/var/lib/postgresql/data:rw | |||||
# You may use a bind-mounted host directory instead, so that it is harder to accidentally remove the volume and lose all your data! | |||||
# - ./docker/db/data:/var/lib/postgresql/data:rw | |||||
###< doctrine/doctrine-bundle ### | |||||
volumes: | |||||
###> doctrine/doctrine-bundle ### | |||||
database_data: | |||||
###< doctrine/doctrine-bundle ### |
@ -0,0 +1,52 @@ | |||||
doctrine: | |||||
dbal: | |||||
url: '%env(resolve:DATABASE_URL)%' | |||||
# IMPORTANT: You MUST configure your server version, | |||||
# either here or in the DATABASE_URL env var (see .env file) | |||||
#server_version: '16' | |||||
profiling_collect_backtrace: '%kernel.debug%' | |||||
use_savepoints: true | |||||
orm: | |||||
auto_generate_proxy_classes: true | |||||
enable_lazy_ghost_objects: true | |||||
report_fields_where_declared: true | |||||
validate_xml_mapping: true | |||||
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware | |||||
auto_mapping: true | |||||
mappings: | |||||
App: | |||||
type: attribute | |||||
is_bundle: false | |||||
dir: '%kernel.project_dir%/src/Entity' | |||||
prefix: 'App\Entity' | |||||
alias: App | |||||
controller_resolver: | |||||
auto_mapping: false | |||||
when@test: | |||||
doctrine: | |||||
dbal: | |||||
# "TEST_TOKEN" is typically set by ParaTest | |||||
dbname_suffix: '_test%env(default::TEST_TOKEN)%' | |||||
when@prod: | |||||
doctrine: | |||||
orm: | |||||
auto_generate_proxy_classes: false | |||||
proxy_dir: '%kernel.build_dir%/doctrine/orm/Proxies' | |||||
query_cache_driver: | |||||
type: pool | |||||
pool: doctrine.system_cache_pool | |||||
result_cache_driver: | |||||
type: pool | |||||
pool: doctrine.result_cache_pool | |||||
framework: | |||||
cache: | |||||
pools: | |||||
doctrine.result_cache_pool: | |||||
adapter: cache.app | |||||
doctrine.system_cache_pool: | |||||
adapter: cache.system |
@ -0,0 +1,6 @@ | |||||
doctrine_migrations: | |||||
migrations_paths: | |||||
# namespace is arbitrary but should be different from App\Migrations | |||||
# as migrations classes should NOT be autoloaded | |||||
'DoctrineMigrations': '%kernel.project_dir%/migrations' | |||||
enable_profiler: false |
@ -0,0 +1,7 @@ | |||||
# Read the documentation: https://symfony.com/doc/current/bundles/StofDoctrineExtensionsBundle/index.html | |||||
# See the official DoctrineExtensions documentation for more details: https://github.com/doctrine-extensions/DoctrineExtensions/tree/main/doc | |||||
stof_doctrine_extensions: | |||||
default_locale: fr_FR | |||||
orm: | |||||
default: | |||||
sluggable: true |
@ -1,7 +1,11 @@ | |||||
twig: | twig: | ||||
file_name_pattern: '*.twig' | file_name_pattern: '*.twig' | ||||
form_themes: ['bootstrap_5_layout.html.twig'] | |||||
globals: | globals: | ||||
title: Gestionnaire de tâches simple | title: Gestionnaire de tâches simple | ||||
menu: | |||||
header: | |||||
- { route: 'app_project', label: 'Projets' } | |||||
when@test: | when@test: | ||||
twig: | twig: | ||||
@ -0,0 +1,11 @@ | |||||
framework: | |||||
validation: | |||||
# Enables validator auto-mapping support. | |||||
# For instance, basic validation constraints will be inferred from Doctrine's metadata. | |||||
#auto_mapping: | |||||
# App\Entity\: [] | |||||
when@test: | |||||
framework: | |||||
validation: | |||||
not_compromised_password: false |
@ -0,0 +1,17 @@ | |||||
when@dev: | |||||
web_profiler: | |||||
toolbar: true | |||||
intercept_redirects: false | |||||
framework: | |||||
profiler: | |||||
only_exceptions: false | |||||
collect_serializer_data: true | |||||
when@test: | |||||
web_profiler: | |||||
toolbar: false | |||||
intercept_redirects: false | |||||
framework: | |||||
profiler: { collect: false } |
@ -0,0 +1,8 @@ | |||||
when@dev: | |||||
web_profiler_wdt: | |||||
resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml' | |||||
prefix: /_wdt | |||||
web_profiler_profiler: | |||||
resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml' | |||||
prefix: /_profiler |
@ -0,0 +1,31 @@ | |||||
<?php | |||||
declare(strict_types=1); | |||||
namespace DoctrineMigrations; | |||||
use Doctrine\DBAL\Schema\Schema; | |||||
use Doctrine\Migrations\AbstractMigration; | |||||
/** | |||||
* Auto-generated Migration: Please modify to your needs! | |||||
*/ | |||||
final class Version20240720132139 extends AbstractMigration | |||||
{ | |||||
public function getDescription(): string | |||||
{ | |||||
return ''; | |||||
} | |||||
public function up(Schema $schema): void | |||||
{ | |||||
// this up() migration is auto-generated, please modify it to your needs | |||||
$this->addSql('CREATE TABLE project (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name VARCHAR(255) NOT NULL, description CLOB DEFAULT NULL)'); | |||||
} | |||||
public function down(Schema $schema): void | |||||
{ | |||||
// this down() migration is auto-generated, please modify it to your needs | |||||
$this->addSql('DROP TABLE project'); | |||||
} | |||||
} |
@ -0,0 +1,40 @@ | |||||
<?php | |||||
declare(strict_types=1); | |||||
namespace DoctrineMigrations; | |||||
use Doctrine\DBAL\Schema\Schema; | |||||
use Doctrine\Migrations\AbstractMigration; | |||||
/** | |||||
* Auto-generated Migration: Please modify to your needs! | |||||
*/ | |||||
final class Version20240720143743 extends AbstractMigration | |||||
{ | |||||
public function getDescription(): string | |||||
{ | |||||
return ''; | |||||
} | |||||
public function up(Schema $schema): void | |||||
{ | |||||
// this up() migration is auto-generated, please modify it to your needs | |||||
$this->addSql('CREATE TEMPORARY TABLE __temp__project AS SELECT id, name, description FROM project'); | |||||
$this->addSql('DROP TABLE project'); | |||||
$this->addSql('CREATE TABLE project (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name VARCHAR(255) NOT NULL, description CLOB DEFAULT NULL, slug VARCHAR(255) NOT NULL)'); | |||||
$this->addSql('INSERT INTO project (id, name, description) SELECT id, name, description FROM __temp__project'); | |||||
$this->addSql('DROP TABLE __temp__project'); | |||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_2FB3D0EE989D9B62 ON project (slug)'); | |||||
} | |||||
public function down(Schema $schema): void | |||||
{ | |||||
// this down() migration is auto-generated, please modify it to your needs | |||||
$this->addSql('CREATE TEMPORARY TABLE __temp__project AS SELECT id, name, description FROM project'); | |||||
$this->addSql('DROP TABLE project'); | |||||
$this->addSql('CREATE TABLE project (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name VARCHAR(255) NOT NULL, description CLOB DEFAULT NULL)'); | |||||
$this->addSql('INSERT INTO project (id, name, description) SELECT id, name, description FROM __temp__project'); | |||||
$this->addSql('DROP TABLE __temp__project'); | |||||
} | |||||
} |
@ -0,0 +1,173 @@ | |||||
<?php | |||||
namespace App\Controller; | |||||
use App\Entity\Project; | |||||
use App\Form\ProjectType; | |||||
use Doctrine\ORM\EntityManagerInterface; | |||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; | |||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType; | |||||
use Symfony\Component\HttpFoundation\Request; | |||||
use Symfony\Component\HttpFoundation\Response; | |||||
use Symfony\Component\Routing\Attribute\Route; | |||||
#[Route('/project')] | |||||
class ProjectController extends AbstractController | |||||
{ | |||||
#[Route('/', name: 'app_project')] | |||||
public function index(EntityManagerInterface $entityManager): Response | |||||
{ | |||||
$repository = $entityManager->getRepository(Project::class); | |||||
$projects = $repository->findAll(); | |||||
$this->addFlash( | |||||
'info', | |||||
sprintf('%s projet%s trouvé%s', count($projects), (count($projects) > 1 ? 's' : ''), (count($projects) > 1 ? 's' : '')) | |||||
); | |||||
return $this->render('project/index.html.twig', [ | |||||
'projects' => $projects, | |||||
]); | |||||
} | |||||
#[Route('/create', name: 'app_project_create')] | |||||
public function create(Request $request, EntityManagerInterface $entityManager): Response | |||||
{ | |||||
$project = new Project(); | |||||
$createForm = $this->createForm(ProjectType::class, $project); | |||||
$createForm->add('submit', SubmitType::class, [ | |||||
'label' => 'Créer', | |||||
]); | |||||
$createForm->handleRequest($request); | |||||
if ($createForm->isSubmitted() and $createForm->isValid()) { | |||||
$project = $createForm->getData(); | |||||
try { | |||||
$entityManager->persist($project); | |||||
$entityManager->flush(); | |||||
$this->addFlash( | |||||
'success', | |||||
'Projet créé !' | |||||
); | |||||
return $this->redirectToRoute('app_project'); | |||||
} catch (\Exception $exception) { | |||||
$this->addFlash( | |||||
'danger', | |||||
'Impossible de créer le projet !' | |||||
); | |||||
} | |||||
} | |||||
return $this->render('project/create.html.twig', [ | |||||
'create_form' => $createForm, | |||||
]); | |||||
} | |||||
#[Route('/show/{slug}', name: 'app_project_show')] | |||||
public function show(EntityManagerInterface $entityManager, $slug): Response | |||||
{ | |||||
$repository = $entityManager->getRepository(Project::class); | |||||
$project = $repository->findOneBySlug($slug); | |||||
if (!$project) { | |||||
$this->addFlash( | |||||
'warning', | |||||
'Projet non trouvé !' | |||||
); | |||||
return $this->redirectToRoute('app_project'); | |||||
} | |||||
return $this->render('project/show.html.twig', [ | |||||
'project' => $project, | |||||
]); | |||||
} | |||||
#[Route('/update/{slug}', name: 'app_project_update')] | |||||
public function update(Request $request, EntityManagerInterface $entityManager, $slug): Response | |||||
{ | |||||
$repository = $entityManager->getRepository(Project::class); | |||||
$project = $repository->findOneBySlug($slug); | |||||
if (!$project) { | |||||
$this->addFlash( | |||||
'warning', | |||||
'Projet non trouvé !' | |||||
); | |||||
return $this->redirectToRoute('app_project'); | |||||
} | |||||
$updateForm = $this->createForm(ProjectType::class, $project); | |||||
$updateForm->add('submit', SubmitType::class, [ | |||||
'label' => 'Modifier', | |||||
]); | |||||
$updateForm->handleRequest($request); | |||||
if ($updateForm->isSubmitted() and $updateForm->isValid()) { | |||||
$project = $updateForm->getData(); | |||||
try { | |||||
$entityManager->persist($project); | |||||
$entityManager->flush(); | |||||
$this->addFlash( | |||||
'success', | |||||
'Projet modifié !' | |||||
); | |||||
return $this->redirectToRoute('app_project'); | |||||
} catch (\Exception $exception) { | |||||
$this->addFlash( | |||||
'danger', | |||||
'Impossible de mopdifier le projet !' | |||||
); | |||||
} | |||||
} | |||||
return $this->render('project/update.html.twig', [ | |||||
'project' => $project, | |||||
'update_form' => $updateForm, | |||||
]); | |||||
} | |||||
#[Route('/remove/{slug}', name: 'app_project_remove')] | |||||
public function remove(EntityManagerInterface $entityManager, $slug): Response | |||||
{ | |||||
$repository = $entityManager->getRepository(Project::class); | |||||
$project = $repository->findOneBySlug($slug); | |||||
if (!$project) { | |||||
$this->addFlash( | |||||
'warning', | |||||
'Projet non trouvé !' | |||||
); | |||||
return $this->redirectToRoute('app_project'); | |||||
} | |||||
try { | |||||
$entityManager->remove($project); | |||||
$entityManager->flush(); | |||||
$this->addFlash( | |||||
'success', | |||||
'Projet supprimé !' | |||||
); | |||||
return $this->redirectToRoute('app_project'); | |||||
} catch (\Exception $exception) { | |||||
$this->addFlash( | |||||
'danger', | |||||
'Impossible de supprimer le projet !' | |||||
); | |||||
} | |||||
return $this->redirectToRoute('app_project'); | |||||
} | |||||
} |
@ -0,0 +1,62 @@ | |||||
<?php | |||||
namespace App\Entity; | |||||
use App\Repository\ProjectRepository; | |||||
use Doctrine\DBAL\Types\Types; | |||||
use Doctrine\ORM\Mapping as ORM; | |||||
use Gedmo\Mapping\Annotation as Gedmo; | |||||
#[ORM\Entity(repositoryClass: ProjectRepository::class)] | |||||
class Project | |||||
{ | |||||
#[ORM\Id] | |||||
#[ORM\GeneratedValue] | |||||
#[ORM\Column] | |||||
private ?int $id = null; | |||||
#[ORM\Column(length: 255)] | |||||
private ?string $name = null; | |||||
#[ORM\Column(type: Types::TEXT, nullable: true)] | |||||
private ?string $description = null; | |||||
#[ORM\Column(length: 255, unique: true)] | |||||
#[Gedmo\Slug(fields: ['name'])] | |||||
private ?string $slug = null; | |||||
public function getId(): ?int | |||||
{ | |||||
return $this->id; | |||||
} | |||||
public function getName(): ?string | |||||
{ | |||||
return $this->name; | |||||
} | |||||
public function setName(string $name): static | |||||
{ | |||||
$this->name = $name; | |||||
return $this; | |||||
} | |||||
public function getDescription(): ?string | |||||
{ | |||||
return $this->description; | |||||
} | |||||
public function setDescription(?string $description): static | |||||
{ | |||||
$this->description = $description; | |||||
return $this; | |||||
} | |||||
public function getSlug(): ?string | |||||
{ | |||||
return $this->slug; | |||||
} | |||||
} |
@ -0,0 +1,31 @@ | |||||
<?php | |||||
namespace App\Form; | |||||
use App\Entity\Project; | |||||
use Symfony\Component\Form\AbstractType; | |||||
use Symfony\Component\Form\FormBuilderInterface; | |||||
use Symfony\Component\OptionsResolver\OptionsResolver; | |||||
class ProjectType extends AbstractType | |||||
{ | |||||
public function buildForm(FormBuilderInterface $builder, array $options): void | |||||
{ | |||||
$builder | |||||
->add('name', null, [ | |||||
'label' => 'Nom', | |||||
]) | |||||
->add('description', null, [ | |||||
'label' => 'Description', | |||||
'help' => 'On peut mettre du Markdown ici…', | |||||
]) | |||||
; | |||||
} | |||||
public function configureOptions(OptionsResolver $resolver): void | |||||
{ | |||||
$resolver->setDefaults([ | |||||
'data_class' => Project::class, | |||||
]); | |||||
} | |||||
} |
@ -0,0 +1,43 @@ | |||||
<?php | |||||
namespace App\Repository; | |||||
use App\Entity\Project; | |||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; | |||||
use Doctrine\Persistence\ManagerRegistry; | |||||
/** | |||||
* @extends ServiceEntityRepository<Project> | |||||
*/ | |||||
class ProjectRepository extends ServiceEntityRepository | |||||
{ | |||||
public function __construct(ManagerRegistry $registry) | |||||
{ | |||||
parent::__construct($registry, Project::class); | |||||
} | |||||
// /** | |||||
// * @return Project[] Returns an array of Project objects | |||||
// */ | |||||
// public function findByExampleField($value): array | |||||
// { | |||||
// return $this->createQueryBuilder('p') | |||||
// ->andWhere('p.exampleField = :val') | |||||
// ->setParameter('val', $value) | |||||
// ->orderBy('p.id', 'ASC') | |||||
// ->setMaxResults(10) | |||||
// ->getQuery() | |||||
// ->getResult() | |||||
// ; | |||||
// } | |||||
// public function findOneBySomeField($value): ?Project | |||||
// { | |||||
// return $this->createQueryBuilder('p') | |||||
// ->andWhere('p.exampleField = :val') | |||||
// ->setParameter('val', $value) | |||||
// ->getQuery() | |||||
// ->getOneOrNullResult() | |||||
// ; | |||||
// } | |||||
} |
@ -0,0 +1,7 @@ | |||||
<div class="container"> | |||||
<div class="row bg-body-tertiary border-top p-2"> | |||||
<div class="col"> | |||||
<p class="text-muted mb-0"></p> | |||||
</div> | |||||
</div> | |||||
</div> |
@ -1,37 +1,18 @@ | |||||
<header> | <header> | ||||
<nav class="navbar navbar-expand-lg bg-body-tertiary"> | <nav class="navbar navbar-expand-lg bg-body-tertiary"> | ||||
<div class="container-fluid"> | <div class="container-fluid"> | ||||
<a class="navbar-brand" href="#">Navbar</a> | |||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> | |||||
<a class="navbar-brand" href="{{ path('app_home') }}">{{ title }}</a> | |||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbar" aria-controls="navbar" aria-expanded="false" aria-label="Toggle navigation"> | |||||
<span class="navbar-toggler-icon"></span> | <span class="navbar-toggler-icon"></span> | ||||
</button> | </button> | ||||
<div class="collapse navbar-collapse" id="navbarSupportedContent"> | |||||
<div class="collapse navbar-collapse" id="navbar"> | |||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0"> | <ul class="navbar-nav me-auto mb-2 mb-lg-0"> | ||||
{% for item in menu.header %} | |||||
<li class="nav-item"> | <li class="nav-item"> | ||||
<a class="nav-link active" aria-current="page" href="#">Home</a> | |||||
</li> | |||||
<li class="nav-item"> | |||||
<a class="nav-link" href="#">Link</a> | |||||
</li> | |||||
<li class="nav-item dropdown"> | |||||
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false"> | |||||
Dropdown | |||||
</a> | |||||
<ul class="dropdown-menu"> | |||||
<li><a class="dropdown-item" href="#">Action</a></li> | |||||
<li><a class="dropdown-item" href="#">Another action</a></li> | |||||
<li><hr class="dropdown-divider"></li> | |||||
<li><a class="dropdown-item" href="#">Something else here</a></li> | |||||
</ul> | |||||
</li> | |||||
<li class="nav-item"> | |||||
<a class="nav-link disabled" aria-disabled="true">Disabled</a> | |||||
<a {% if app.request.attributes.get('_route') == item.route %}class="nav-link active" aria-current="page"{% else %}class="nav-link"{% endif %} href="{{ path(item.route) }}">{{ item.label }}</a> | |||||
</li> | </li> | ||||
{% endfor %} | |||||
</ul> | </ul> | ||||
<form class="d-flex" role="search"> | |||||
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search"> | |||||
<button class="btn btn-outline-success" type="submit">Search</button> | |||||
</form> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</nav> | </nav> | ||||
@ -1 +0,0 @@ | |||||
{% extends 'base.html.twig' %} |
@ -1,5 +1,11 @@ | |||||
{% extends 'home/base.html.twig' %} | |||||
{% extends 'base.html.twig' %} | |||||
{% block main %} | {% block main %} | ||||
home | |||||
<div class="container"> | |||||
<div class="row"> | |||||
<div class="col"> | |||||
ici la page d’accueil | |||||
</div> | |||||
</div> | |||||
</div> | |||||
{% endblock %} | {% endblock %} |
@ -0,0 +1,12 @@ | |||||
{% extends 'base.html.twig' %} | |||||
{% block breadcrumb %} | |||||
<li class="breadcrumb-item"><a href="{{ path('app_project') }}">Projets</a></li> | |||||
<li class="breadcrumb-item"><a href="{{ path('app_project_create') }}">Créer un nouveau projet</a></li> | |||||
{% endblock %} | |||||
{% block page_title %}Créer un nouveau projet{% endblock %} | |||||
{% block page_content %} | |||||
{{ form(create_form) }} | |||||
{% endblock %} |
@ -0,0 +1,31 @@ | |||||
{% extends 'base.html.twig' %} | |||||
{% block breadcrumb %} | |||||
<li class="breadcrumb-item"><a href="{{ path('app_project') }}">Projets</a></li> | |||||
{% endblock %} | |||||
{% block page_title %}Projets{% endblock %} | |||||
{% block page_content %} | |||||
<div class="row"> | |||||
<div class="col mb-3"> | |||||
<a href="{{ path('app_project_create') }}" class="btn btn-primary">Créer un projet</a> | |||||
</div> | |||||
</div> | |||||
{% if projects is not empty %} | |||||
<div class="row"> | |||||
{% for project in projects %} | |||||
<div class="col col-md-4 mb-3"> | |||||
<div class="card h-100"> | |||||
<div class="card-body"> | |||||
<h2 class="card-title">{{ project.name }}</h2> | |||||
{% if project.description %}<p class="card-text">{{ project.description|markdown_to_html }}</p>{% endif %} | |||||
<a href="{{ path('app_project_show', {'slug': project.slug}) }}" class="btn btn-primary">Voir</a> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
{% endfor %} | |||||
</div> | |||||
{% endif %} | |||||
{% endblock %} |
@ -0,0 +1,21 @@ | |||||
{% extends 'base.html.twig' %} | |||||
{% block breadcrumb %} | |||||
<li class="breadcrumb-item"><a href="{{ path('app_project') }}">Projets</a></li> | |||||
<li class="breadcrumb-item"><a href="{{ path('app_project_show', {'slug': project.slug}) }}">Projet {{ project.name }}</a></li> | |||||
{% endblock %} | |||||
{% block page_title %}Projet {{ project.name }}{% endblock %} | |||||
{% block page_content %} | |||||
<div class="row"> | |||||
<div class="col mb-3"> | |||||
<a href="{{ path('app_project_update', {'slug': project.slug}) }}" class="btn btn-primary">Modifier le projet</a> | |||||
<a href="{{ path('app_project_remove', {'slug': project.slug}) }}" class="btn btn-primary">Supprimer le projet</a> | |||||
</div> | |||||
</div> | |||||
<div class="row"> | |||||
<div class="col mb-3 lead">{{ project.description|markdown_to_html }}</div> | |||||
</div> | |||||
{% endblock %} |
@ -0,0 +1,12 @@ | |||||
{% extends 'base.html.twig' %} | |||||
{% block breadcrumb %} | |||||
<li class="breadcrumb-item"><a href="{{ path('app_project') }}">Projets</a></li> | |||||
<li class="breadcrumb-item"><a href="{{ path('app_project_create') }}">Modifier le projet {{ project.name }}</a></li> | |||||
{% endblock %} | |||||
{% block page_title %}Modifier le projet {{ project.name }}{% endblock %} | |||||
{% block page_content %} | |||||
{{ form(update_form) }} | |||||
{% endblock %} |