i have test class like this
class CallTest extends WebTestCase
{
/** #var \Doctrine\Common\DataFixtures\Executor\AbstractExecutor */
protected $executor;
public function setUp()
{
$this->executor = $this->loadFixtures(array('Tests\Fixtures\LoadCallData'));
}
/**
* #dataProvider callProvider
*/
public function testCall($service, $token, $fileId, $phone, $callTime)
{
// some code for testing
}
/**
* Данные для проверки
* #return array
*/
public function callProvider()
{
$devices = $this->devicesProvider();
// providing some data
return array(.....);
}
public function devicesProvider()
{
return array_map(
function ($device) use($service) {
return array($service, $device);
},
$devices
);
}
}
problem is that setUp method not rans
Related
The flush function does not add anything to the database even though it doesn't return any error.
Any idea of how can I solve that?
Thanks in advance for your help!
Here is my code:
Controller:
#[Route("/messages")]
public function create(Request $request, ManagerRegistry $signup, UserRepository $userRepository, MessageRepository $messageRepository): Response
{
$message = new Message();
$userRepository = $signup->getRepository(User::class);
$formdico = [];
foreach ($userRepository->findAll() as $user) {
$userform = $this->createForm(MessageType::class, $message);
$formdico[$user->getId()] = $userform;
}
foreach ($formdico as $form) {
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$newMessage = new Message();
$newMessage->setSender($userRepository->findOneById($form->getData()->getSender()));
$newMessage->setReceiver($userRepository->findOneById($form->getData()->getSender()));
$newMessage->setContent($form->getData()->getContent());
$newMessage->setCreatedAt(new \DateTime('now'));
$em = $signup->getManager();
$em->persist($newMessage);
$em->flush($newMessage);
}
}
foreach ($userRepository->findAll() as $user) {
$userform = $this->createForm(MessageType::class, $message);
$formdico[$user->getId()] = $userform->createView();
}
return $this->render('message/readAllUser.html.twig', ['users' => $userRepository->findAll(), "formdico" => $formdico, 'messages' => $messageRepository->findAll()]);
}
Entity:
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity()]
class Message
{
#[ORM\Id]
#[ORM\GeneratedValue(strategy: "AUTO")]
#[ORM\Column(type: "integer")]
private int $id;
#[ORM\ManyToOne(targetEntity: "App\Entity\User", inversedBy: "sendedMessages")]
private $sender;
#[ORM\ManyToOne(targetEntity: "App\Entity\User", inversedBy: "receivedMessages")]
private $receiver;
#[ORM\Column(type: "text")]
private string $content;
#[ORM\Column(type: "date")]
private \DateTime $createdAt;
/**
* Get the value of id
*/
public function getId()
{
return $this->id;
}
/**
* Set the value of id
*
* #return self
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* Get the value of sender
*/
public function getSender()
{
return $this->sender;
}
/**
* Set the value of sender
*
* #return self
*/
public function setSender($sender)
{
$this->sender = $sender;
return $this;
}
/**
* Get the value of receiver
*/
public function getReceiver()
{
return $this->receiver;
}
/**
* Set the value of receiver
*
* #return self
*/
public function setReceiver($receiver)
{
$this->receiver = $receiver;
return $this;
}
/**
* Get the value of content
*/
public function getContent()
{
return $this->content;
}
/**
* Set the value of content
*
* #return self
*/
public function setContent($content)
{
$this->content = $content;
return $this;
}
/**
* Get the value of createdAt
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* Set the value of createdAt
*
* #return self
*/
public function setCreatedAt($createdAt)
{
$this->createdAt = $createdAt;
return $this;
}
}
Form:
<?php
namespace App\Form;
use App\Entity\Message;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
class MessageType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('sender', IntegerType::class, [])
->add('content', TextType::class, ['label' => false, 'attr' => ['placeholder' => 'Message Content']])
->add('receiver', IntegerType::class, []);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults(['data_class' => Message::class,]);
}
}
I tried removing the persist, dumped a lot of things to try understanding the problem but I can't get to solve this...
And the form is valid
I'm writing PHPUnit tests and running coverage tests. I admit its very difficult to have 100% coverage, however, I'd like to get as close as possible. In a following scenario, how to mock variables in a clause in order to test the code block?
class CalendarClientService
{
/** #var array SCOPES */
public const SCOPES = [Google_Service_Calendar::CALENDAR];
/** #var string ACCESS_TYPE */
public const ACCESS_TYPE = "offline";
/** #var string CALENDAR_ID */
public const CALENDAR_ID = "primary";
/** #var int MAX_RESULTS */
public const MAX_RESULTS = 25;
/** #var string ORDER_BY */
public const ORDER_BY = "startTime";
/** #var bool SINGLE_EVENTS */
public const SINGLE_EVENTS = true;
/** #var string|null TIME_MIN */
public const TIME_MIN = null;
/** #var bool CACHE_TIME_TO_LIVE */
public const CACHE_TIME_TO_LIVE = 604800;
/** #var string */
public string $clientSecretPath = "";
/** #var StorageAdapterFactoryInterface */
protected StorageAdapterFactoryInterface $storageAdapterFactory;
/** #var StorageInterface */
protected StorageInterface $storageInterfaceCache;
/**
* CalendarClientService constructor.
* #param string $clientSecretPath
* #param StorageAdapterFactoryInterface $storageAdapterFactory
* #param StorageInterface $storageInterfaceCache
*/
public function __construct(
string $clientSecretPath,
StorageAdapterFactoryInterface $storageAdapterFactory,
StorageInterface $storageInterfaceCache
) {
$this->clientSecretPath = $clientSecretPath;
$this->storageAdapterFactory = $storageAdapterFactory;
$this->storageInterfaceCache = $storageInterfaceCache;
}
/** #return string */
public function getClientSecretPath()
{
return $this->clientSecretPath;
}
/** #param string $secretFile */
public function setClientSecretPath(string $secretFile)
{
$this->clientSecretPath = $secretFile;
}
/**
* #param array
* #return Google_Service_Calendar_Event
*/
public function getGoogleServiceCalendarEvent($eventData)
{
return new Google_Service_Calendar_Event($eventData);
}
/**
* #param string
* #return Google_Service_Calendar_EventDateTime
*/
public function getGoogleServiceCalendarEventDateTime($dateTime)
{
$eventDateTime = new Google_Service_Calendar_EventDateTime();
$eventDateTime->setDateTime(Carbon::parse($dateTime)->toW3cString());
$eventDateTime->setTimeZone(Carbon::parse($dateTime)->timezone->getName());
return $eventDateTime;
}
/**
* #param Google_Client $client
* #return Events
*/
public function getGoogleServiceCalendarResourceEvents(Google_Client $client)
{
$service = new Google_Service_Calendar($client);
return $service->events;
}
/**
* #param int
* #return array
* #throws Exception
* #throws ExceptionInterface
*/
public function getEventData($id)
{
$client = $this->getClient();
if (!$this->authenticateClient($client)) {
return [
"error" => "authentication",
"url" => filter_var($client->createAuthUrl(), FILTER_SANITIZE_URL),
];
}
$service = $this->getGoogleServiceCalendarResourceEvents($client);
return ["event" => $service->get(self::CALENDAR_ID, $id)];
}
/**
* #return Google_Client
* #throws Exception
*/
public function getClient()
{
$client = new Google_Client();
$client->setApplicationName(Module::MODULE_NAME);
$client->setScopes(self::SCOPES);
$client->setAuthConfig($this->clientSecretPath);
$client->setAccessType(self::ACCESS_TYPE);
return $client;
}
/**
* #param Google_Client $client
* #return bool
* #throws ExceptionInterface
*/
public function authenticateClient(Google_Client $client)
{
if ($this->storageInterfaceCache->hasItem("api_access_token")) {
$accessToken = json_decode($this->storageInterfaceCache->getItem("api_access_token"), true);
if ($accessToken["error"] == "invalid_grant" || empty($accessToken)) {
$this->storageInterfaceCache->removeItem("api_access_token");
} else {
$this->storageInterfaceCache->setItem("api_access_token", json_encode($accessToken));
$client->setAccessToken($accessToken);
}
}
if ($client->isAccessTokenExpired()) {
$tokenValid = false;
if ($client->getRefreshToken()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
$accessToken = $client->getAccessToken();
$this->storageInterfaceCache->setItem("api_access_token", json_encode($accessToken));
$tokenValid = true;
} else {
$helper = new Helper();
if(!$helper->verifyAuthCode($_GET["code"])){
return $tokenValid;
}
$authCode = $_GET["code"];
$accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
if ($accessToken["error"] == "invalid_grant" || empty($accessToken)) {
$this->storageInterfaceCache->removeItem("api_access_token");
} else {
$this->storageInterfaceCache->setItem("api_access_token", json_encode($accessToken));
$client->setAccessToken($accessToken);
$tokenValid = true;
}
}
} else {
$tokenValid = true;
}
return isset($tokenValid) ? $tokenValid : false;
}
I want to test this 6th line from top in authenticateClient method and want to mock this clause $accessToken["error"] == "invalid_grant" || empty($accessToken).
Now how to go about it?
Edit: Here's a test that I've written. Now whatever value I'm mocking in the $this->storageInterfaceCacheMock->method("getItem"), it always returns empty $accessToken. I've also attached the image for better understanding of what's happening and what I want.
public function testGetEventDataReturnsArrayOnSuccessfulAuthenticateClientThroughCache()
{
$this->storageInterfaceCacheMock->method("hasItem")->willReturn(true);
$this->storageInterfaceCacheMock->method("getItem")->willReturn(json_encode('{"access_token":"ya29.a0ARrdaM99pJTf1XzmD1ngxAH3XJud8lvHb0aTaOOABYdfdhsdfgsdfgVD9OoH4heiKoskDF7DMkHj1_aPuWIO5TE14KHJidFf66xwn_pTCkkSow6Kg4lRHwGrNQBQGI8sPlgnFO5U5hJvYdqgxDMHEqw1TER2w","expires_in":3599,"scope":"https:\/\/www.googleapis.com\/auth\/calendar","token_type":"Bearer","created":1637312218,"refresh_token":"1\/\/03psr5omKiljUCgYFDHDGJHGSHSNwF-L9Iraor5zcfe-h3BeCHSFGSDFGDGJHjy4UnEtKj974LXthS5bWexQcjviVGfJsdfGHSHgIrDn6Yk"}'));
$this->assertIsArray($this->calendarClientService->getEventData(1));
}
Another test which isn't performing as per required is mentioned below. (also visible in the screenshot)
public function testAccessTokenIsExpiredAndGotRefreshToken()
{
$this->googleClientMock->method("isAccessTokenExpired")->willReturn(true);
$this->googleClientMock->method("getRefreshToken")->willReturn(true);
$this->googleClientMock->method("fetchAccessTokenWithRefreshToken")->willReturnSelf();
$this->googleClientMock->method("getAccessToken")->willReturnSelf();
$this->assertTrue($this->calendarClientService->authenticateClient($this->googleClientMock));
}
I believe you want json_decode you don't need double encode here:
$this->storageInterfaceCacheMock->method("getItem")->willReturn(json_encode('{"access_token":"...."}'));
just
$this->storageInterfaceCacheMock->method("getItem")->willReturn('{"access_token":"...."}');
Here's how I resolved the issue and got the test to be successful.
I declared a dummy ACCESS_TOKEN as below and then used in the test method.
class CalendarControllerTest extends AbstractApplicationTestCase
{
/** #var string CLIENT_SECRET */
public const CLIENT_SECRET = __DIR__ . "/../_fixtures/config/client_secret.json";
/** #var string CLIENT_SECRET */
public const ACCESS_TOKEN = [
"access_token" => "test-data",
"expires_in" => 3592,
"scope" => "https://www.googleapis.com/auth/calendar",
"token_type" => "Bearer",
"created" => 1640858809,
];
...
...
...
}
public function setUp(): void
{
parent::setUp();
$this->googleClientMock = $this->getMockBuilder(Google_Client::class)
->disableOriginalConstructor()
->onlyMethods(
[
"isAccessTokenExpired",
"setAuthConfig",
"getRefreshToken",
"fetchAccessTokenWithRefreshToken",
"fetchAccessTokenWithAuthCode",
"getAccessToken",
"setAccessToken",
]
)
->getMock();
$this->googleServiceCalendarResourceEventsMock = $this->getMockBuilder(Events::class)
->disableOriginalConstructor()
->onlyMethods(["get"])
->getMock();
$this->googleServiceCalendarEventMock = $this->getMockBuilder(Event::class)
->disableOriginalConstructor()
->getMock();
$this->storageInterfaceCacheMock = $this->getMockForAbstractClass(StorageInterface::class);
$this->container->setAllowOverride(true);
$this->container->setService(Google_Client::class, $this->googleClientMock);
$this->container->setService(Events::class, $this->googleServiceCalendarResourceEventsMock);
$this->container->setService(Event::class, $this->googleServiceCalendarEventMock);
$this->container->setService(StorageInterface::class, $this->storageInterfaceCacheMock);
$this->container->setAllowOverride(true);
$this->googleClientMock->method("setAuthConfig")->willReturn(true);
$this->calendarClientService = $this->container->get("ServiceManager")->get(CalendarClientService::class);
$this->calendarClientService->setClientSecretPath(CalendarControllerTest::CLIENT_SECRET);
}
/** #throws ExceptionInterface */
public function testAccessTokenIsExpiredAndFailureToRefreshTokenWillGenerateNewAccessToken()
{
$this->calendarClientService->setAuthCode(CalendarControllerTest::DEFAULT_TESTING_VALUE);
$this->googleClientMock->method("isAccessTokenExpired")->willReturn(true);
$this->googleClientMock->method("getRefreshToken")->willReturn(false);
$this->googleClientMock->method("fetchAccessTokenWithAuthCode")->willReturn(
CalendarControllerTest::ACCESS_TOKEN
);
$this->storageInterfaceCacheMock->method("setItem")->willReturn(true);
$this->googleClientMock->method("setAccessToken")->willReturnSelf();
$this->assertTrue($this->calendarClientService->authenticateClient($this->googleClientMock));
}
I'm trying to show preview image with Sonata Admin Bundle 3 version but I can't do it. I get this error in RecipeAdmin.php: Could not load type "file": class does not exist.
RecipeAdmin.php
<?php
declare(strict_types=1);
namespace App\Admin;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Show\ShowMapper;
use Sonata\Form\Type\CollectionType;
use Sonata\AdminBundle\Form\Type\ModelListType;
final class RecipeAdmin extends AbstractAdmin
{
protected function configureDatagridFilters(DatagridMapper $datagridMapper): void
{
$datagridMapper
->add('title',null,['label' =>'Título'])
->add('image',null,['label' =>'Imagen'])
->add('description',null,['label' =>'Descripción'])
->add('score',null,['label' =>'Puntuación'])
->add('visible')
;
}
protected function configureListFields(ListMapper $listMapper): void
{
$listMapper
->add('id')
->add('user', CollectionType::class,['label' =>'Usuario'])
->add('title',null,['label' =>'Título'])
->add('image',null,['label' =>'Imagen'])
->add('description',null,['label' =>'Descripción'])
->add('score',null,['label' =>'Puntuación'])
->add('visible',null,['label' =>'Visible'])
->add('_action', null, [
'label' => 'Acciones',
'actions' => [
'show' => [],
'edit' => [],
'delete' => [],
],
]);
}
protected function configureFormFields(FormMapper $formMapper): void
{
$image = $this->getSubject();
// use $fileFormOptions so we can add other options to the field
$fileFormOptions = ['required' => false];
if ($image && ($webPath = $image->getImage())) {
// get the request so the full path to the image can be set
$request = $this->getRequest();
$fullPath = $request->getBasePath().'/'.$webPath;
// add a 'help' option containing the preview's img tag
$fileFormOptions['help'] = '<img src="'.$fullPath.'" class="admin-preview"/>';
$fileFormOptions['help_html'] = true;
}
$formMapper
->add('title',null,['label' =>'Título'])
->add('image', 'file', $fileFormOptions)
->add('description',null,['label' =>'Descripción'])
->add('score',null,['label' =>'Puntuación'])
->add('visible')
;
}
protected function configureShowFields(ShowMapper $showMapper): void
{
$showMapper
->add('title',null,['label' =>'Título'])
->add('image',null,['label' =>'Imagen'])
->add('description',null,['label' =>'Descripción'])
->add('user', CollectionType::class)
->add('score',null,['label' =>'Puntuaciones'])
->add('visible')
;
}
}
Recipe.php Entity
<?php
namespace App\Entity;
use App\Repository\RecipeRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass=RecipeRepository::class)
*/
class Recipe
{
public function __construct() {
$this->categories = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $title;
/**
* #ORM\Column(type="string", length=255)
*/
private $image;
/**
* #ORM\Column(type="string", length=255)
*/
private $description;
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="recipes")
* #ORM\JoinColumn(nullable=false)
*/
private $user;
/**
* #ORM\Column(type="integer", nullable=true)
*/
private $score;
/**
* #ORM\Column(type="boolean")
*/
private $visible;
/**
* #ORM\ManyToMany(targetEntity="Category", inversedBy="recipe", cascade={"persist"})
* #ORM\JoinTable(name="recipes_categories")
*/
private $categories;
public function getId(): ?int
{
return $this->id;
}
public function setId(int $id)
{
$this->id = $id;
return $this;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getImage(): ?string
{
return $this->image;
}
public function setImage(string $image): self
{
$this->image = $image;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(string $description): self
{
$this->description = $description;
return $this;
}
public function getUser()
{
return $this->user;
}
public function setUser($user)
{
$this->user = $user;
return $this;
}
public function getScore(): ?int
{
return $this->score;
}
public function setScore(?int $score): self
{
$this->score = $score;
return $this;
}
public function getVisible(): ?bool
{
return $this->visible;
}
public function setVisible(bool $visible): self
{
$this->visible = $visible;
return $this;
}
public function getCategories()
{
return $this->categories;
}
public function setCategories($categories)
{
$this->categories = $categories;
return $this;
}
public function __toString()
{
return $this->getTitle();
}
public function addCategory(Category $category): self
{
if (!$this->categories->contains($category)) {
$this->categories[] = $category;
}
return $this;
}
public function removeCategory(Category $category): self
{
$this->categories->removeElement($category);
return $this;
}
}
This is the link about how do it: https://symfony.com/doc/current/bundles/SonataAdminBundle/cookbook/recipe_image_previews.html
https://sonata-project.org/bundles/admin/master/doc/cookbook/recipe_image_previews.html#showing-image-previews
In the documentation explains that I have to use 'file' type fields but when I use it in my proyect doesn't runs.
This is an error in the doc, instead of file you should use FileType::class and adding :
use Symfony\Component\Form\Extension\Core\Type\FileType;
$formMapper
->add('title',null,['label' =>'Título'])
->add('image', FileType::class, $fileFormOptions)
You will still have error such as :
The form's view data is expected to be an instance of class Symfony\Component\HttpFoundation\File\File, but is a(n) string. You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms a(n) string to an instance of Symfony\Component\HttpFoundation\File\File.
In the cookbook they tell you to create an Image Entity so you should add it and follow all the steps :
https://sonata-project.org/bundles/admin/master/doc/cookbook/recipe_file_uploads.html
I suggest instead of following this cookbook, you should install and use the sonata media, the integration is easier and it have some nice features such as making different formats for your upload.
I'm currently doing app that's similar to imgur and I'm receiving following error
An exception occurred while executing 'INSERT INTO user_gallery_views (gallery_id, user_id) VALUES (?, ?)' with params [1, 1]:
SQLSTATE[23000]: Integrity constraint violation: 19 UNIQUE constraint failed: user_gallery_views.gallery_id, user_gallery_views.user_id
It occurs while calling path to add object as saved in users collection
Related part of App Controller
/**
* #Route("/image/{id}", name="imgDisp", methods={"GET"})
*/
public function imgDisp($id)
{
$img = $this->gR->findBy(['id'=>$id]);
if ($img) {
$img = $img[0];
$img->setImage(stream_get_contents($img->getImage()));
}
if($this->ls)
{
$this->viewMod($id);
}
return $this->render('app/imgDisp.html.twig', [
'img'=>$img
]);
}
/**
* #Route("/image/{id}/like", name="likeImg", methods={"POST"})
*/
public function likeImg($id)
{
$img = $this->gR->findBy(['id'=>$id])[0];
$user = $this->uR->findBy(['id'=>$this->session->get('user')->getId()])[0];
if(!$img->getLikes()->contains($user))
{
$img->addLike($user);
}
else
{
$img->removeLike($user);
}
$this->em->flush();
return $this->redirectToRoute('imgDisp', ['id'=>$id]);
}
/**
* #Route("/image/{id}/save", name="saveImg", methods={"POST"})
*/
public function saveImg($id)
{
$img = $this->gR->findBy(['id'=>$id])[0];
$user = $this->uR->findBy(['id'=>$this->session->get('user')->getId()])[0];
if(!$img->getSaves()->contains($user))
{
$img->addSave($user);
}
else
{
$img->removeSave($user);
}
$this->em->flush();
return $this->redirectToRoute('imgDisp', ['id'=>$id]);
}
private function viewMod($id)
{
$img = $this->gR->findBy(['id'=>$id])[0];
$user = $this->uR->findBy(['id'=>$this->session->get('user')->getId()])[0];
if(!$img->getViews()->contains($user))
{
$img->addView($user);
$this->em->flush();
}
}
Gallery entity (part related to problem)
/**
* #ORM\ManyToMany(targetEntity="App\Entity\User", inversedBy="likes")
* #ORM\JoinTable(name="user_gallery_likes")
*/
private $likes;
/**
* #ORM\ManyToMany(targetEntity="App\Entity\User", inversedBy="collection")
* #ORM\JoinTable(name="user_gallery_saves")
*/
private $saves;
/**
* #ORM\ManyToMany(targetEntity="App\Entity\User", inversedBy="views")
* #ORM\JoinTable(name="user_gallery_views")
*/
private $views;
/**
* #return Collection|User[]
*/
public function getLikes(): Collection
{
return $this->likes;
}
public function addLike(User $like): self
{
if (!$this->likes->contains($like)) {
$this->likes[] = $like;
}
return $this;
}
public function removeLike(User $like): self
{
if ($this->likes->contains($like)) {
$this->likes->removeElement($like);
}
return $this;
}
/**
* #return Collection|User[]
*/
public function getSaves(): Collection
{
return $this->saves;
}
public function addSave(User $save): self
{
if (!$this->saves->contains($save)) {
$this->views[] = $save;
}
return $this;
}
public function removeSave(User $save): self
{
if ($this->saves->contains($save)) {
$this->saves->removeElement($save);
}
return $this;
}
/**
* #return Collection|User[]
*/
public function getViews(): Collection
{
return $this->views;
}
public function addView(User $view): self
{
if (!$this->views->contains($view)) {
$this->views[] = $view;
}
return $this;
}
Users entity (part related to problem)
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Gallery", mappedBy="saves")
*/
private $collection;
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Gallery", mappedBy="likes")
*/
private $likes;
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Gallery", mappedBy="views")
*/
private $views;
/**
* #return Collection|Gallery[]
*/
public function getCollection(): Collection
{
return $this->collection;
}
public function addCollection(Gallery $collection): self
{
if (!$this->collection->contains($collection)) {
$this->collection[] = $collection;
}
return $this;
}
public function removeCollection(Gallery $collection): self
{
if ($this->collection->contains($collection)) {
$this->collection->removeElement($collection);
}
return $this;
}
/**
* #return Collection|Gallery[]
*/
public function getLikes(): Collection
{
return $this->likes;
}
public function addLike(Gallery $like): self
{
if (!$this->likes->contains($like)) {
$this->likes[] = $like;
$like->addLike($this);
}
return $this;
}
public function removeLike(Gallery $like): self
{
if ($this->likes->contains($like)) {
$this->likes->removeElement($like);
$like->removeLike($this);
}
return $this;
}
/**
* #return Collection|Gallery[]
*/
public function getViews(): Collection
{
return $this->views;
}
public function addView(Gallery $view): self
{
if (!$this->views->contains($view)) {
$this->views[] = $view;
$view->addView($this);
}
return $this;
}
The point I don't get is why error concern user_galler_views when it's not even used in /image/{id}/save?
I'm for sure not seeing something but don't even know what, so I'm full of hope u gonna help me
It looks like you are storing the entity to the wrong Array.
public function addSave(User $save): self
{
if (!$this->saves->contains($save)) {
$this->views[] = $save;
}
return $this;
}
You check for $this->saves->contains($save) but then you store the data not to saves but to views.
$this->views[] = $save;
It is probably a coincidence that the save entity has the same id as another view entity that is already assigned to the gallery.
Im trying to upload a file using SonataAdminBundle.
I don't know what am I doing wrong as I followed instructions from official documentation https://sonata-project.org/bundles/admin/3-x/doc/cookbook/recipe_file_uploads.html
The upload() function is not triggering, and even when I invoke the method in DocumentAdmin it does not put the files in the directory I specified.
It seems like the yaml file is not even read, but how am I supposed to configure it ?
prePersist() and preUpdate() are triggered even without it.
Code:
final class DocumentAdmin extends AbstractAdmin
{
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->add('title', null, [
'label' => 'Name'
])
->add('documentCategory', null, [
'label' => 'Typ'
])
->add('priority', null, [
'label' => 'Order'
])
;
}
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('file', FileType::class, [
'required' => true,
])
->add('title', null, [
'label' => 'Name'
])
->add('priority', null, [
'label' => 'Priority'
])
->add('documentCategory', null, [
'label' => 'Typ'
])
;
}
public function prePersist($document)
{
$this->manageFileUpload($document);
}
public function preUpdate($document)
{
$this->manageFileUpload($document);
}
private function manageFileUpload($document)
{
if ($document->getFile()) {
$document->refreshUpdated();
}
}
public function toString($object)
{
return $object instanceof Document
? $object->getTitle()
: 'File'; // shown in the breadcrumb on the create view
}
}
Document Entity
class Document
{
const SERVER_PATH_TO_DOCUMENTS_FOLDER = '%kernel.project_dir%/public/uploads';
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* Unmapped property to handle file uploads
*/
private $file;
/**
* #param UploadedFile $file
*/
public function setFile(UploadedFile $file = null)
{
$this->file = $file;
}
/**
* #return UploadedFile
*/
public function getFile()
{
return $this->file;
}
/**
* Manages the copying of the file to the relevant place on the server
*/
public function upload()
{
// the file property can be empty if the field is not required
if (null === $this->getFile()) {
return;
}
// we use the original file name here but you should
// sanitize it at least to avoid any security issues
// move takes the target directory and target filename as params
$file = $this->getFile();
$directory = self::SERVER_PATH_TO_DOCUMENTS_FOLDER;
$originaName = $this->getFile()->getClientOriginalName();
// dump($file);
// dump($directory);
// dump($originaName);
// die();
$file->move($directory, $originaName);
// set the path property to the filename where you've saved the file
// clean up the file property as you won't need it anymore
$this->setFile(null);
}
/**
* Lifecycle callback to upload the file to the server.
*/
public function lifecycleFileUpload()
{
$this->upload();
}
/**
* Updates the hash value to force the preUpdate and postUpdate events to fire.
*/
public function refreshUpdated()
{
$this->setDateOfUpload(new \DateTime());
}
/**
* #ORM\Column
* #Gedmo\UploadableFileName
*/
private $title;
/**
* #Gedmo\Timestampable(on="create")
* #ORM\Column(type="datetime")
*/
private $dateOfUpload;
/**
* #ORM\Column(type="smallint")
*/
private $priority;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\DocumentCategory", inversedBy="documents")
* #ORM\JoinColumn(nullable=false)
*/
private $documentCategory;
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
/**
* #return \DateTime
*/
public function getDateOfUpload()
{
return $this->dateOfUpload;
}
public function setDateOfUpload(\DateTimeInterface $dateOfUpload): self
{
$this->dateOfUpload = new \DateTime();
return $this;
}
public function getPriority(): ?int
{
return $this->priority;
}
public function setPriority(int $priority): self
{
$this->priority = $priority;
return $this;
}
public function getDocumentCategory(): ?DocumentCategory
{
return $this->documentCategory;
}
public function setDocumentCategory(?DocumentCategory $documentCategory): self
{
$this->documentCategory = $documentCategory;
return $this;
}
// public function myCallbackMethod(array $info)
// {
// }
public function __toString()
{
return $this->title;
}
}
EDIT: I changed the file directory path to:
const SERVER_PATH_TO_DOCUMENTS_FOLDER = 'uploads/documents';
And also invoked the lifecycleFileUpload() method in manageFileUpload() method
and now the files are moved to the directory.
Is it the right way to upload ?