File entity added. Post and Comment entities now has $files property. New migration. New FileFactory.

This commit is contained in:
Alexey Skobkin 2016-03-25 00:28:43 +03:00
parent a1b982d891
commit f919740524
9 changed files with 388 additions and 2 deletions

View file

@ -0,0 +1,51 @@
<?php
namespace Application\Migrations;
use Doctrine\DBAL\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema;
/**
* Auto-generated Migration: Please modify to your needs!
*/
class Version20160325001415 extends AbstractMigration
{
/**
* @param Schema $schema
*/
public function up(Schema $schema)
{
// this up() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
$this->addSql('CREATE SEQUENCE posts.files_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE TABLE posts.comments_files (comment_id INT NOT NULL, file_id INT NOT NULL, PRIMARY KEY(comment_id, file_id))');
$this->addSql('CREATE INDEX IDX_D0F69329F8697D13 ON posts.comments_files (comment_id)');
$this->addSql('CREATE INDEX IDX_D0F6932993CB796C ON posts.comments_files (file_id)');
$this->addSql('CREATE TABLE posts.posts_files (post_id VARCHAR(16) NOT NULL, file_id INT NOT NULL, PRIMARY KEY(post_id, file_id))');
$this->addSql('CREATE INDEX IDX_D799EBF04B89032C ON posts.posts_files (post_id)');
$this->addSql('CREATE INDEX IDX_D799EBF093CB796C ON posts.posts_files (file_id)');
$this->addSql('CREATE TABLE posts.files (id INT NOT NULL, remoteUrl VARCHAR(128) NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE UNIQUE INDEX UNIQ_744CC52C80445AEA ON posts.files (remoteUrl)');
$this->addSql('ALTER TABLE posts.comments_files ADD CONSTRAINT FK_D0F69329F8697D13 FOREIGN KEY (comment_id) REFERENCES posts.comments (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE posts.comments_files ADD CONSTRAINT FK_D0F6932993CB796C FOREIGN KEY (file_id) REFERENCES posts.files (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE posts.posts_files ADD CONSTRAINT FK_D799EBF04B89032C FOREIGN KEY (post_id) REFERENCES posts.posts (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE posts.posts_files ADD CONSTRAINT FK_D799EBF093CB796C FOREIGN KEY (file_id) REFERENCES posts.files (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
}
/**
* @param Schema $schema
*/
public function down(Schema $schema)
{
// this down() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
$this->addSql('ALTER TABLE posts.comments_files DROP CONSTRAINT FK_D0F6932993CB796C');
$this->addSql('ALTER TABLE posts.posts_files DROP CONSTRAINT FK_D799EBF093CB796C');
$this->addSql('DROP SEQUENCE posts.files_id_seq CASCADE');
$this->addSql('DROP TABLE posts.comments_files');
$this->addSql('DROP TABLE posts.posts_files');
$this->addSql('DROP TABLE posts.files');
}
}

View file

@ -26,6 +26,14 @@ class Post
*/ */
private $tags; private $tags;
/**
* @var string[]
*
* @JMSS\SerializedName("files")
* @JMSS\Type("array<string>")
*/
private $files;
/** /**
* @var User * @var User
* *
@ -104,6 +112,26 @@ class Post
return $this; return $this;
} }
/**
* @return string[]
*/
public function getFiles()
{
return $this->files;
}
/**
* @param string[] $files
*
* @return Post
*/
public function setFiles($files)
{
$this->files = $files;
return $this;
}
/** /**
* @return User * @return User
*/ */

View file

@ -76,6 +76,17 @@ class Comment
*/ */
private $author; private $author;
/**
* @var File[]|ArrayCollection
*
* @ORM\ManyToMany(targetEntity="Skobkin\Bundle\PointToolsBundle\Entity\Blogs\File", fetch="EXTRA_LAZY", cascade={"persist"})
* @ORM\JoinTable(name="posts.comments_files", schema="posts",
* joinColumns={@ORM\JoinColumn(name="comment_id")},
* inverseJoinColumns={@ORM\JoinColumn(name="file_id")}
* )
*/
private $files;
/** /**
* @var Comment|null * @var Comment|null
* *
@ -94,6 +105,7 @@ class Comment
public function __construct() public function __construct()
{ {
$this->files = new ArrayCollection();
$this->children = new ArrayCollection(); $this->children = new ArrayCollection();
} }
@ -247,6 +259,39 @@ class Comment
return $this; return $this;
} }
/**
* Add files
*
* @param File $files
* @return Comment
*/
public function addFile(File $files)
{
$this->files[] = $files;
return $this;
}
/**
* Remove files
*
* @param File $files
*/
public function removeFile(File $files)
{
$this->files->removeElement($files);
}
/**
* Get files
*
* @return File[]|ArrayCollection
*/
public function getFiles()
{
return $this->files;
}
/** /**
* @return Comment * @return Comment
*/ */

View file

@ -0,0 +1,69 @@
<?php
namespace Skobkin\Bundle\PointToolsBundle\Entity\Blogs;
use Doctrine\ORM\Mapping as ORM;
/**
* File
*
* @ORM\Table(name="posts.files", schema="posts")
* @ORM\Entity(repositoryClass="Skobkin\Bundle\PointToolsBundle\Repository\Blogs\FileRepository")
*/
class File
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="remoteUrl", type="string", length=128, unique=true)
*/
private $remoteUrl;
public function __construct($remoteUrl = null)
{
$this->remoteUrl = $remoteUrl;
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set remoteUrl
*
* @param string $remoteUrl
* @return File
*/
public function setRemoteUrl($remoteUrl)
{
$this->remoteUrl = $remoteUrl;
return $this;
}
/**
* Get remoteUrl
*
* @return string
*/
public function getRemoteUrl()
{
return $this->remoteUrl;
}
}

