Symfony 4, аргумент 1, переданный в .., должен быть экземпляром DateTime, значение null задано

Мой вопрос очень связан с этот вопрос, но не совсем то же самое. Это дополнительный вопрос к мой предыдущий, если вы его читали, но он не так сильно от него зависит, поэтому чтения только этого вопроса должно быть достаточно. У меня есть этот метод, чтобы сохранить «прикосновение» к «кабине» (я знаю, что это странно). Я (пытаюсь) извлекать информацию из запроса POST и тестировать ее с помощью POSTMAN.


/**
 * @param Request $request
 * @throws \Doctrine\ORM\ORMException
 * @throws \Doctrine\ORM\OptimisticLockException
 * @throws \ErrorException
 * @return JsonResponse
 */
public function registerTouch(Request $request)
{
    $touchService = new TouchService($this->entityManager);

    $cabinet = $request->get('cabinet_id');

    /**
     * @var $touch Touch
     */
    $touch = new Touch(
        $request->get('time'),
        $request->get('toucher'),
        $request->get('cabinet_id'),
        $request->get('id')
    );

    if (empty($cabinet)) {
        return new JsonResponse(['error' => 'Touch not saved'], 200);
    } else {
        $touch->setCabinet($cabinet);
        $touchService->registerTouch($touch);
        return new JsonResponse(['success' => 'Touch saved'], 200);
    }

а класс Touch состоит из следующего:

<?php

namespace App\Entity;

use DateTime;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass = "App\Repository\TouchRepository")
 */
class Touch implements \JsonSerializable
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type = "integer")
     */
    private $id;

    /**
     * @ORM\Column(type = "datetime")
     */
    private $time;

    /**
     * @ORM\Column(type = "string", length=255)
     */
    private $toucher;

    private $accountId;

    /**
     * @ORM\ManyToOne(targetEntity = "Cabinet")
     */
    private $cabinet;

    /**
     * Touch constructor.
     * @param DateTime $time
     * @param string $toucher
     * @param Cabinet $cabinet
     * @param int $id
     */
    public function __construct(DateTime $time, string $toucher, Cabinet $cabinet = null, int $id = null)
    {
        $this->time = $time;
        $this->toucher = $toucher;
        $this->cabinet = $cabinet;
        $this->id = $id;
    }

    public function getId(): int
    {
        return $this->id;
    }

    public function setId(int $id): self
    {
        $this->id = $id;

        return $this;
    }

    public function getTime(): DateTime
    {
        return $this->time;
    }

    public function getToucher(): string
    {
        return $this->toucher;
    }

    public function getCabinet(): Cabinet
    {
        return $this->cabinet;
    }

    public function setCabinet(Cabinet $cabinet): self
    {
        $this->cabinet = $cabinet;
        $this->accountId = $cabinet->getId();
        return $this;
    }

    public function getAccountId(): int
    {
        return $this->accountId;
    }

    public function setAccountId(int $accountId): self
    {
        $this->accountId = $accountId;

        return $this;
    }

    public function jsonSerialize()
    {
        return get_object_vars($this);
    }
}

Но при запуске этого кода я получаю эту ошибку:

Argument 1 passed to App\Entity\Touch::__construct() must be an instance of DateTime, null given, called in /var/www/learningProject/src/Controller/APITouchController.php on line 89 (500 Internal Server Error)

Я передаю данные с помощью POSTMAN:

[
    {
        "id": 666,
        "cabinet_id": 55,
        "time": {
            "date": "2018-06-18 11:51:22.000000",
            "timezone_type": 3,
            "timezone": "UTC"
        },
        "toucher": "person1",
    }
]

Какой правильный макет для объекта DateTime, поэтому я не уверен, почему возникает эта ошибка и как ее решить. Любая помощь будет оценена по достоинству!

Наличие правильного формата не делает его объектом DateTime, в какой-то момент вам придется преобразовать его. См. этот вопрос.

ehymel 18.07.2019 17:06

@ehymel Не приведет ли это к потере формата и, возможно, данных, таких как часовой пояс? Как это будет работать? Потому что мне нужно сохранить «прикосновение» в базе данных.

user8678484 18.07.2019 17:08

