Skip to content

Commit

Permalink
Merge pull request #43 from VSVverkeerskunde/feature/VSVGVQ-76
Browse files Browse the repository at this point in the history
VSVGVQ-76 add functionality to edit image of question
  • Loading branch information
Luc Wollants committed Jun 26, 2018
2 parents 199b585 + 9436fdd commit a662ff1
Show file tree
Hide file tree
Showing 10 changed files with 267 additions and 11 deletions.
6 changes: 6 additions & 0 deletions config/routes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ questions_view_edit:
methods: [GET, POST]
requirements:
_locale: nl|fr
questions_view_edit_image:
path: /{_locale}/view/questions/image/edit/{id}
controller: VSV\GVQ_API\Question\Controllers\QuestionViewController::editImage
methods: [GET, POST]
requirements:
_locale: nl|fr
questions_view_delete:
path: /{_locale}/view/questions/delete/{id}
controller: VSV\GVQ_API\Question\Controllers\QuestionViewController::delete
Expand Down
19 changes: 16 additions & 3 deletions src/Image/Controllers/ImageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace VSV\GVQ_API\Image\Controllers;

use League\Flysystem\FileExistsException;
use League\Flysystem\FileNotFoundException;
use League\Flysystem\Filesystem;
use Ramsey\Uuid\UuidFactoryInterface;
use Symfony\Component\HttpFoundation\File\UploadedFile;
Expand Down Expand Up @@ -46,7 +48,7 @@ public function __construct(
/**
* @param Request $request
* @return Response
* @throws \League\Flysystem\FileExistsException
* @throws FileExistsException
*/
public function upload(Request $request): Response
{
Expand All @@ -63,14 +65,14 @@ public function upload(Request $request): Response
/**
* @param UploadedFile $uploadedFile
* @return NotEmptyString
* @throws \League\Flysystem\FileExistsException
* @throws FileExistsException
*/
public function handleImage(UploadedFile $uploadedFile): NotEmptyString
{
$this->imageValidator->validate($uploadedFile);

$uuid = $this->uuidFactory->uuid4();
$filename = $uuid->toString().'.'. $uploadedFile->getClientOriginalExtension();
$filename = $uuid->toString().'.'.$uploadedFile->getClientOriginalExtension();

$stream = fopen($uploadedFile->getRealPath(), 'r+');
$this->fileSystem->writeStream($filename, $stream);
Expand All @@ -79,6 +81,17 @@ public function handleImage(UploadedFile $uploadedFile): NotEmptyString
return new NotEmptyString($filename);
}

/**
* @param string $fileName
* @throws FileNotFoundException
*/
public function delete(string $fileName)
{
if ($this->fileSystem->has($fileName)) {
$this->fileSystem->delete($fileName);
}
}

/**
* @param FileBag $files
* @return UploadedFile
Expand Down
91 changes: 91 additions & 0 deletions src/Question/Controllers/QuestionViewController.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
use Symfony\Component\Translation\TranslatorInterface;
use VSV\GVQ_API\Common\ValueObjects\Language;
use VSV\GVQ_API\Common\ValueObjects\Languages;
use VSV\GVQ_API\Common\ValueObjects\NotEmptyString;
use VSV\GVQ_API\Image\Controllers\ImageController;
use VSV\GVQ_API\Question\Forms\ImageFormType;
use VSV\GVQ_API\Question\Forms\QuestionFormType;
use VSV\GVQ_API\Question\Models\Question;
use VSV\GVQ_API\Question\Models\Questions;
Expand Down Expand Up @@ -49,6 +51,11 @@ class QuestionViewController extends AbstractController
*/
private $questionFormType;

/**
* @var ImageFormType
*/
private $imageFormType;

/**
* @param UuidFactoryInterface $uuidFactory
* @param QuestionRepository $questionRepository
Expand All @@ -70,6 +77,7 @@ public function __construct(
$this->translator = $translator;

$this->questionFormType = new QuestionFormType();
$this->imageFormType = new ImageFormType();
}

/**
Expand Down Expand Up @@ -189,6 +197,51 @@ public function edit(Request $request, string $id): Response
);
}

/**
* @param Request $request
* @param string $id
* @return Response
* @throws \League\Flysystem\FileExistsException
* @throws \League\Flysystem\FileNotFoundException
*/
public function editImage(Request $request, string $id): Response
{
$question = $this->questionRepository->getById(
$this->uuidFactory->fromString($id)
);

if (!$question) {
$this->addFlash('warning', 'Geen vraag gevonden met id '.$id.' om aan te passen.');
return $this->redirectToRoute('questions_view_index');
}

$form = $this->createEditImageForm();
$form->handleRequest($request);

if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();

$fileName = $this->imageController->handleImage($data['image']);
$this->imageController->delete($question->getImageFileName()->toNative());

$question = $this->updateQuestionImage(
$question,
$fileName
);
$this->questionRepository->update($question);

$this->addFlash('success', 'Foto van vraag '.$id.' is aangepast.');
return $this->redirectToRoute('questions_view_index');
}

return $this->render(
'questions/edit_image.html.twig',
[
'form' => $form->createView(),
]
);
}

/**
* @param Request $request
* @param string $id
Expand Down Expand Up @@ -235,6 +288,23 @@ private function createQuestionForm(?Question $question): FormInterface
return $formBuilder->getForm();
}

/**
* @return FormInterface
*/
private function createEditImageForm(): FormInterface
{
$formBuilder = $this->createFormBuilder();

$this->imageFormType->buildForm(
$formBuilder,
[
'translator' => $this->translator,
]
);

return $formBuilder->getForm();
}

/**
* @param Request $request
* @return null|Language
Expand Down Expand Up @@ -274,4 +344,25 @@ private function filterQuestions(

return $filteredQuestions;
}

/**
* @param Question $question
* @param NotEmptyString $imageFileName
* @return Question
*/
public function updateQuestionImage(
Question $question,
NotEmptyString $imageFileName
): Question {
return new Question(
$question->getId(),
$question->getLanguage(),
$question->getYear(),
$question->getCategory(),
$question->getText(),
$imageFileName,
$question->getAnswers(),
$question->getFeedback()
);
}
}
47 changes: 47 additions & 0 deletions src/Question/Forms/ImageFormType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php declare(strict_types=1);

