【问题标题】:Symfony 4, Argument 1 passed to .. must be an instance of DateTime, null givenSymfony 4,传递给 .. 的参数 1 必须是 DateTime 的实例,给定 null
【发布时间】:2019-07-18 14:30:56
【问题描述】:

我的问题与this question 非常相关,但并不完全相同。这是my previous one 上的后续问题,如果您已经阅读过它,但它并不那么依赖它,所以只阅读这个问题就足够了。我有这种方法可以在“小屋”上保存“触摸”(我知道这很奇怪)。我(尝试)这样做是从 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);
    }
}

但是在运行此代码时出现此错误:

传递给 App\Entity\Touch::__construct() 的参数 1 必须是 DateTime 的实例,给定 null,在第 89 行的 /var/www/learningProject/src/Controller/APITouchController.php 中调用(500 内部服务器错误)

我正在使用 POSTMAN 传递数据:

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

哪个是 DateTime 对象的正确布局,所以我不确定为什么会发生这个错误,也不知道如何解决它。任何帮助将不胜感激!

【问题讨论】:

  • 拥有正确的格式并不能使其成为DateTime 对象,您必须在某个时候对其进行转换。见this question
  • @ehymel 这不会导致我丢失格式和可能的时区等数据吗?这将如何工作?因为我需要将“触摸”存储在数据库中。
  • @ehymel 我也用这个"time": "2018-06-18 11:51:22", 尝试了上面的time,但我仍然得到同样的错误。
  • 您的 Touch::__construct() 函数需要一个 php DateTime 对象。但是当您调用$touch = new Touch(...) 时,您实际上是在传递一个字符串,无论该字符串是否采用某种特定格式。在调用new Touch(...)之前,您必须满足您自己代码的类型要求。请参阅我的第一条评论。
  • 试试dump($request),告诉我们你有什么。

标签: symfony datetime symfony4


【解决方案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.php on line 89 (500 Internal Server Error) 我是否也应该将其转换为整数然后其他类似的东西?那将如何工作?因为new \int 不是 iirc 的东西
  • 更新了答案。关于DateTimeDateTimeImmutable 的推荐。互联网上有很多关于这个主题的文章(即this one)。只是谷歌它:)
  • 再次感谢!最后一期,我在提示内阁时收到了这个:Method call uses 1 parameters, but method signature uses 0 parameters less...。我的内阁课在这个问题中:stackoverflow.com/questions/56612348/… 有什么想法可以解决这个问题吗?
  • 哦,我明白了。然后,您必须通过给定的 id 从数据库中获取您的橱柜实体。像$this-&gt;entityManager-&gt;getRepository(Cabinet::class)-&gt;findOneBy(['id' -&gt; $request-&gt;get('cabinet_id')]) 这样的东西。更新了答案。
  • 几天后,但是您是否有任何想法为什么无论如何都不会返回 JsonResponse ?一切正常,触摸被注册,一切都很好,但邮递员给出了回应:{ "headers": {} }。我也尝试过返回 Response 和其他类型,但无论我尝试什么都没有返回。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-10
  • 1970-01-01
  • 2018-12-15
相关资源
最近更新 更多