add post follow
This commit is contained in:
parent
bf901ad799
commit
6607b03e3b
1
.php-version
Normal file
1
.php-version
Normal file
|
@ -0,0 +1 @@
|
||||||
|
8.1
|
|
@ -15,6 +15,8 @@ core:
|
||||||
- {name: 'Blog\PostController::rss', action: 'App\Controller\Blog\PostController::rss'}
|
- {name: 'Blog\PostController::rss', action: 'App\Controller\Blog\PostController::rss'}
|
||||||
- {name: 'Blog\PostController::jsonApi', action: 'App\Controller\Blog\PostController::jsonApi'}
|
- {name: 'Blog\PostController::jsonApi', action: 'App\Controller\Blog\PostController::jsonApi'}
|
||||||
- {name: 'Blog\CategoryController::categories', action: 'App\Controller\Blog\CategoryController::categories'}
|
- {name: 'Blog\CategoryController::categories', action: 'App\Controller\Blog\CategoryController::categories'}
|
||||||
|
- {name: 'Blog\PostFollowController::enable', action: 'App\Controller\Blog\PostFollowController::enable'}
|
||||||
|
- {name: 'Blog\PostFollowController::disable', action: 'App\Controller\Blog\PostFollowController::disable'}
|
||||||
- {name: 'StlMeshController::meshes', action: 'App\Controller\StlMeshController::meshes'}
|
- {name: 'StlMeshController::meshes', action: 'App\Controller\StlMeshController::meshes'}
|
||||||
pages:
|
pages:
|
||||||
App\Entity\Page\SimplePage:
|
App\Entity\Page\SimplePage:
|
||||||
|
@ -62,7 +64,7 @@ core:
|
||||||
templates:
|
templates:
|
||||||
- {name: "Par défaut", file: "page/text/default.txt.twig"}
|
- {name: "Par défaut", file: "page/text/default.txt.twig"}
|
||||||
App\Entity\Page\TitledPage:
|
App\Entity\Page\TitledPage:
|
||||||
name: '_'
|
name: 'Page avec titre'
|
||||||
templates:
|
templates:
|
||||||
- {name: "Par défaut", file: "page/text/default.txt.twig"}
|
- {name: "Par défaut", file: "page/text/default.txt.twig"}
|
||||||
|
|
||||||
|
|
33
migrations/Version20220205165823.php
Normal file
33
migrations/Version20220205165823.php
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?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 Version20220205165823 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 post_follow (id INT AUTO_INCREMENT NOT NULL, post_id INT NOT NULL, comment_id INT NOT NULL, hash VARCHAR(255) NOT NULL, is_enabled TINYINT(1) NOT NULL, INDEX IDX_5816A0154B89032C (post_id), INDEX IDX_5816A015F8697D13 (comment_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
|
||||||
|
$this->addSql('ALTER TABLE post_follow ADD CONSTRAINT FK_5816A0154B89032C FOREIGN KEY (post_id) REFERENCES post (id)');
|
||||||
|
$this->addSql('ALTER TABLE post_follow ADD CONSTRAINT FK_5816A015F8697D13 FOREIGN KEY (comment_id) REFERENCES comment (id)');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('DROP TABLE post_follow');
|
||||||
|
}
|
||||||
|
}
|
31
migrations/Version20220205172820.php
Normal file
31
migrations/Version20220205172820.php
Normal file
|
@ -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 Version20220205172820 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('ALTER TABLE post_follow ADD created_at DATETIME NOT NULL, ADD updated_at DATETIME NOT NULL');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('ALTER TABLE post_follow DROP created_at, DROP updated_at');
|
||||||
|
}
|
||||||
|
}
|
37
migrations/Version20220206181024.php
Normal file
37
migrations/Version20220206181024.php
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<?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 Version20220206181024 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('ALTER TABLE post_follow DROP FOREIGN KEY FK_5816A015F8697D13');
|
||||||
|
$this->addSql('ALTER TABLE post_follow DROP FOREIGN KEY FK_5816A0154B89032C');
|
||||||
|
$this->addSql('ALTER TABLE post_follow ADD CONSTRAINT FK_5816A015F8697D13 FOREIGN KEY (comment_id) REFERENCES comment (id) ON DELETE CASCADE');
|
||||||
|
$this->addSql('ALTER TABLE post_follow ADD CONSTRAINT FK_5816A0154B89032C FOREIGN KEY (post_id) REFERENCES post (id) ON DELETE CASCADE');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('ALTER TABLE post_follow DROP FOREIGN KEY FK_5816A0154B89032C');
|
||||||
|
$this->addSql('ALTER TABLE post_follow DROP FOREIGN KEY FK_5816A015F8697D13');
|
||||||
|
$this->addSql('ALTER TABLE post_follow ADD CONSTRAINT FK_5816A0154B89032C FOREIGN KEY (post_id) REFERENCES post (id)');
|
||||||
|
$this->addSql('ALTER TABLE post_follow ADD CONSTRAINT FK_5816A015F8697D13 FOREIGN KEY (comment_id) REFERENCES comment (id)');
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,8 @@ use App\UrlGenerator\PostGenerator;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||||
|
use App\Factory\Blog\PostFollowFactory;
|
||||||
|
use App\Manager\PostFollowManager;
|
||||||
|
|
||||||
class PostController extends PageController
|
class PostController extends PageController
|
||||||
{
|
{
|
||||||
|
@ -36,6 +38,7 @@ class PostController extends PageController
|
||||||
Post $post,
|
Post $post,
|
||||||
string $slug,
|
string $slug,
|
||||||
CommentFactory $commentFactory,
|
CommentFactory $commentFactory,
|
||||||
|
PostFollowManager $postFollowManager,
|
||||||
Request $request,
|
Request $request,
|
||||||
EntityManager $entityManager
|
EntityManager $entityManager
|
||||||
): Response {
|
): Response {
|
||||||
|
@ -61,6 +64,7 @@ class PostController extends PageController
|
||||||
if ($form->isValid()) {
|
if ($form->isValid()) {
|
||||||
$data = $request->request->get($form->getName());
|
$data = $request->request->get($form->getName());
|
||||||
$parentCommentId = (int) $data['parentCommentId'];
|
$parentCommentId = (int) $data['parentCommentId'];
|
||||||
|
$follow = (bool) ($data['follow'] ?? false);
|
||||||
|
|
||||||
foreach ($post->getComments(['id' => $parentCommentId]) as $comment) {
|
foreach ($post->getComments(['id' => $parentCommentId]) as $comment) {
|
||||||
$form->getData()->setParentComment($comment);
|
$form->getData()->setParentComment($comment);
|
||||||
|
@ -70,8 +74,13 @@ class PostController extends PageController
|
||||||
|
|
||||||
$this->addFlash('success', 'Commentaire publié !');
|
$this->addFlash('success', 'Commentaire publié !');
|
||||||
|
|
||||||
|
if ($follow && $form->getData()->getEmail()) {
|
||||||
|
$postFollowManager->create($post, $form->getData());
|
||||||
|
}
|
||||||
|
|
||||||
return $this->redirect($request->getUri());
|
return $this->redirect($request->getUri());
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->addFlash('error', 'Le formulaire n\'est pas valide.');
|
$this->addFlash('error', 'Le formulaire n\'est pas valide.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
47
src/Controller/Blog/PostFollowController.php
Normal file
47
src/Controller/Blog/PostFollowController.php
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller\Blog;
|
||||||
|
|
||||||
|
use App\Core\Controller\Site\PageController;
|
||||||
|
use App\Core\Site\SiteRequest;
|
||||||
|
use App\Core\Site\SiteStore;
|
||||||
|
use App\Entity\Blog\PostFollow;
|
||||||
|
use App\Manager\PostFollowManager;
|
||||||
|
|
||||||
|
class PostFollowController extends PageController
|
||||||
|
{
|
||||||
|
protected PostFollowManager $manager;
|
||||||
|
|
||||||
|
public function __construct(PostFollowManager $manager, SiteRequest $siteRequest, SiteStore $siteStore)
|
||||||
|
{
|
||||||
|
parent::__construct($siteRequest, $siteStore);
|
||||||
|
|
||||||
|
$this->manager = $manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function enable(PostFollow $postFollow)
|
||||||
|
{
|
||||||
|
$this->manager->enable($postFollow);
|
||||||
|
|
||||||
|
$this->addFlash('success', 'Votre e-mail a bien été confirmé.');
|
||||||
|
|
||||||
|
return $this->redirectToRoute('blog_menu_post', [
|
||||||
|
'post' => $postFollow->getPost()->getId(),
|
||||||
|
'slug' => $postFollow->getPost()->getSlug(),
|
||||||
|
'_domain' => $this->siteRequest->getDomain(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function disable(PostFollow $postFollow)
|
||||||
|
{
|
||||||
|
$this->manager->disable($postFollow);
|
||||||
|
|
||||||
|
$this->addFlash('success', 'Vous ne recevrez plus de notification pour cet article.');
|
||||||
|
|
||||||
|
return $this->redirectToRoute('blog_menu_post', [
|
||||||
|
'post' => $postFollow->getPost()->getId(),
|
||||||
|
'slug' => $postFollow->getPost()->getSlug(),
|
||||||
|
'_domain' => $this->siteRequest->getDomain(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -66,9 +66,15 @@ class Comment implements EntityInterface
|
||||||
*/
|
*/
|
||||||
private $comments;
|
private $comments;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\OneToMany(targetEntity=PostFollow::class, mappedBy="comment", orphanRemoval=true)
|
||||||
|
*/
|
||||||
|
private $postFollows;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->comments = new ArrayCollection();
|
$this->comments = new ArrayCollection();
|
||||||
|
$this->postFollows = new ArrayCollection();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): ?int
|
public function getId(): ?int
|
||||||
|
@ -220,4 +226,34 @@ class Comment implements EntityInterface
|
||||||
substr($this->getContent(), 0, 20).'…'
|
substr($this->getContent(), 0, 20).'…'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection|PostFollow[]
|
||||||
|
*/
|
||||||
|
public function getPostFollows(): Collection
|
||||||
|
{
|
||||||
|
return $this->postFollows;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addPostFollow(PostFollow $postFollow): self
|
||||||
|
{
|
||||||
|
if (!$this->postFollows->contains($postFollow)) {
|
||||||
|
$this->postFollows[] = $postFollow;
|
||||||
|
$postFollow->setComment($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removePostFollow(PostFollow $postFollow): self
|
||||||
|
{
|
||||||
|
if ($this->postFollows->removeElement($postFollow)) {
|
||||||
|
// set the owning side to null (unless already changed)
|
||||||
|
if ($postFollow->getComment() === $this) {
|
||||||
|
$postFollow->setComment(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,10 +118,16 @@ class Post implements EntityInterface
|
||||||
*/
|
*/
|
||||||
private $notebook;
|
private $notebook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\OneToMany(targetEntity=PostFollow::class, mappedBy="post", orphanRemoval=true)
|
||||||
|
*/
|
||||||
|
private $postFollows;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->categories = new ArrayCollection();
|
$this->categories = new ArrayCollection();
|
||||||
$this->comments = new ArrayCollection();
|
$this->comments = new ArrayCollection();
|
||||||
|
$this->postFollows = new ArrayCollection();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): ?int
|
public function getId(): ?int
|
||||||
|
@ -410,4 +416,34 @@ class Post implements EntityInterface
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection|PostFollow[]
|
||||||
|
*/
|
||||||
|
public function getPostFollows(): Collection
|
||||||
|
{
|
||||||
|
return $this->postFollows;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addPostFollow(PostFollow $postFollow): self
|
||||||
|
{
|
||||||
|
if (!$this->postFollows->contains($postFollow)) {
|
||||||
|
$this->postFollows[] = $postFollow;
|
||||||
|
$postFollow->setPost($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removePostFollow(PostFollow $postFollow): self
|
||||||
|
{
|
||||||
|
if ($this->postFollows->removeElement($postFollow)) {
|
||||||
|
// set the owning side to null (unless already changed)
|
||||||
|
if ($postFollow->getPost() === $this) {
|
||||||
|
$postFollow->setPost(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
99
src/Entity/Blog/PostFollow.php
Normal file
99
src/Entity/Blog/PostFollow.php
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Entity\Blog;
|
||||||
|
|
||||||
|
use App\Core\Doctrine\Timestampable;
|
||||||
|
use App\Core\Entity\EntityInterface;
|
||||||
|
use App\Repository\Blog\PostFollowRepository;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Entity(repositoryClass=PostFollowRepository::class)
|
||||||
|
* @ORM\HasLifecycleCallbacks
|
||||||
|
*/
|
||||||
|
class PostFollow implements EntityInterface
|
||||||
|
{
|
||||||
|
use Timestampable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Id
|
||||||
|
* @ORM\GeneratedValue
|
||||||
|
* @ORM\Column(type="integer")
|
||||||
|
*/
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="string", length=255)
|
||||||
|
*/
|
||||||
|
private $hash;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="boolean")
|
||||||
|
*/
|
||||||
|
private $isEnabled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\ManyToOne(targetEntity=Post::class, inversedBy="postFollows")
|
||||||
|
* @ORM\JoinColumn(nullable=false, onDelete="CASCADE")
|
||||||
|
*/
|
||||||
|
private $post;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\ManyToOne(targetEntity=Comment::class, inversedBy="postFollows")
|
||||||
|
* @ORM\JoinColumn(nullable=false, onDelete="CASCADE")
|
||||||
|
*/
|
||||||
|
private $comment;
|
||||||
|
|
||||||
|
public function getId(): ?int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHash(): ?string
|
||||||
|
{
|
||||||
|
return $this->hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setHash(string $hash): self
|
||||||
|
{
|
||||||
|
$this->hash = $hash;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsEnabled(): ?bool
|
||||||
|
{
|
||||||
|
return $this->isEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setIsEnabled(bool $isEnabled): self
|
||||||
|
{
|
||||||
|
$this->isEnabled = $isEnabled;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPost(): ?Post
|
||||||
|
{
|
||||||
|
return $this->post;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPost(?Post $post): self
|
||||||
|
{
|
||||||
|
$this->post = $post;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getComment(): ?Comment
|
||||||
|
{
|
||||||
|
return $this->comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setComment(?Comment $comment): self
|
||||||
|
{
|
||||||
|
$this->comment = $comment;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,8 @@ use App\Core\Notification\MailNotifier;
|
||||||
use App\Entity\Blog\Comment;
|
use App\Entity\Blog\Comment;
|
||||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||||
use App\Core\Setting\SettingManager;
|
use App\Core\Setting\SettingManager;
|
||||||
|
use App\Repository\Blog\PostFollowRepositoryQuery;
|
||||||
|
use App\Core\Site\SiteRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* class CommentEventSubscriber.
|
* class CommentEventSubscriber.
|
||||||
|
@ -20,12 +22,22 @@ class CommentEventSubscriber extends EntityManagerEventSubscriber
|
||||||
protected MailNotifier $notifier;
|
protected MailNotifier $notifier;
|
||||||
protected UrlGeneratorInterface $urlGenerator;
|
protected UrlGeneratorInterface $urlGenerator;
|
||||||
protected SettingManager $settingManager;
|
protected SettingManager $settingManager;
|
||||||
|
protected PostFollowRepository $postFollowRepository;
|
||||||
|
protected SiteRequest $siteRequest;
|
||||||
|
|
||||||
public function __construct(MailNotifier $notifier, UrlGeneratorInterface $urlGenerator, SettingManager $settingManager)
|
public function __construct(
|
||||||
|
MailNotifier $notifier,
|
||||||
|
UrlGeneratorInterface $urlGenerator,
|
||||||
|
SettingManager $settingManager,
|
||||||
|
PostFollowRepositoryQuery $postFollowRepositoryQuery,
|
||||||
|
SiteRequest $siteRequest
|
||||||
|
)
|
||||||
{
|
{
|
||||||
$this->notifier = $notifier;
|
$this->notifier = $notifier;
|
||||||
$this->urlGenerator = $urlGenerator;
|
$this->urlGenerator = $urlGenerator;
|
||||||
$this->settingManager = $settingManager;
|
$this->settingManager = $settingManager;
|
||||||
|
$this->postFollowRepositoryQuery = $postFollowRepositoryQuery;
|
||||||
|
$this->siteRequest = $siteRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function support(EntityInterface $entity)
|
public function support(EntityInterface $entity)
|
||||||
|
@ -50,9 +62,41 @@ class CommentEventSubscriber extends EntityManagerEventSubscriber
|
||||||
'post' => $this->urlGenerator->generate('blog_menu_post', [
|
'post' => $this->urlGenerator->generate('blog_menu_post', [
|
||||||
'post' => $event->getEntity()->getPost()->getId(),
|
'post' => $event->getEntity()->getPost()->getId(),
|
||||||
'slug' => $event->getEntity()->getPost()->getSlug(),
|
'slug' => $event->getEntity()->getPost()->getSlug(),
|
||||||
|
'_domain' => $this->siteRequest->getDomain(),
|
||||||
], UrlGeneratorInterface::ABSOLUTE_URL).'#review-'.$event->getEntity()->getId(),
|
], UrlGeneratorInterface::ABSOLUTE_URL).'#review-'.$event->getEntity()->getId(),
|
||||||
],
|
],
|
||||||
], 'text/plain')
|
], 'text/plain')
|
||||||
;
|
;
|
||||||
|
|
||||||
|
$postFollows = $this->postFollowRepositoryQuery->create()
|
||||||
|
->where('.post = :post')
|
||||||
|
->andWhere('.isEnabled = 1')
|
||||||
|
->setParameter(':post', $event->getEntity()->getPost()->getId())
|
||||||
|
->find();
|
||||||
|
|
||||||
|
foreach ($postFollows as $postFollow) {
|
||||||
|
if ($event->getEntity()->getEmail() !== $postFollow->getComment()->getEmail()) {
|
||||||
|
$this->notifier
|
||||||
|
->init()
|
||||||
|
->setFrom($this->settingManager->get('email_sender')->getValue())
|
||||||
|
->addRecipient($this->settingManager->get('email_comment')->getValue())
|
||||||
|
->setSubject('[Deblan] Nouveau commentaire')
|
||||||
|
->notify('mail/post_follow_comment.html.twig', [
|
||||||
|
'post' => $event->getEntity()->getPost(),
|
||||||
|
'links' => [
|
||||||
|
'post' => $this->urlGenerator->generate('blog_menu_post', [
|
||||||
|
'post' => $event->getEntity()->getPost()->getId(),
|
||||||
|
'slug' => $event->getEntity()->getPost()->getSlug(),
|
||||||
|
'_domain' => $this->siteRequest->getDomain(),
|
||||||
|
], UrlGeneratorInterface::ABSOLUTE_URL).'#review-'.$event->getEntity()->getId(),
|
||||||
|
'disable' => $this->urlGenerator->generate('blog_tech_follow_disable', [
|
||||||
|
'hash' => $postFollow->getHash(),
|
||||||
|
'_domain' => $this->siteRequest->getDomain(),
|
||||||
|
], UrlGeneratorInterface::ABSOLUTE_URL),
|
||||||
|
],
|
||||||
|
], 'text/plain')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
75
src/EventSuscriber/Blog/PostFollowEventSubscriber.php
Normal file
75
src/EventSuscriber/Blog/PostFollowEventSubscriber.php
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\EventSuscriber\Blog;
|
||||||
|
|
||||||
|
use App\Core\Entity\EntityInterface;
|
||||||
|
use App\Core\Event\EntityManager\EntityManagerEvent;
|
||||||
|
use App\Core\EventSuscriber\EntityManagerEventSubscriber;
|
||||||
|
use App\Core\Notification\MailNotifier;
|
||||||
|
use App\Core\Setting\SettingManager;
|
||||||
|
use App\Entity\Blog\PostFollow;
|
||||||
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||||
|
use App\Core\Site\SiteRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class PostFollowEventSubscriber.
|
||||||
|
*
|
||||||
|
* @author Simon Vieille <simon@deblan.fr>
|
||||||
|
*/
|
||||||
|
class PostFollowEventSubscriber extends EntityManagerEventSubscriber
|
||||||
|
{
|
||||||
|
protected MailNotifier $notifier;
|
||||||
|
protected UrlGeneratorInterface $urlGenerator;
|
||||||
|
protected SettingManager $settingManager;
|
||||||
|
protected SiteRequest $siteRequest;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
MailNotifier $notifier,
|
||||||
|
UrlGeneratorInterface $urlGenerator,
|
||||||
|
SettingManager $settingManager,
|
||||||
|
SiteRequest $siteRequest
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$this->notifier = $notifier;
|
||||||
|
$this->urlGenerator = $urlGenerator;
|
||||||
|
$this->settingManager = $settingManager;
|
||||||
|
$this->siteRequest = $siteRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function support(EntityInterface $entity)
|
||||||
|
{
|
||||||
|
return $entity instanceof PostFollow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onCreate(EntityManagerEvent $event)
|
||||||
|
{
|
||||||
|
if (!$this->support($event->getEntity())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->notifier
|
||||||
|
->init()
|
||||||
|
->setFrom($this->settingManager->get('email_sender')->getValue())
|
||||||
|
->addRecipient($event->getEntity()->getComment()->getEmail())
|
||||||
|
->setSubject('[Deblan] Confirmer votre e-mail')
|
||||||
|
->notify('mail/post_follow_subscription.html.twig', [
|
||||||
|
'entity' => $event->getEntity(),
|
||||||
|
'links' => [
|
||||||
|
'post' => $this->urlGenerator->generate('blog_menu_post', [
|
||||||
|
'post' => $event->getEntity()->getPost()->getId(),
|
||||||
|
'slug' => $event->getEntity()->getPost()->getSlug(),
|
||||||
|
'_domain' => $this->siteRequest->getDomain(),
|
||||||
|
], UrlGeneratorInterface::ABSOLUTE_URL),
|
||||||
|
'enable' => $this->urlGenerator->generate('blog_tech_follow_enable', [
|
||||||
|
'hash' => $event->getEntity()->getHash(),
|
||||||
|
'_domain' => $this->siteRequest->getDomain(),
|
||||||
|
], UrlGeneratorInterface::ABSOLUTE_URL),
|
||||||
|
'disable' => $this->urlGenerator->generate('blog_tech_follow_disable', [
|
||||||
|
'hash' => $event->getEntity()->getHash(),
|
||||||
|
'_domain' => $this->siteRequest->getDomain(),
|
||||||
|
], UrlGeneratorInterface::ABSOLUTE_URL),
|
||||||
|
],
|
||||||
|
], 'text/plain')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
24
src/Factory/Blog/PostFollowFactory.php
Normal file
24
src/Factory/Blog/PostFollowFactory.php
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Factory\Blog;
|
||||||
|
|
||||||
|
use App\Core\Factory\FactoryInterface;
|
||||||
|
use App\Entity\Blog\Comment;
|
||||||
|
use App\Entity\Blog\Post;
|
||||||
|
use App\Entity\Blog\PostFollow as Entity;
|
||||||
|
|
||||||
|
class PostFollowFactory implements FactoryInterface
|
||||||
|
{
|
||||||
|
public function create(Post $post, Comment $comment): Entity
|
||||||
|
{
|
||||||
|
$entity = new Entity();
|
||||||
|
$entity
|
||||||
|
->setPost($post)
|
||||||
|
->setComment($comment)
|
||||||
|
->setIsEnabled(false)
|
||||||
|
->setHash(hash('sha256', bin2hex(random_bytes(32))))
|
||||||
|
;
|
||||||
|
|
||||||
|
return $entity;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
use Symfony\Component\Validator\Constraints\Email;
|
use Symfony\Component\Validator\Constraints\Email;
|
||||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||||
use Symfony\Component\Validator\Constraints\Url;
|
use Symfony\Component\Validator\Constraints\Url;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||||
|
|
||||||
class UserCommentType extends AbstractType
|
class UserCommentType extends AbstractType
|
||||||
{
|
{
|
||||||
|
@ -75,6 +76,16 @@ class UserCommentType extends AbstractType
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$builder->add(
|
||||||
|
'follow',
|
||||||
|
CheckboxType::class,
|
||||||
|
[
|
||||||
|
'label' => 'Recevoir une notification par e-mail si un commentaire est déposé sur cet article',
|
||||||
|
'mapped' => false,
|
||||||
|
'required' => false,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
$builder->add(
|
$builder->add(
|
||||||
'parentCommentId',
|
'parentCommentId',
|
||||||
HiddenType::class,
|
HiddenType::class,
|
||||||
|
|
70
src/Manager/PostFollowManager.php
Normal file
70
src/Manager/PostFollowManager.php
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Manager;
|
||||||
|
|
||||||
|
use App\Core\Manager\EntityManager;
|
||||||
|
use App\Entity\Blog\Comment;
|
||||||
|
use App\Entity\Blog\Post;
|
||||||
|
use App\Entity\Blog\PostFollow;
|
||||||
|
use App\Factory\Blog\PostFollowFactory;
|
||||||
|
use App\Repository\Blog\PostFollowRepositoryQuery;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class PostFollowManager.
|
||||||
|
*
|
||||||
|
* @author Simon Vieille <simon@deblan.fr>
|
||||||
|
*/
|
||||||
|
class PostFollowManager
|
||||||
|
{
|
||||||
|
protected PostFollowFactory $factory;
|
||||||
|
protected PostFollowRepositoryQuery $repository;
|
||||||
|
protected EntityManager $manager;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
PostFollowFactory $factory,
|
||||||
|
PostFollowRepositoryQuery $repository,
|
||||||
|
EntityManager $manager
|
||||||
|
) {
|
||||||
|
$this->factory = $factory;
|
||||||
|
$this->repository = $repository;
|
||||||
|
$this->manager = $manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create(Post $post, Comment $comment): PostFollow
|
||||||
|
{
|
||||||
|
$postFollow = $this->find($post, $comment);
|
||||||
|
|
||||||
|
if (!$postFollow) {
|
||||||
|
$postFollow = $this->factory->create($post, $comment);
|
||||||
|
|
||||||
|
$this->manager->create($postFollow);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $postFollow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function find(Post $post, Comment $comment): ?PostFollow
|
||||||
|
{
|
||||||
|
return $this->repository->create()
|
||||||
|
->where('.post = :post')
|
||||||
|
->andWhere('.comment = :comment')
|
||||||
|
->setParameters([
|
||||||
|
':post' => $post->getId(),
|
||||||
|
':comment' => $comment->getId(),
|
||||||
|
])
|
||||||
|
->findOne()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function enable(PostFollow $postFollow): void
|
||||||
|
{
|
||||||
|
$postFollow->setIsEnabled(true);
|
||||||
|
|
||||||
|
$this->manager->update($postFollow);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function disable(PostFollow $postFollow): void
|
||||||
|
{
|
||||||
|
$this->manager->delete($postFollow);
|
||||||
|
}
|
||||||
|
}
|
20
src/Repository/Blog/PostFollowRepository.php
Normal file
20
src/Repository/Blog/PostFollowRepository.php
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repository\Blog;
|
||||||
|
|
||||||
|
use App\Entity\Blog\PostFollow;
|
||||||
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
|
||||||
|
class PostFollowRepository extends ServiceEntityRepository
|
||||||
|
{
|
||||||
|
public function __construct(ManagerRegistry $registry)
|
||||||
|
{
|
||||||
|
parent::__construct($registry, PostFollow::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEm()
|
||||||
|
{
|
||||||
|
return $this->getEntityManager();
|
||||||
|
}
|
||||||
|
}
|
15
src/Repository/Blog/PostFollowRepositoryQuery.php
Normal file
15
src/Repository/Blog/PostFollowRepositoryQuery.php
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repository\Blog;
|
||||||
|
|
||||||
|
use App\Core\Repository\RepositoryQuery;
|
||||||
|
use Knp\Component\Pager\PaginatorInterface;
|
||||||
|
use App\Repository\Blog\PostFollowRepository as Repository;
|
||||||
|
|
||||||
|
class PostFollowRepositoryQuery extends RepositoryQuery
|
||||||
|
{
|
||||||
|
public function __construct(Repository $repository, PaginatorInterface $paginator)
|
||||||
|
{
|
||||||
|
parent::__construct($repository, 'p', $paginator);
|
||||||
|
}
|
||||||
|
}
|
8
templates/mail/post_follow_comment.html.twig
Normal file
8
templates/mail/post_follow_comment.html.twig
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
Un nouveau commentaire a été déposé sur l'article suivant :
|
||||||
|
|
||||||
|
{{ post.title|raw }}
|
||||||
|
{{ links.post }}
|
||||||
|
|
||||||
|
Vous pourrez supprimer les notifications de cet article via ce lien :
|
||||||
|
|
||||||
|
{{ links.disable }}
|
14
templates/mail/post_follow_subscription.html.twig
Normal file
14
templates/mail/post_follow_subscription.html.twig
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
Vous avez décidé de recevoir les notifications de cet article :
|
||||||
|
|
||||||
|
{{ entity.post.title|raw }}
|
||||||
|
{{ links.post }}
|
||||||
|
|
||||||
|
Si vous n'êtes pas à l'origine de cette demande, vous pouvez ignorer ce message et votre e-mail sera automatiquement supprimé dans quelques jours.
|
||||||
|
|
||||||
|
Veuillez cliquer sur le lien de confirmation pour valider votre e-mail :
|
||||||
|
|
||||||
|
{{ links.enable }}
|
||||||
|
|
||||||
|
Vous pourrez vous désinscrire à tout moment via ce lien :
|
||||||
|
|
||||||
|
{{ links.disable }}
|
|
@ -148,6 +148,13 @@
|
||||||
{{ form_errors(form.email) }}
|
{{ form_errors(form.email) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="field col-12">
|
||||||
|
{{ form_label(form.follow) }}
|
||||||
|
{{ form_widget(form.follow) }}
|
||||||
|
{{ form_errors(form.follow) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<p class="no-margin">
|
<p class="no-margin">
|
||||||
{{- 'Votre commentaire - Vous pouvez utiliser du markdown ' }}
|
{{- 'Votre commentaire - Vous pouvez utiliser du markdown ' }}
|
||||||
|
|
Loading…
Reference in a new issue