diff --git a/Controller/WikiController.php b/Controller/WikiController.php
new file mode 100644
index 0000000..9f3a1f6
--- /dev/null
+++ b/Controller/WikiController.php
@@ -0,0 +1,117 @@
+render('@wiki_bundle/wiki/index.html.twig', ['wikis' => $wikiRepository->findAll()]);
+ }
+
+ /**
+ * @Route("/add", name="wiki_add", methods="GET|POST")
+ */
+ public function AddAction(Request $request, WikiEventService $wikiEventService): Response
+ {
+ $wiki = new Wiki();
+
+ return $this->getEditForm($request, $wiki, $wikiEventService);
+ }
+
+ /**
+ * @Route("/{wikiName}/edit", name="wiki_edit", methods="GET|POST")
+ * @ParamConverter("wiki", options={"mapping"={"wikiName"="name"}})
+ */
+ public function editAction(Request $request, Wiki $wiki, WikiEventService $wikiEventService): Response
+ {
+ return $this->getEditForm($request, $wiki, $wikiEventService);
+ }
+
+ /**
+ * @Route("/{wikiName}/delete", name="wiki_delete", methods="GET")
+ * @ParamConverter("wiki", options={"mapping"={"wikiName"="name"}})
+ */
+ public function deleteAction(Request $request, Wiki $wiki, WikiEventService $wikiEventService): Response
+ {
+ if (count($wiki->getWikiPages())) {
+ $this->addFlash('error', 'The wiki cannot be deleted because of having a wiki-page.');
+ } else {
+ $wikiEventService->createEvent(
+ 'wiki.deleted',
+ $wiki->getId(),
+ json_encode([
+ 'deletedAt' => time(),
+ 'deletedBy' => $this->getUser()->getUsername(),
+ 'name' => $wiki->getName(),
+ ])
+ );
+ $em = $this->getDoctrine()->getManager();
+ $em->remove($wiki);
+ $em->flush();
+ }
+
+ return $this->redirectToRoute('wiki_index');
+ }
+
+ protected function getEditForm(Request $request, Wiki $wiki, WikiEventService $wikiEventService)
+ {
+ $form = $this->createForm(WikiType::class, $wiki);
+ $form->handleRequest($request);
+
+ $add = !$wiki->getid();
+
+ if ($form->isSubmitted() && $form->isValid()) {
+ $em = $this->getDoctrine()->getManager();
+ $em->persist($wiki);
+ $em->flush();
+
+ if ($add) {
+ $wikiEventService->createEvent(
+ 'wiki.created',
+ $wiki->getId(),
+ json_encode([
+ 'createdAt' => time(),
+ 'createdBy' => $this->getUser()->getUsername(),
+ 'name' => $wiki->getName(),
+ 'description' => $wiki->getDescription(),
+ ])
+ );
+ } else {
+ $wikiEventService->createEvent(
+ 'wiki.updated',
+ $wiki->getId(),
+ json_encode([
+ 'updatedAt' => time(),
+ 'updatedBy' => $this->getUser()->getUsername(),
+ 'name' => $wiki->getName(),
+ 'description' => $wiki->getDescription(),
+ ])
+ );
+ }
+
+ return $this->redirectToRoute('wiki_index');
+ }
+
+ return $this->render('@wiki_bundle/wiki/edit.html.twig', [
+ 'wiki' => $wiki,
+ 'form' => $form->createView(),
+ ]);
+ }
+}
diff --git a/Controller/WikiEventController.php b/Controller/WikiEventController.php
new file mode 100644
index 0000000..b8b2566
--- /dev/null
+++ b/Controller/WikiEventController.php
@@ -0,0 +1,30 @@
+findOneByName($wikiName)) {
+ return $this->redirectToRoute('wiki_index');
+ }
+ $wikiEvents = $wikiEventRepository->findByWikiId($wiki->getId());
+
+ return $this->render('@wiki_bundle/wiki_event/index.html.twig', [
+ 'wikiEvents' => $wikiEvents,
+ 'wiki' => $wiki,
+ ]);
+ }
+}
diff --git a/Controller/WikiPageController.php b/Controller/WikiPageController.php
new file mode 100644
index 0000000..62b9286
--- /dev/null
+++ b/Controller/WikiPageController.php
@@ -0,0 +1,132 @@
+render('@wiki_bundle/wiki_page/index.html.twig', [
+ 'wikiPages' => $wikiPageRepository->findByWikiId($wiki->getId()),
+ 'wiki' => $wiki,
+ ]);
+ }
+
+ /**
+ * @Route("/pages/add", name="wiki_page_add", methods="GET|POST")
+ */
+ public function addAction(Request $request, Wiki $wiki, WikiEventService $wikiEventService): Response
+ {
+ $wikiPage = new WikiPage();
+ $wikiPage->setWiki($wiki);
+
+ return $this->getEditForm($request, $wikiPage, $wikiEventService);
+ }
+
+ /**
+ * @Route("/{pageName}", name="wiki_page_view", methods="GET")
+ * @ParamConverter("wikiPage", options={"mapping"={"pageName"="name"}})
+ */
+ public function viewAction(WikiPage $wikiPage): Response
+ {
+ return $this->render('@wiki_bundle/wiki_page/view.html.twig', ['wikiPage' => $wikiPage]);
+ }
+
+ /**
+ * @Route("/pages/{id}/edit", name="wiki_page_edit", methods="GET|POST")
+ */
+ public function editAction(Request $request, Wiki $wiki, WikiPage $wikiPage, WikiEventService $wikiEventService): Response
+ {
+ return $this->getEditForm($request, $wikiPage, $wikiEventService);
+ }
+
+ /**
+ * @Route("/pages/{id}/delete", name="wiki_page_delete", methods="GET")
+ */
+ public function deleteAction(Request $request, Wiki $wiki, WikiPage $wikiPage, WikiEventService $wikiEventService): Response
+ {
+ $wikiEventService->createEvent(
+ 'page.deleted',
+ $wikiPage->getWiki()->getId(),
+ json_encode([
+ 'deletedAt' => time(),
+ 'deletedBy' => $this->getUser()->getUsername(),
+ 'name' => $wikiPage->getName(),
+ ]),
+ $wikiPage->getId()
+ );
+
+ $em = $this->getDoctrine()->getManager();
+ $em->remove($wikiPage);
+ $em->flush();
+
+ return $this->redirectToRoute('wiki_page_index', [
+ 'wikiName' => $wiki->getName(),
+ ]);
+ }
+
+ protected function getEditForm($request, $wikiPage, WikiEventService $wikiEventService)
+ {
+ $form = $this->createForm(WikiPageType::class, $wikiPage);
+ $form->handleRequest($request);
+
+ $add = !$wikiPage->getId();
+
+ if ($form->isSubmitted() && $form->isValid()) {
+ $em = $this->getDoctrine()->getManager();
+ $em->persist($wikiPage);
+ $em->flush();
+
+ if ($add) {
+ $wikiEventService->createEvent(
+ 'page.created',
+ $wikiPage->getWiki()->getId(),
+ json_encode([
+ 'createdAt' => time(),
+ 'createdBy' => $this->getUser()->getUsername(),
+ 'name' => $wikiPage->getName(),
+ ]),
+ $wikiPage->getId()
+ );
+ } else {
+ $wikiEventService->createEvent(
+ 'page.updated',
+ $wikiPage->getWiki()->getId(),
+ json_encode([
+ 'updatedAt' => time(),
+ 'updatedBy' => $this->getUser()->getUsername(),
+ 'name' => $wikiPage->getName(),
+ ]),
+ $wikiPage->getId()
+ );
+ }
+
+ return $this->redirectToRoute('wiki_page_index', [
+ 'wikiName' => $wikiPage->getWiki()->getName(),
+ ]);
+ }
+
+ return $this->render('@wiki_bundle/wiki_page/edit.html.twig', [
+ 'wikiPage' => $wikiPage,
+ 'form' => $form->createView(),
+ ]);
+ }
+}
diff --git a/DependencyInjection/LinkorbWikiExtension.php b/DependencyInjection/LinkorbWikiExtension.php
new file mode 100644
index 0000000..c7cf6e4
--- /dev/null
+++ b/DependencyInjection/LinkorbWikiExtension.php
@@ -0,0 +1,21 @@
+load('services.xml');
+
+ $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
+ $loader->load('services.yaml');
+ }
+}
diff --git a/Entity/Wiki.php b/Entity/Wiki.php
new file mode 100644
index 0000000..7c068cc
--- /dev/null
+++ b/Entity/Wiki.php
@@ -0,0 +1,100 @@
+wikiPages = new ArrayCollection();
+ }
+
+ public function getId(): ?int
+ {
+ return $this->id;
+ }
+
+ public function getName(): ?string
+ {
+ return $this->name;
+ }
+
+ public function setName(string $name): self
+ {
+ $this->name = $name;
+
+ return $this;
+ }
+
+ public function getDescription(): ?string
+ {
+ return $this->description;
+ }
+
+ public function setDescription(string $description): self
+ {
+ $this->description = $description;
+
+ return $this;
+ }
+
+ /**
+ * @return Collection|WikiPage[]
+ */
+ public function getWikiPages(): Collection
+ {
+ return $this->wikiPages;
+ }
+
+ public function addWikiPage(WikiPage $wikiPage): self
+ {
+ if (!$this->wikiPages->contains($wikiPage)) {
+ $this->wikiPages[] = $wikiPage;
+ $wikiPage->setWiki($this);
+ }
+
+ return $this;
+ }
+
+ public function removeWikiPage(WikiPage $wikiPage): self
+ {
+ if ($this->wikiPages->contains($wikiPage)) {
+ $this->wikiPages->removeElement($wikiPage);
+ // set the owning side to null (unless already changed)
+ if ($wikiPage->getWiki() === $this) {
+ $wikiPage->setWiki(null);
+ }
+ }
+
+ return $this;
+ }
+}
diff --git a/Entity/WikiEvent.php b/Entity/WikiEvent.php
new file mode 100644
index 0000000..c6ced8a
--- /dev/null
+++ b/Entity/WikiEvent.php
@@ -0,0 +1,125 @@
+id;
+ }
+
+ public function getType(): ?string
+ {
+ return $this->type;
+ }
+
+ public function setType(string $type): self
+ {
+ $this->type = $type;
+
+ return $this;
+ }
+
+ public function getCreatedAt(): ?int
+ {
+ return $this->created_at;
+ }
+
+ public function setCreatedAt(int $created_at): self
+ {
+ $this->created_at = $created_at;
+
+ return $this;
+ }
+
+ public function getCreatedBy(): ?string
+ {
+ return $this->created_by;
+ }
+
+ public function setCreatedBy(string $created_by): self
+ {
+ $this->created_by = $created_by;
+
+ return $this;
+ }
+
+ public function getWikiPageId(): ?int
+ {
+ return $this->wiki_page_id;
+ }
+
+ public function setWikiPageId(?int $wiki_page_id): self
+ {
+ $this->wiki_page_id = $wiki_page_id;
+
+ return $this;
+ }
+
+ public function getData(): ?string
+ {
+ return $this->data;
+ }
+
+ public function setData(?string $data): self
+ {
+ $this->data = $data;
+
+ return $this;
+ }
+
+ public function getWikiId(): ?int
+ {
+ return $this->wiki_id;
+ }
+
+ public function setWikiId(?int $wiki_id): self
+ {
+ $this->wiki_id = $wiki_id;
+
+ return $this;
+ }
+}
diff --git a/Entity/WikiPage.php b/Entity/WikiPage.php
new file mode 100644
index 0000000..88fb2f6
--- /dev/null
+++ b/Entity/WikiPage.php
@@ -0,0 +1,92 @@
+id;
+ }
+
+ public function getWiki(): ?Wiki
+ {
+ return $this->wiki;
+ }
+
+ public function setWiki(?Wiki $wiki): self
+ {
+ $this->wiki = $wiki;
+
+ return $this;
+ }
+
+ public function getName(): ?string
+ {
+ return $this->name;
+ }
+
+ public function setName(string $name): self
+ {
+ $this->name = $name;
+
+ return $this;
+ }
+
+ public function getContent(): ?string
+ {
+ return $this->content;
+ }
+
+ public function setContent(?string $content): self
+ {
+ $this->content = $content;
+
+ return $this;
+ }
+
+ public function getData(): ?string
+ {
+ return $this->data;
+ }
+
+ public function setData(?string $data): self
+ {
+ $this->data = $data;
+
+ return $this;
+ }
+}
diff --git a/Form/WikiPageType.php b/Form/WikiPageType.php
new file mode 100644
index 0000000..77bb6d5
--- /dev/null
+++ b/Form/WikiPageType.php
@@ -0,0 +1,70 @@
+wikiPageRepository = $wikiPageRepository;
+ }
+
+ public function buildForm(FormBuilderInterface $builder, array $options)
+ {
+ $wikiPageRepository = $this->wikiPageRepository;
+ $entity = $options['data'];
+
+ $builder
+ ->add('name', TextType::class, [
+ 'required' => true,
+ 'trim' => true,
+ 'constraints' => [
+ new Assert\NotBlank(),
+ new CodeConstraint(),
+ new Assert\Callback(
+ function ($name, ExecutionContext $context) use ($wikiPageRepository, $entity) {
+ if ($findEntity = $wikiPageRepository->findOneByWikiIdAndName($entity->getWiki()->getId(), $name)) {
+ if ($findEntity->getId() != $entity->getId()) {
+ $context->addViolation('Name already exist');
+ }
+ }
+ }
+ ),
+ ],
+ ])
+ ->add('content', TextareaType::class, [
+ 'required' => false,
+ 'trim' => true,
+ ])
+ ->add('data', TextareaType::class, [
+ 'required' => false,
+ 'trim' => true,
+ 'attr' => [
+ 'class' => 'ace-editor',
+ 'data-mode' => 'yaml',
+ 'data-lines' => '10',
+ ],
+ ])
+ ;
+ }
+
+ public function configureOptions(OptionsResolver $resolver)
+ {
+ $resolver->setDefaults([
+ 'data_class' => WikiPage::class,
+ ]);
+ }
+}
diff --git a/Form/WikiType.php b/Form/WikiType.php
new file mode 100644
index 0000000..c84e9fb
--- /dev/null
+++ b/Form/WikiType.php
@@ -0,0 +1,63 @@
+wikiRepository = $wikiRepository;
+ }
+
+ public function buildForm(FormBuilderInterface $builder, array $options)
+ {
+ $wikiRepository = $this->wikiRepository;
+ $entity = $options['data'];
+
+ $builder
+ ->add('name', TextType::class, [
+ 'required' => true,
+ 'trim' => true,
+ 'constraints' => [
+ new Assert\NotBlank(),
+ new CodeConstraint(),
+ new Assert\Callback(
+ function ($name, ExecutionContext $context) use ($wikiRepository, $entity) {
+ if ($findEntity = $wikiRepository->findOneByName($name)) {
+ if ($findEntity->getId() != $entity->getId()) {
+ $context->addViolation('Name already exist');
+ }
+ }
+ }
+ ),
+ ],
+ ])
+ ->add('description', TextType::class, [
+ 'required' => true,
+ 'trim' => true,
+ 'constraints' => [
+ new Assert\NotBlank(),
+ ],
+ ])
+ ;
+ }
+
+ public function configureOptions(OptionsResolver $resolver)
+ {
+ $resolver->setDefaults([
+ 'data_class' => Wiki::class,
+ ]);
+ }
+}
diff --git a/LinkorbWikiBundle.php b/LinkorbWikiBundle.php
new file mode 100644
index 0000000..ed73bda
--- /dev/null
+++ b/LinkorbWikiBundle.php
@@ -0,0 +1,9 @@
+findBy(['wiki_id' => $wikiId]);
+ }
+}
diff --git a/Repository/WikiPageRepository.php b/Repository/WikiPageRepository.php
new file mode 100644
index 0000000..8f9d2a2
--- /dev/null
+++ b/Repository/WikiPageRepository.php
@@ -0,0 +1,60 @@
+createQueryBuilder('w')
+ ->andWhere('w.exampleField = :val')
+ ->setParameter('val', $value)
+ ->orderBy('w.id', 'ASC')
+ ->setMaxResults(10)
+ ->getQuery()
+ ->getResult()
+ ;
+ }
+ */
+
+ /*
+ public function findOneBySomeField($value): ?WikiPage
+ {
+ return $this->createQueryBuilder('w')
+ ->andWhere('w.exampleField = :val')
+ ->setParameter('val', $value)
+ ->getQuery()
+ ->getOneOrNullResult()
+ ;
+ }
+ */
+
+ public function findByWikiId($wikiId)
+ {
+ return $this->findBy(['wiki' => $wikiId]);
+ }
+
+ public function findOneByWikiIdAndName($wikiId, $name)
+ {
+ return $this->findOneBy(['wiki' => $wikiId, 'name' => $name]);
+ }
+}
diff --git a/Repository/WikiRepository.php b/Repository/WikiRepository.php
new file mode 100644
index 0000000..472a140
--- /dev/null
+++ b/Repository/WikiRepository.php
@@ -0,0 +1,26 @@
+findOneBy(['name' => $name]);
+ }
+}
diff --git a/Resources/Services/WikiEventService.php b/Resources/Services/WikiEventService.php
new file mode 100644
index 0000000..42490dd
--- /dev/null
+++ b/Resources/Services/WikiEventService.php
@@ -0,0 +1,42 @@
+tokenStorage = $tokenStorage;
+ $this->wikiEventRepository = $wikiEventRepository;
+ $this->em = $em;
+ }
+
+ public function createEvent($type, $wikiId, $data, $wikiPageId = null)
+ {
+ $user = $this->tokenStorage->getToken()->getUser();
+
+ $wikiEvent = new WikiEvent();
+ $wikiEvent
+ ->setCreatedAt(time())
+ ->setCreatedBy($user->getUsername())
+ ->setType($type)
+ ->setWikiId($wikiId)
+ ->setWikiPageId($wikiPageId)
+ ->setData($data)
+ ;
+
+ $this->em->persist($wikiEvent);
+ $this->em->flush();
+
+ return $wikiEvent;
+ }
+}
diff --git a/Resources/config/routing.yaml b/Resources/config/routing.yaml
new file mode 100644
index 0000000..e69de29
diff --git a/Resources/config/services.xml b/Resources/config/services.xml
new file mode 100644
index 0000000..639c591
--- /dev/null
+++ b/Resources/config/services.xml
@@ -0,0 +1,13 @@
+
+