diff --git a/migrations/Version20220520124026.php b/migrations/Version20220520124026.php deleted file mode 100644 index b03d66d..0000000 --- a/migrations/Version20220520124026.php +++ /dev/null @@ -1,31 +0,0 @@ -addSql('ALTER TABLE book ADD subtitle VARCHAR(255) DEFAULT NULL'); - } - - public function down(Schema $schema): void - { - // this down() migration is auto-generated, please modify it to your needs - $this->addSql('ALTER TABLE book DROP subtitle'); - } -} diff --git a/migrations/Version20220520130832.php b/migrations/Version20220520130832.php deleted file mode 100644 index 35309c9..0000000 --- a/migrations/Version20220520130832.php +++ /dev/null @@ -1,32 +0,0 @@ -addSql('CREATE TABLE file (id INT AUTO_INCREMENT NOT NULL, book_id INT NOT NULL, file_name VARCHAR(255) NOT NULL, file_size INT NOT NULL, extension VARCHAR(255) NOT NULL, type VARCHAR(255) NOT NULL, INDEX IDX_8C9F361016A2B381 (book_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); - $this->addSql('ALTER TABLE file ADD CONSTRAINT FK_8C9F361016A2B381 FOREIGN KEY (book_id) REFERENCES book (id)'); - } - - public function down(Schema $schema): void - { - // this down() migration is auto-generated, please modify it to your needs - $this->addSql('DROP TABLE file'); - } -} diff --git a/migrations/Version20220520082729.php b/migrations/Version20220523130539.php similarity index 62% rename from migrations/Version20220520082729.php rename to migrations/Version20220523130539.php index 27162c2..8099cb5 100644 --- a/migrations/Version20220520082729.php +++ b/migrations/Version20220523130539.php @@ -10,7 +10,7 @@ use Doctrine\Migrations\AbstractMigration; /** * Auto-generated Migration: Please modify to your needs! */ -final class Version20220520082729 extends AbstractMigration +final class Version20220523130539 extends AbstractMigration { public function getDescription(): string { @@ -20,15 +20,19 @@ final class Version20220520082729 extends AbstractMigration public function up(Schema $schema): void { // this up() migration is auto-generated, please modify it to your needs - $this->addSql('CREATE TABLE book (id INT AUTO_INCREMENT NOT NULL, title VARCHAR(255) NOT NULL, language VARCHAR(255) NOT NULL, description LONGTEXT DEFAULT NULL, publisher VARCHAR(255) DEFAULT NULL, publish_date DATE DEFAULT NULL, filename VARCHAR(255) DEFAULT NULL, original_filename VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE book (id INT AUTO_INCREMENT NOT NULL, title VARCHAR(255) NOT NULL, language VARCHAR(255) NOT NULL, description LONGTEXT DEFAULT NULL, publisher VARCHAR(255) DEFAULT NULL, publish_date DATE DEFAULT NULL, subtitle VARCHAR(255) DEFAULT NULL, isbn VARCHAR(255) DEFAULT NULL, series VARCHAR(255) DEFAULT NULL, volume INT DEFAULT NULL, author VARCHAR(255) NOT NULL, tags LONGTEXT DEFAULT NULL, pages INT DEFAULT NULL, rating SMALLINT DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE file (id INT AUTO_INCREMENT NOT NULL, book_id INT NOT NULL, file_name VARCHAR(255) NOT NULL, file_size INT NOT NULL, extension VARCHAR(255) NOT NULL, type VARCHAR(255) NOT NULL, INDEX IDX_8C9F361016A2B381 (book_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('CREATE TABLE `user` (id INT AUTO_INCREMENT NOT NULL, email VARCHAR(180) NOT NULL, roles JSON NOT NULL, password VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_8D93D649E7927C74 (email), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('CREATE TABLE messenger_messages (id BIGINT AUTO_INCREMENT NOT NULL, body LONGTEXT NOT NULL, headers LONGTEXT NOT NULL, queue_name VARCHAR(190) NOT NULL, created_at DATETIME NOT NULL, available_at DATETIME NOT NULL, delivered_at DATETIME DEFAULT NULL, INDEX IDX_75EA56E0FB7336F0 (queue_name), INDEX IDX_75EA56E0E3BD61CE (available_at), INDEX IDX_75EA56E016BA31DB (delivered_at), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('ALTER TABLE file ADD CONSTRAINT FK_8C9F361016A2B381 FOREIGN KEY (book_id) REFERENCES book (id)'); } public function down(Schema $schema): void { // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE file DROP FOREIGN KEY FK_8C9F361016A2B381'); $this->addSql('DROP TABLE book'); + $this->addSql('DROP TABLE file'); $this->addSql('DROP TABLE `user`'); $this->addSql('DROP TABLE messenger_messages'); } diff --git a/src/Controller/BookController.php b/src/Controller/BookController.php index 9b8f005..43d2ffa 100644 --- a/src/Controller/BookController.php +++ b/src/Controller/BookController.php @@ -3,11 +3,12 @@ namespace App\Controller; use App\Entity\Book; +use App\Entity\File; use App\Form\BookType; use App\Repository\BookRepository; +use App\Repository\FileRepository; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\BinaryFileResponse; -use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; @@ -43,14 +44,13 @@ class BookController extends AbstractController $ebook = $request->files->get('book')['ebook']; if ($ebook) { + dd($ebook); $ebook->move( $this->getParameter('book_files'), 'ebook_' . $book->getId() . '.' . $ebook->guessClientExtension() ); } - dd($book->getId()); - return $this->redirectToRoute('app_book_index', [], Response::HTTP_SEE_OTHER); } @@ -69,8 +69,12 @@ class BookController extends AbstractController } #[Route('/{id}/edit', name: 'app_book_edit', methods: ['GET', 'POST'])] - public function edit(Request $request, Book $book, BookRepository $bookRepository): Response - { + public function edit( + Request $request, + Book $book, + BookRepository $bookRepository, + FileRepository $fileRepository + ): Response { $form = $this->createForm(BookType::class, $book); $form->handleRequest($request); @@ -83,20 +87,29 @@ class BookController extends AbstractController ); } - /** @var \Symfony\Component\HttpFoundation\File\UploadedFile $ebook */ - $ebook = $request->files->get('book')['ebook']; - if ($ebook) { - $ebook->move( - $this->getParameter('book_files'), - 'ebook_' . $book->getId() . '.' . $ebook->guessClientExtension() - ); + /** @var \Symfony\Component\HttpFoundation\File\UploadedFile[] $ebooks */ + $ebooks = $request->files->get('book')['ebook']; + if (count($ebooks) > 0) { + foreach ($ebooks as $ebook) { + $file = new File(); + $file->setFileName(trim($ebook->getClientOriginalName())); + $file->setFileSize($ebook->getSize()); + $file->setExtension($ebook->guessClientExtension()); + $file->setBook($book); + $fileRepository->add($file, true); + + $ebook->move( + $this->getParameter('book_files'), + 'ebook_' . $book->getId() . '_' . md5( + $ebook->getClientOriginalName() + ) . '.' . $ebook->guessClientExtension() + ); + } } - $book->setOriginalFilename($ebook->getClientOriginalName()); $bookRepository->add($book, true); - - return $this->redirectToRoute('app_book_index', [], Response::HTTP_SEE_OTHER); + return $this->redirectToRoute('app_book_edit', ['id' => $book->getId()], Response::HTTP_SEE_OTHER); } return $this->renderForm('book/edit.html.twig', [ @@ -119,7 +132,10 @@ class BookController extends AbstractController public function downloadBook(Book $book): BinaryFileResponse { return $this->file( - $this->getParameter('book_files') . '/' . 'ebook_' . $book->getId() . '.'.pathinfo($book->getOriginalFilename(), PATHINFO_EXTENSION), + $this->getParameter('book_files') . '/' . 'ebook_' . $book->getId() . '.' . pathinfo( + $book->getOriginalFilename(), + PATHINFO_EXTENSION + ), $book->getOriginalFilename() ); } diff --git a/src/Entity/Book.php b/src/Entity/Book.php index 7748904..f972216 100644 --- a/src/Entity/Book.php +++ b/src/Entity/Book.php @@ -36,6 +36,27 @@ class Book #[ORM\OneToMany(mappedBy: 'book', targetEntity: File::class, orphanRemoval: true)] private $files; + #[ORM\Column(type: 'string', length: 255, nullable: true)] + private $isbn; + + #[ORM\Column(type: 'string', length: 255, nullable: true)] + private $series; + + #[ORM\Column(type: 'integer', nullable: true)] + private $volume; + + #[ORM\Column(type: 'string', length: 255)] + private $author; + + #[ORM\Column(type: 'text', nullable: true)] + private $tags; + + #[ORM\Column(type: 'integer', nullable: true)] + private $pages; + + #[ORM\Column(type: 'smallint', nullable: true)] + private $rating; + public function __construct() { $this->files = new ArrayCollection(); @@ -147,4 +168,88 @@ class Book return $this; } + + public function getIsbn(): ?string + { + return $this->isbn; + } + + public function setIsbn(?string $isbn): self + { + $this->isbn = $isbn; + + return $this; + } + + public function getSeries(): ?string + { + return $this->series; + } + + public function setSeries(?string $series): self + { + $this->series = $series; + + return $this; + } + + public function getVolume(): ?int + { + return $this->volume; + } + + public function setVolume(?int $volume): self + { + $this->volume = $volume; + + return $this; + } + + public function getAuthor(): ?string + { + return $this->author; + } + + public function setAuthor(string $author): self + { + $this->author = $author; + + return $this; + } + + public function getTags(): ?string + { + return $this->tags; + } + + public function setTags(?string $tags): self + { + $this->tags = $tags; + + return $this; + } + + public function getPages(): ?int + { + return $this->pages; + } + + public function setPages(?int $pages): self + { + $this->pages = $pages; + + return $this; + } + + public function getRating(): ?int + { + return $this->rating; + } + + public function setRating(?int $rating): self + { + $this->rating = $rating; + + return $this; + } } diff --git a/src/Entity/File.php b/src/Entity/File.php index 1cc288e..24852fa 100644 --- a/src/Entity/File.php +++ b/src/Entity/File.php @@ -23,7 +23,7 @@ class File private $extension; #[ORM\Column(type: 'string', length: 255)] - private $type; + private $type = 'ebook'; #[ORM\ManyToOne(targetEntity: Book::class, inversedBy: 'files')] #[ORM\JoinColumn(nullable: false)] @@ -75,7 +75,7 @@ class File return $this->type; } - public function setType(string $type): self + public function setType(string $type = 'ebook'): self { $this->type = $type; diff --git a/src/Form/BookType.php b/src/Form/BookType.php index 1743edc..703dee4 100644 --- a/src/Form/BookType.php +++ b/src/Form/BookType.php @@ -4,7 +4,11 @@ namespace App\Form; use App\Entity\Book; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Form\Extension\Core\Type\FileType; +use Symfony\Component\Form\Extension\Core\Type\IntegerType; +use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -14,13 +18,40 @@ class BookType extends AbstractType { $builder ->add('Title') + ->add('subtitle') + ->add('author') + ->add('isbn') + ->add('pages') + ->add('tags') + ->add('publish_date', DateType::class, [ + 'widget' => 'single_text', + 'html5' => true, + 'required' => false, + ]) + ->add('publisher') ->add('language') ->add('description') - ->add('publisher') - ->add('publish_date') - ->add('ebook', FileType::class, ['mapped' => false, 'data_class' => null, 'required' => false]) - ->add('cover', FileType::class, ['mapped' => false, 'data_class' => null, 'required' => false]) - ; + ->add('series', TextType::class, ['label' => 'Series', 'required' => false]) + ->add('volume', IntegerType::class, ['label' => 'Volume', 'required' => false]) + ->add('rating', ChoiceType::class, [ + 'choices' => [ + 'not rated' => null, + ':|' => 0, + '⭐ (1/5)' => 1, + '⭐⭐ (2/5)' => 2, + '⭐⭐⭐ (3/5)' => 3, + '⭐⭐⭐⭐ (4/5)' => 4, + '⭐⭐⭐⭐⭐ (5/5)' => 5, + ], + ]) + ->add('ebook', FileType::class, [ + 'mapped' => false, + 'multiple' => true, + 'data_class' => null, + 'required' => false, + 'attr' => ['accept' => ".pdf, .epub, .mobi"] + ]) + ->add('cover', FileType::class, ['mapped' => false, 'data_class' => null, 'required' => false]); } public function configureOptions(OptionsResolver $resolver): void