View file

@ -79,6 +79,17 @@ class Post
*/ */
private $author; private $author;
/**
* @var File[]|ArrayCollection
*
* @ORM\ManyToMany(targetEntity="Skobkin\Bundle\PointToolsBundle\Entity\Blogs\File", fetch="EXTRA_LAZY", cascade={"persist"})
* @ORM\JoinTable(name="posts.posts_files", schema="posts",
* joinColumns={@ORM\JoinColumn(name="post_id")},
* inverseJoinColumns={@ORM\JoinColumn(name="file_id")}
* )
*/
private $files;
/** /**
* @var Tag[]|ArrayCollection * @var Tag[]|ArrayCollection
* *
@ -102,6 +113,7 @@ class Post
{ {
$this->id = $id; $this->id = $id;
$this->files = new ArrayCollection();
$this->postTags = new ArrayCollection(); $this->postTags = new ArrayCollection();
$this->comments = new ArrayCollection(); $this->comments = new ArrayCollection();
} }
@ -219,6 +231,39 @@ class Post
return $this; return $this;
} }
/**
* Add files
*
* @param File $files
* @return Post
*/
public function addFile(File $files)
{
$this->files[] = $files;
return $this;
}
/**
* Remove files
*
* @param File $files
*/
public function removeFile(File $files)
{
$this->files->removeElement($files);
}
/**
* Get files
*
* @return File[]|ArrayCollection
*/
public function getFiles()
{
return $this->files;
}
/** /**
* Add post tags * Add post tags
* *

View file

@ -0,0 +1,9 @@
<?php
namespace Skobkin\Bundle\PointToolsBundle\Repository\Blogs;
use Doctrine\ORM\EntityRepository;
class FileRepository extends EntityRepository
{
}

View file

@ -37,6 +37,17 @@ services:
class: Skobkin\Bundle\PointToolsBundle\Service\Factory\Blogs\TagFactory class: Skobkin\Bundle\PointToolsBundle\Service\Factory\Blogs\TagFactory
arguments: [ @logger, @doctrine.orm.entity_manager ] arguments: [ @logger, @doctrine.orm.entity_manager ]
skobkin__point_tools.service_factory.file_factory:
class: Skobkin\Bundle\PointToolsBundle\Service\Factory\Blogs\FileFactory
arguments: [ @logger, @doctrine.orm.entity_manager ]
skobkin__point_tools.service_factory.post_factory: skobkin__point_tools.service_factory.post_factory:
class: Skobkin\Bundle\PointToolsBundle\Service\Factory\Blogs\PostFactory class: Skobkin\Bundle\PointToolsBundle\Service\Factory\Blogs\PostFactory
arguments: [ @logger, @doctrine.orm.entity_manager, @skobkin__point_tools.service_factory.user_factory, @skobkin__point_tools.service_factory.comment_factory, @skobkin__point_tools.service_factory.tag_factory ] arguments:
- @logger
- @doctrine.orm.entity_manager
- @skobkin__point_tools.service_factory.user_factory
- @skobkin__point_tools.service_factory.file_factory
- @skobkin__point_tools.service_factory.comment_factory
- @skobkin__point_tools.service_factory.tag_factory

View file

@ -0,0 +1,98 @@
<?php
namespace Skobkin\Bundle\PointToolsBundle\Service\Factory\Blogs;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Psr\Log\LoggerInterface;
use Skobkin\Bundle\PointToolsBundle\Entity\Blogs\File;
use Skobkin\Bundle\PointToolsBundle\Service\Exceptions\InvalidResponseException;
class FileFactory
{
/**
* @var EntityManager
*/
private $em;
/**
* @var LoggerInterface
*/
private $log;
/**
* @var EntityRepository
*/
private $fileRepository;
/**
* @param EntityManager $em
*/
public function __construct(LoggerInterface $log, EntityManagerInterface $em)
{
$this->log = $log;
$this->em = $em;
$this->fileRepository = $em->getRepository('SkobkinPointToolsBundle:Blogs\File');
}
/**
* @param string[] $urlStrings
*
* @return File[]
*/
public function createFromUrlsArray(array $urlStrings)
{
$files = [];
foreach ($urlStrings as $url) {
try {
$file = $this->createFromUrl($url);
$files[] = $file;
} catch (\Exception $e) {
$this->log->error('Error while creating file from DTO', ['file' => $url, 'message' => $e->getMessage()]);
continue;
}
}
return $files;
}
/**
* @param $url
*
* @return File
* @throws InvalidResponseException
*/
public function createFromUrl($url)
{
$this->validateData($url);
// Replacing HTTP with HTTPS
$url = str_replace('http://', 'https://', $url);
if (null === ($file = $this->fileRepository->findOneBy(['remoteUrl' => $url]))) {
// Creating new file
$file = new File($url);
$this->em->persist($file);
}
$this->em->flush($file);
return $file;
}
/**
* @param $data
*
* @throws InvalidResponseException
*/
private function validateData($data)
{
if (!is_string($data)) {
// @todo Change exception
throw new InvalidResponseException('File data must be a string');
}
}
}