@ehymel Я также пробовал вышеописанное time с этим "time": "2018-06-18 11:51:22", и все равно получаю ту же ошибку.

user8678484 18.07.2019 17:12

Для вашей Touch::__construct() функции требуется объект php DateTime. но когда вы вызываете $touch = new Touch(...), вы фактически передаете строку, независимо от того, имеет ли строка какой-то определенный формат. Прежде чем звонить new Touch(...), вы должны соответствовать требованиям типа вашего собственного кода. Смотрите мой первый комментарий.

ehymel 18.07.2019 17:23

Попробуйте dump($request) и расскажите нам, что у вас есть.

ste 18.07.2019 17:23
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Symfony Station Communiqué - 17 февраля 2023 г
Symfony Station Communiqué - 17 февраля 2023 г
Это коммюнике первоначально появилось на Symfony Station , вашем источнике передовых новостей Symfony, PHP и кибербезопасности.
Управление ответами api для исключений на Symfony с помощью KernelEvents
Управление ответами api для исключений на Symfony с помощью KernelEvents
Много раз при создании api нам нужно возвращать клиентам разные ответы в зависимости от возникшего исключения.
1
5
10 195
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема в том, что вы передаете строку конструктору Touch, но вы указываете тип с помощью DateTime $time, поэтому он ожидает объект DateTime.

Чтобы решить вашу проблему, преобразуйте строку в DateTime, прежде чем передавать ее в конструктор.

/** @var $cabinet Cabinet|null */
$cabinet = $this->entityManager->getRepository(Cabinet::class)->findOneBy([
    'id' => $request->get('cabinet_id')
]);

if (null === $cabinet) {
    return new JsonResponse(['error' => 'Touch not saved'], 200);
}

/** @var $touch Touch */
$touch = new Touch(
    new \DateTime($request->get('time')),
    $request->get('toucher'),
    $cabinet,
    (int)$request->get('id')
);
$touchService->registerTouch($touch);

return new JsonResponse(['success' => 'Touch saved'], 200);

Наконечник: рассмотрите возможность использования DateTimeImmutable вместо DateTime.

Спасибо за ваш ответ! Два небольших вопроса, если вы не возражаете, 1) почему DateTimeImmutable вместо этого? 2) Это действительно решило проблему, но она все еще появляется для остальных элементов Argument 2 passed to App\Entity\Touch::__construct() must be of the type integer, null given, called in /var/www/learningProject/src/Controller/APITouchController.p‌​hp on line 89 (500 Internal Server Error) Должен ли я также преобразовать это в целое число и аналогичные вещи для остальных? и как это будет работать? Потому что new \int это не вещь iirc

user8678484 18.07.2019 17:29

Обновил ответ. О рекомендации DateTime vs DateTimeImmutable. В Интернете есть много статей на эту тему (например, Вот этот). Просто погуглите :)

Nicolai Fröhlich 18.07.2019 17:33

Еще раз спасибо! И последняя проблема, я получаю это, когда печатаю намек на кабинет: Method call uses 1 parameters, but method signature uses 0 parameters less.... Мой класс кабинета в этом вопросе: stackoverflow.com/questions/56612348/… Любые идеи, что можно было бы сделать по этому поводу?

user8678484 18.07.2019 17:38

О, я вижу. тогда вам нужно будет получить объект вашего кабинета из базы данных по заданному идентификатору. Что-то вроде $this->entityManager->getRepository(Cabinet::class)->findOne‌​By(['id' -> $request->get('cabinet_id')]). Обновил ответ.

Nicolai Fröhlich 18.07.2019 17:41

Несколько дней спустя, но вы случайно не знаете, почему JsonResponse не возвращается, несмотря ни на что? Все работает и тач регистрируется и все нормально, но POSTMAN дает в ответ это: { "headers": {} }. Я также пытался вернуть ответ и другие типы, но ничего не возвращается, что бы я ни пытался.

user8678484 23.07.2019 13:56

Пожалуйста, откройте новый вопрос и добавьте соответствующие части кода и информацию (действие контроллера, полезная нагрузка и т. д.).

Nicolai Fröhlich 23.07.2019 14:45

Другие вопросы по теме