elementRepo = new FakeElementRepository(); $this->fileUploader = new FakeFileUploader(); $this->updateElement = new UpdateElement( new UpdateTitle($this->elementRepo), new UpdateDescription($this->elementRepo), new UpdateIconImageUrl($this->elementRepo, $this->fileUploader), new UpdateRichText($this->elementRepo), new UpdateShortPdfPath($this->elementRepo, $this->fileUploader), new UpdateLongPdfPath($this->elementRepo, $this->fileUploader), new UpdateYoutubeUrl($this->elementRepo), new UpdateIconImage( $this->elementRepo, $this->fileUploader, ), new UpdateShortPdf( $this->elementRepo, $this->fileUploader, ), new UpdateLongPdf( $this->elementRepo, $this->fileUploader, ), $this->elementRepo, ); } public function testUpdatesContentFields(): void { $set = $this->createSet(1, 'Baderech'); $element = $this->createElement( $set, 'Original title', 'Original description', '/assets/original-icon.png', '
Original rich text
', '/assets/pdfs/original.pdf', '/assets/pdfs/original-long.pdf', 'https://www.youtube.com/watch?v=yHx-r4p6hHU&t=1s', null, ); $updatedElement = $this->updateElement->execute( new UpdateElementRequest( id: $element->getId(), title: 'Updated title', description: 'Updated description', iconImageUrl: '/assets/updated-icon.png', richText: 'Updated rich text
', shortPdfPath: '/assets/pdfs/updated.pdf', longPdfPath: '/assets/pdfs/updated-long.pdf', pdfPath: null, youtubeUrl: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', fileType: null, fileContents: null, fileOriginalName: null, fileMimeType: null, fileSizeBytes: null, ) ); $this->assertSame($element->getId(), $updatedElement->getId()); $this->assertSame('Updated title', $updatedElement->getTitle()); $this->assertSame( 'Updated description', $updatedElement->getDescription(), ); $this->assertSame( '/assets/updated-icon.png', $updatedElement->getIconImageUrl(), ); $this->assertSame( 'Updated rich text
', $updatedElement->getRichText(), ); $this->assertSame( '/assets/pdfs/updated.pdf', $updatedElement->getShortPdfPath(), ); $this->assertSame( '/assets/pdfs/updated-long.pdf', $updatedElement->getLongPdfPath(), ); $this->assertSame( 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', $updatedElement->getYoutubeUrl(), ); $persistedElement = $this->elementRepo->find($element->getId()); $this->assertInstanceOf(Element::class, $persistedElement); $this->assertSame('Updated title', $persistedElement->getTitle()); } public function testLegacyPdfPathUpdatesShortPdfPath(): void { $set = $this->createSet(1, 'Baderech'); $element = $this->createElement( $set, 'Original title', 'Original description', null, 'Original rich text
', '/assets/pdfs/original.pdf', '/assets/pdfs/original-long.pdf', null, null, ); $updatedElement = $this->updateElement->execute( new UpdateElementRequest( id: $element->getId(), title: null, description: null, iconImageUrl: null, richText: null, shortPdfPath: null, longPdfPath: null, pdfPath: '/assets/pdfs/legacy-updated.pdf', youtubeUrl: null, fileType: null, fileContents: null, fileOriginalName: null, fileMimeType: null, fileSizeBytes: null, ) ); $this->assertSame( '/assets/pdfs/legacy-updated.pdf', $updatedElement->getShortPdfPath(), ); $this->assertSame( '/assets/pdfs/original-long.pdf', $updatedElement->getLongPdfPath(), ); } public function testConvertsEmptyNullableFieldsToNull(): void { $set = $this->createSet(1, 'Baderech'); $element = $this->createElement( $set, 'Original title', 'Original description', '/assets/original-icon.png', 'Original rich text
', '/assets/pdfs/original.pdf', '/assets/pdfs/original-long.pdf', 'https://www.youtube.com/watch?v=yHx-r4p6hHU&t=1s', null, ); $updatedElement = $this->updateElement->execute( new UpdateElementRequest( id: $element->getId(), title: 'Updated title', description: 'Updated description', iconImageUrl: '', richText: 'Updated rich text
', shortPdfPath: '', longPdfPath: '', pdfPath: null, youtubeUrl: '', fileType: null, fileContents: null, fileOriginalName: null, fileMimeType: null, fileSizeBytes: null, ) ); $this->assertNull($updatedElement->getIconImageUrl()); $this->assertNull($updatedElement->getShortPdfPath()); $this->assertNull($updatedElement->getLongPdfPath()); $this->assertNull($updatedElement->getYoutubeUrl()); } public function testUpdatesOnlySuppliedFields(): void { $set = $this->createSet(1, 'Baderech'); $element = $this->createElement( $set, 'Original title', 'Original description', '/assets/original-icon.png', 'Original rich text
', '/assets/pdfs/original.pdf', '/assets/pdfs/original-long.pdf', 'https://www.youtube.com/watch?v=yHx-r4p6hHU&t=1s', null, ); $updatedElement = $this->updateElement->execute( new UpdateElementRequest( id: $element->getId(), title: 'Updated title', description: null, iconImageUrl: null, richText: null, shortPdfPath: null, longPdfPath: null, pdfPath: null, youtubeUrl: null, fileType: null, fileContents: null, fileOriginalName: null, fileMimeType: null, fileSizeBytes: null, ) ); $this->assertSame('Updated title', $updatedElement->getTitle()); $this->assertSame( 'Original description', $updatedElement->getDescription(), ); $this->assertSame( '/assets/original-icon.png', $updatedElement->getIconImageUrl(), ); $this->assertSame( 'Original rich text
', $updatedElement->getRichText(), ); $this->assertSame( '/assets/pdfs/original.pdf', $updatedElement->getShortPdfPath(), ); $this->assertSame( '/assets/pdfs/original-long.pdf', $updatedElement->getLongPdfPath(), ); $this->assertSame( 'https://www.youtube.com/watch?v=yHx-r4p6hHU&t=1s', $updatedElement->getYoutubeUrl(), ); } public function testRoutesUploadedFilesByFileType(): void { $set = $this->createSet(1, 'Baderech'); $element = $this->createElement( $set, 'Original title', 'Original description', null, 'Original rich text
', null, null, null, null, ); $this->updateElement->execute(new UpdateElementRequest( id: $element->getId(), title: null, description: null, iconImageUrl: null, richText: null, shortPdfPath: null, longPdfPath: null, pdfPath: null, youtubeUrl: null, fileType: 'iconImage', fileContents: 'binary-image-bytes', fileOriginalName: 'icon.png', fileMimeType: 'image/png', fileSizeBytes: 1024, )); $this->updateElement->execute(new UpdateElementRequest( id: $element->getId(), title: null, description: null, iconImageUrl: null, richText: null, shortPdfPath: null, longPdfPath: null, pdfPath: null, youtubeUrl: null, fileType: 'shortPdf', fileContents: 'binary-short-pdf-bytes', fileOriginalName: 'baderech.pdf', fileMimeType: 'application/pdf', fileSizeBytes: 1024, )); $updatedElement = $this->updateElement->execute( new UpdateElementRequest( id: $element->getId(), title: null, description: null, iconImageUrl: null, richText: null, shortPdfPath: null, longPdfPath: null, pdfPath: null, youtubeUrl: null, fileType: 'longPdf', fileContents: 'binary-long-pdf-bytes', fileOriginalName: 'baderech-long.pdf', fileMimeType: 'application/pdf', fileSizeBytes: 1024, ) ); $this->assertSame( 'element-icons/fake-icon.png', $updatedElement->getIconImageUrl(), ); $this->assertSame( 'element-pdfs/short/fake-baderech.pdf', $updatedElement->getShortPdfPath(), ); $this->assertSame( 'element-pdfs/long/fake-baderech-long.pdf', $updatedElement->getLongPdfPath(), ); $this->assertSame( 'element-icons', $this->fileUploader->uploads[0]['folder'], ); $this->assertSame( 'element-pdfs/short', $this->fileUploader->uploads[1]['folder'], ); $this->assertSame( 'element-pdfs/long', $this->fileUploader->uploads[2]['folder'], ); } public function testThrowsWhenFileTypeMissingForUpload(): void { $this->expectException(BadRequestException::class); $this->expectExceptionMessage('fileType is required'); $this->updateElement->execute(new UpdateElementRequest( id: 1, title: null, description: null, iconImageUrl: null, richText: null, shortPdfPath: null, longPdfPath: null, pdfPath: null, youtubeUrl: null, fileType: null, fileContents: 'binary-image-bytes', fileOriginalName: 'icon.png', fileMimeType: 'image/png', fileSizeBytes: 1024, )); } public function testThrowsWhenFileTypeInvalid(): void { $this->expectException(BadRequestException::class); $this->expectExceptionMessage('fileType is invalid'); $this->updateElement->execute(new UpdateElementRequest( id: 1, title: null, description: null, iconImageUrl: null, richText: null, shortPdfPath: null, longPdfPath: null, pdfPath: null, youtubeUrl: null, fileType: 'audio', fileContents: 'binary-audio-bytes', fileOriginalName: 'shiur.mp3', fileMimeType: 'audio/mpeg', fileSizeBytes: 1024, )); } public function testThrowsWhenIdMissing(): void { $this->expectException(BadRequestException::class); $this->expectExceptionMessage('id is required'); $this->updateElement->execute(new UpdateElementRequest( id: null, title: 'Updated title', description: 'Updated description', iconImageUrl: null, richText: 'Updated rich text
', shortPdfPath: null, longPdfPath: null, pdfPath: null, youtubeUrl: null, fileType: null, fileContents: null, fileOriginalName: null, fileMimeType: null, fileSizeBytes: null, )); } public function testThrowsWhenNothingProvided(): void { $this->expectException(BadRequestException::class); $this->expectExceptionMessage('nothing to update'); $this->updateElement->execute(new UpdateElementRequest( id: 1, title: null, description: null, iconImageUrl: null, richText: null, shortPdfPath: null, longPdfPath: null, pdfPath: null, youtubeUrl: null, fileType: null, fileContents: null, fileOriginalName: null, fileMimeType: null, fileSizeBytes: null, )); } public function testThrowsWhenTitleIsBlank(): void { $this->expectException(BadRequestException::class); $this->expectExceptionMessage('title is required'); $this->updateElement->execute(new UpdateElementRequest( id: 1, title: '', description: 'Updated description', iconImageUrl: null, richText: 'Updated rich text
', shortPdfPath: null, longPdfPath: null, pdfPath: null, youtubeUrl: null, fileType: null, fileContents: null, fileOriginalName: null, fileMimeType: null, fileSizeBytes: null, )); } public function testThrowsWhenElementDoesNotExist(): void { $this->expectException(NotFoundException::class); $this->expectExceptionMessage('Element not found'); $this->updateElement->execute(new UpdateElementRequest( id: 999, title: 'Updated title', description: 'Updated description', iconImageUrl: null, richText: 'Updated rich text
', shortPdfPath: null, longPdfPath: null, pdfPath: null, youtubeUrl: null, fileType: null, fileContents: null, fileOriginalName: null, fileMimeType: null, fileSizeBytes: null, )); } private function createSet(int $id, string $name): DomainSet { return new DomainSet( id: $id, name: $name, description: "$name description", iconImageUrl: '/assets/baderech-icon.png', ); } private function createElement( DomainSet $set, string $title, string $description, ?string $iconImageUrl, string $richText, ?string $shortPdfPath, ?string $longPdfPath, ?string $youtubeUrl, ?Element $parentElement, ): Element { return $this->elementRepo->create(new CreateElementDto( set: $set, title: $title, description: $description, iconImageUrl: $iconImageUrl, richText: $richText, shortPdfPath: $shortPdfPath, longPdfPath: $longPdfPath, youtubeUrl: $youtubeUrl, parentElement: $parentElement, )); } }