View file

@ -39,6 +39,11 @@ class PostFactory
*/ */
private $userFactory; private $userFactory;
/**
* @var FileFactory
*/
private $fileFactory;
/** /**
* @var CommentFactory * @var CommentFactory
*/ */
@ -52,10 +57,11 @@ class PostFactory
/** /**
* @param EntityManager $em * @param EntityManager $em
*/ */
public function __construct(LoggerInterface $log, EntityManagerInterface $em, UserFactory $userFactory, CommentFactory $commentFactory, TagFactory $tagFactory) public function __construct(LoggerInterface $log, EntityManagerInterface $em, UserFactory $userFactory, FileFactory $fileFactory, CommentFactory $commentFactory, TagFactory $tagFactory)
{ {
$this->log = $log; $this->log = $log;
$this->userFactory = $userFactory; $this->userFactory = $userFactory;
$this->fileFactory = $fileFactory;
$this->commentFactory = $commentFactory; $this->commentFactory = $commentFactory;
$this->tagFactory = $tagFactory; $this->tagFactory = $tagFactory;
$this->em = $em; $this->em = $em;
@ -140,6 +146,7 @@ class PostFactory
; ;
$this->updatePostTags($post, $postData->getPost()->getTags()); $this->updatePostTags($post, $postData->getPost()->getTags());
$this->updatePostFiles($post, $postData->getPost()->getFiles());
$this->em->flush($post); $this->em->flush($post);
@ -190,6 +197,29 @@ class PostFactory
} }
} }
/**
* @param Post $post
* @param array $urls
*/
private function updatePostFiles(Post $post, array $urls)
{
$files = $this->fileFactory->createFromUrlsArray($urls);
// Adding missing files
foreach ($files as $file) {
if (!$post->getFiles()->contains($file)) {
$post->addFile($file);
}
}
// Removing deleted files
foreach ($post->getFiles() as $file) {
if (!in_array($file, $files, true)) {
$post->removeFile($file);
}
}
}
private function validateMetaPost(MetaPost $post) private function validateMetaPost(MetaPost $post)
{ {
if (!$post->getPost()->getId()) { if (!$post->getPost()->getId()) {