Laravel 6.4: __toString () должна возвращать строковое значение - PullRequest
2 голосов
/ 08 ноября 2019

У меня есть этот простой класс:

<?php

namespace App\Domain\Model\User;

use Ramsey\Uuid\Uuid;

class UserId
{
    private $id;

    public function __construct($id = null)
    {
        $this->id = null === $id ? Uuid::uuid4()->toString() : $id;
    }

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

    public function equals(UserId $userId)
    {
        return $this->id() === $userId->id;
    }

    public function __toString()
    {
        return $this->id();
    }
}

И получаю эту ошибку:

Method App\Domain\Model\User\UserId::__toString() must return a string value

Я использую:

  • Laravel6.4.1

  • PHP 7.3.11

Когда dd($this->id()) внутри метода __toString() я получаю:

UserId {#420 ▼
  -id: "b7d24ad1-8dcc-4af1-b50e-c3d569f8badb"
}

У меня также есть реплика этого класса, работающая в другом php-проекте на той же машине, без всяких вещей Laravel, но я не могу понять, почему возвращается весь объект, а не только строка.

Это проект, на который я ссылаюсь, и где этот код работает нормально: https://github.com/dddinphp/last-wishes/blob/master/src/Lw/Domain/Model/User/UserId.php

Я проверяю все подобные проблемы в течение некоторого времени и не могу найти решение.

Обновление

Я также добавляю Post класс:

<?php


namespace App\Domain\Model\Post;


use App\Domain\Model\User\UserId;


class Post
{

    protected $postId;

    protected $userId;

    protected $name;

    protected $created_at;

    protected $updated_at;

    protected $user;

    public function __construct(PostId $postId, UserId $userId, $name)
    {
        $this->postId = $postId;
        $this->userId = $userId;
        $this->name = $name;
        $this->created_at = new \DateTime();
        $this->updated_at = new \DateTime();

        $this->user = null;
    }

    public function id()
    {
        return $this->postId;
    }

    public function name()
    {
        return $this->name;
    }
}

Обновление 2

User класс

<?php


namespace App\Domain\Model\User;


use Assert\Assertion;
use Doctrine\Common\Collections\ArrayCollection;
use http\Exception\InvalidArgumentException;
use App\Domain\Model\Post\Post;
use App\Domain\Model\Post\PostId;

class User
{
    const MAX_LENGTH_EMAIL = 255;
    const MIN_LENGTH_PASSWORD = 6;
    const MAX_LENGTH_PASSWORD = 25;

    protected $userId;

    protected $email;

    protected $password;

    protected $firstname;

    protected $lastname;

    protected $created_at;

    protected $updated_at;

    protected $posts;

    public function __construct(UserId $userId, $email, $password, $firstname, $lastname)
    {
        $this->userId = $userId;
        $this->setEmail($email);
        $this->password = $password;
        $this->firstname = $firstname;
        $this->lastname = $lastname;
        $this->created_at = new \DateTime();
        $this->updated_at = new \DateTime();

        $this->posts = new ArrayCollection;
    }

    protected function setEmail($email)
    {
        $email = trim($email);

        if (!$email) {
            throw new \InvalidArgumentException('email');
        }

        Assertion::email($email);
        $this->email = strtolower($email);
    }

    public function changePassword($password)
    {
        $password = trim($password);
        if (!$password) {
            throw new \InvalidArgumentException('password');
        }

        $this->password = $password;
    }

    public function id()
    {
        return $this->userId;
    }

    public function email()
    {
        return $this->email;
    }

    public function password()
    {
        return $this->password;
    }

    public function makePost($name)
    {
        $this->posts[] = new Post(
            new PostId(),
            $this->id(),
            $name
        );
    }
}

Ответы [ 3 ]

3 голосов
/ 08 ноября 2019

Поскольку классу UserId принадлежит свойство, почему бы не использовать само свойство $ id вместо вызова метода id()? И простой тип подсказывает это как (строка)

   /**
     * @return string
     */
    public function __toString()
    {
        return (string) $this->id;
    }

вот мой проверенный код

<?php
declare(strict_types=1);

namespace App;

use Faker\Provider\Uuid;

final class UserId
{
    private $id;

    public function __construct(?string $id = null)
    {
        $this->id = $id ?? Uuid::uuid();
    }

    /**
     * @return string
     */
    public function __toString(): string
    {
        return (string)$this->id;
    }
}

и мой тест

<?php
declare(strict_types=1);

namespace Tests\App\Unit;

use App\UserId;
use Tests\App\AbstractTestCase;

/**
 * @covers \App\UserId
 */
final class UserIdTest extends AbstractTestCase
{
    /**
     * @return void
     */
    public function testToString(): void
    {
        $userId = new UserId();
        self::assertIsString(\sprintf('%s', $userId));
        self::assertIsObject($userId);
    }
}

надеюсь, это поможет

1 голос
/ 08 ноября 2019

Попробуйте обернуть условие в троичный оператор и привести id к строке

<?php

namespace App\Domain\Model\User;

use Ramsey\Uuid\Uuid;

class UserId
{
    private $id;

    public function __construct($id = null)
    {

        $this->id = ($id === null) ? Uuid::uuid4()->toString() : $id;
    }

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

    public function equals(UserId $userId)
    {
        return $this->id() === $userId->id;
    }

    public function __toString()
    {
        return (string) $this->id();
    }
}

Надеюсь, это поможет

1 голос
/ 08 ноября 2019

Это не стандарт laravel, но вы возвращаете объект вместо строки. Вместо этого получите доступ к идентификатору объекта.

public function __toString()
{
    return $this->id()->id;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...