namespace VSV\GVQ_API\Question\Forms;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Validator\Constraints\NotBlank;

class ImageFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
/** @var TranslatorInterface $translator */
$translator = $options['translator'];

$builder
->add(
'image',
FileType::class,
[
'constraints' => [
new NotBlank(
[
'message' => $translator->trans('Empty field'),
]
),

],
]
);
}

/**
* @inheritdoc
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
[
'translator' => null,
]
);
}
}
25 changes: 25 additions & 0 deletions templates/questions/edit_image.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{% extends 'admin_index_base.html.twig' %}

{% block title %}{% trans %}Change.picture{% endtrans %}{% endblock %}

{% block content %}

{{ form_start(form, {'attr': {'novalidate': 'novalidate'}}) }}

<div class="form-group">
<label for="question_form_image">{% trans %}Foto{% endtrans %}</label>
{{ form_widget(form.image, {'attr': {'style': 'opacity: 1'}}) }}
{{ form_errors(form.image) }}
</div>

<div class="form-group">
<a role="button"
class="btn btn-secondary"
href="{{ path('questions_view_index') }}">{% trans %}Annuleren{% endtrans %}
</a>
<button type="submit" class="btn btn-primary">{% trans %}Bewaar{% endtrans %}</button>
</div>

{{ form_end(form) }}

{% endblock %}
5 changes: 5 additions & 0 deletions templates/questions/index.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@
href="{{ path('questions_view_edit', {'id': question.id.toString}) }}" >
<span class="oi oi-pencil"></span>{% trans %}Aanpassen{% endtrans %}
</a>
<a role="button"
class="btn btn-light"
href="{{ path('questions_view_edit_image', {'id': question.id.toString}) }}">
<span class="oi oi-image"></span>{% trans %}Change.picture{% endtrans %}
</a>
<a role="button"
class="btn btn-light"
href="{{ path('questions_view_delete', {'id': question.id.toString}) }}">
Expand Down
57 changes: 49 additions & 8 deletions tests/Image/Controllers/ImageControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace VSV\GVQ_API\Image\Controllers;

use League\Flysystem\FileExistsException;
use League\Flysystem\FileNotFoundException;
use League\Flysystem\Filesystem;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
Expand Down Expand Up @@ -33,9 +35,6 @@ class ImageControllerTest extends TestCase
*/
private $imageController;

/**
* @throws \ReflectionException
*/
protected function setUp(): void
{
/** @var Filesystem|MockObject $fileSystem */
Expand All @@ -59,8 +58,7 @@ protected function setUp(): void

/**
* @test
* @throws \League\Flysystem\FileExistsException
* @throws \ReflectionException
* @throws FileExistsException
*/
public function it_can_handle_a_file_upload(): void
{
Expand Down Expand Up @@ -107,7 +105,7 @@ public function it_can_handle_a_file_upload(): void

/**
* @test
* @throws \League\Flysystem\FileExistsException
* @throws FileExistsException
*/
public function it_requires_exactly_one_file(): void
{
Expand All @@ -121,8 +119,7 @@ public function it_requires_exactly_one_file(): void

/**
* @test
* @throws \League\Flysystem\FileExistsException
* @throws \ReflectionException
* @throws FileExistsException
*/
public function it_requires_image_key(): void
{
Expand All @@ -141,4 +138,48 @@ public function it_requires_image_key(): void

$this->imageController->upload($request);
}

/**
* @test
* @throws FileNotFoundException
*/
public function it_deletes_the_previous_image_if_it_exists(): void
{
$fileName = 'existingImage.jpg';

$this->fileSystem
->expects($this->once())
->method('has')
->with($fileName)
->willReturn(true);

$this->fileSystem
->expects($this->once())
->method('delete')
->with($fileName);

$this->imageController->delete($fileName);
}

/**
* @test
* @throws FileNotFoundException
*/
public function it_does_not_try_to_delete_nonexisting_image(): void
{
$fileName = 'existingImage.jpg';

$this->fileSystem
->expects($this->once())
->method('has')
->with($fileName)
->willReturn(false);

$this->fileSystem
->expects($this->never())
->method('delete')
->with($fileName);

$this->imageController->delete($fileName);
}
}
Loading

0 comments on commit a662ff1

Please sign in to comment.