-1

这可能是一个愚蠢的问题。但是对于许多框架来说,其中一件非常令人沮丧的事情是,当某些东西被期望如此简单和直接以至于甚至没有被提及时,然后当它需要几个小时才能弄清楚时,这是非常令人沮丧的。

我再次学习 Symfony,我有一个用于 Animal 实体的简单 API,并且我在数据库中创建了一些条目。

现在我不想使用迁移,因为我希望能够手动设计模式。我想要的只是让存储库返回所有对象。它做得很好,但不知何故它每次都返回一个空对象。我意识到这是因为这些属性是私有的。现在我创建了自己的方法,它基本上使用 getter 来提供对属性的访问,但这似乎违背了使用 ORM 的全部目的。

我花了两天时间试图找到文档,但找不到任何东西。这让我觉得很明显我必须使用 getter 来获取属性,但这是我希望开箱即用的东西。想

所以我的问题基本上是,这是怎么回事?还是我直接错过了什么?我只问了这个问题,因为我发现一个框架不能开箱即用地提供这个问题让我感到惊讶。

已安装的捆绑包:

<?php

return [
    Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
    Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
    Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
    Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
];

这是教义配置文件:

doctrine:
    dbal:
        url: '%env(resolve:DATABASE_URL)%'

        # IMPORTANT: You MUST configure your server version,
        # either here or in the DATABASE_URL env var (see .env file)
        #server_version: '13'
    orm:
        auto_generate_proxy_classes: true
        #-> Simply comment this out: Fixes the issue of column name underscores naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
        auto_mapping: true
        mappings:
            App:
                is_bundle: false
                dir: '%kernel.project_dir%/src/Entity'
                prefix: 'App\Entity'
                alias: App

when@test:
    doctrine:
        dbal:
            # "TEST_TOKEN" is typically set by ParaTest
            dbname_suffix: '_test%env(default::TEST_TOKEN)%'

when@prod:
    doctrine:
        orm:
            auto_generate_proxy_classes: false
            query_cache_driver:
                type: pool
                pool: doctrine.system_cache_pool
            result_cache_driver:
                type: pool
                pool: doctrine.result_cache_pool

    framework:
        cache:
            pools:
                doctrine.result_cache_pool:
                    adapter: cache.app
                doctrine.system_cache_pool:
                    adapter: cache.system

以下是简单 API 的代码:

//AnimalController.php
<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use App\Repository\AnimalRepository;

class AnimalController extends AbstractController
{

    private $repository;

    public function __construct(AnimalRepository $repository)
    {
       $this->repository = $repository;
    }

    #[Route('/api/animals', name: 'animals')]
    public function index(): Response
    {
        return $this->json(['animals' => $this->repository->getAnimals()]);
    }

    #[Route('/api/animals/{habitat}', name: 'animalsByHabitat')]
    public function getAnimalsByHabitat(string $habitat):Response
    {
        return $this->json([
            'byHabitat' => $habitat,
            'animals' => $this->repository->findByHabitat($habitat)
        ]);
    }
}


//Animal.php
<?php

namespace App\Entity;

use App\Repository\AnimalRepository;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: AnimalRepository::class)]
class Animal
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private $id;

    #[ORM\Column(type: 'string', length: 100, nullable: true)]
    private $commonName;

    #[ORM\Column(type: 'string', length: 100, nullable: true)]
    private $scientificName;

    #[ORM\Column(type: 'decimal', precision: 8, scale: 2, nullable: true)]
    private $weight;

    #[ORM\Column(type: 'integer', nullable: true)]
    private $lifeSpan;

    #[ORM\Column(type: 'string', length: 100)]
    private $integument;

    #[ORM\Column(type: 'boolean', nullable: true)]
    private $activeAllYear;

    #[ORM\Column(type: 'string', length: 100, nullable: true)]
    private $foodType;

    #[ORM\Column(type: 'boolean', nullable: true)]
    private $territorial;

    #[ORM\Column(type: 'string', length: 100, nullable: true)]
    private $habitat;

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

    public function getCommonName(): ?string
    {
        return $this->commonName;
    }

    public function setCommonName(?string $commonName): self
    {
        $this->commonName = $commonName;

        return $this;
    }

    public function getScientificName(): ?string
    {
        return $this->scientificName;
    }

    public function setScientificName(?string $scientificName): self
    {
        $this->scientificName = $scientificName;

        return $this;
    }

    public function getWeight(): ?string
    {
        return $this->weight;
    }

    public function setWeight(?string $weight): self
    {
        $this->weight = $weight;

        return $this;
    }

    public function getLifeSpan(): ?int
    {
        return $this->lifeSpan;
    }

    public function setLifeSpan(?int $lifeSpan): self
    {
        $this->lifeSpan = $lifeSpan;

        return $this;
    }

    public function getIntegument(): ?string
    {
        return $this->integument;
    }

    public function setIntegument(string $integument): self
    {
        $this->integument = $integument;

        return $this;
    }

    public function getActiveAllYear(): ?bool
    {
        return $this->activeAllYear;
    }

    public function setActiveAllYear(?bool $activeAllYear): self
    {
        $this->activeAllYear = $activeAllYear;

        return $this;
    }

    public function getFoodType(): ?string
    {
        return $this->foodType;
    }

    public function setFoodType(?string $foodType): self
    {
        $this->foodType = $foodType;

        return $this;
    }

    public function getTerritorial(): ?bool
    {
        return $this->territorial;
    }

    public function setTerritorial(?bool $territorial): self
    {
        $this->territorial = $territorial;

        return $this;
    }

    public function getHabitat(): ?string
    {
        return $this->habitat;
    }

    public function setHabitat(?string $habitat): self
    {
        $this->habitat = $habitat;

        return $this;
    }
}


//AnimalRepository.php
<?php

namespace App\Repository;

use App\Entity\Animal;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;

/**
 * @method Animal|null find($id, $lockMode = null, $lockVersion = null)
 * @method Animal|null findOneBy(array $criteria, array $orderBy = null)
 * @method Animal[]    findAll()
 * @method Animal[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
 */
class AnimalRepository extends ServiceEntityRepository
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, Animal::class);
    }

    /**
     * Seems like this might need to be done everytime?
     * With the normal Twig Controllers this was done automatically,
     * I don't think it's about serialiser, the Json method does it,
     * Its about getting these getters & setters to work, I don't want to do this everytime
     */
    public function getAnimals():array
    {
       
        $animalsObj = $this->findAll();
        $animals = [];

        foreach ($animalsObj as $animal) {
            $animals[] = $this->getArrayFromPrivateProps($animal);
        }

        return $animals;

   }


    
    /** 
     * @return Animal[] Returns an array of Animal objects
     * 
    */
    public function findByHabitat(string $habitat)
    {
        $animals = $this->createQueryBuilder('a')
            ->andWhere('a.habitat = :habitat')
            ->setParameter('habitat', $habitat)
            ->getQuery()
            ->getResult()
        ;

        return $animals;
    }

    private function getArrayFromPrivateProps(Animal $animal):array
    {
        return array(
            'id' => $animal->getId(),
            'commonName' => $animal->getCommonName(),
            'scientificName' => $animal->getScientificName(),
            'weight' => $animal->getWeight(),
            'lifeSpan' => $animal->getLifeSpan(),
            'habitat' => $animal->getHabitat(),
            'integument' => $animal->getIntegument(),
            'activeAllYear' => $animal->getActiveAllYear(),
            'foodType' => $animal->getFoodType(),
            'territorial' => $animal->getTerritorial()
        );
    }
   
}

我很难相信每次我想访问实体道具时都需要创建这个方法?ps 我已将访问修饰符更改为公共,然后它们可以正常工作。

我使用的是 Symfony 6,但 API 不是完整的应用程序。我需要引入任何特殊的捆绑包来实现这一点吗?

结果如下:

在此处输入图像描述

编辑1:

我已经从存储库中完成了 dd($this->findAll()) 并且工作正常。见截图:

dd($this->findAll():) 的截图

然后,当我执行 dd(json_encode($this->findAll())) 时,我得到相同的错误,即编码方法无法转换对象。Symfony 文档确实说 json_encode 可以用作 Serialise 组件的替代品?

dd(json_encode($this->findAll()))

4

1 回答 1

-1

如果其他人也面临同样的问题:将以下代码放入 framework.yaml 文件中工作:

# config/packages/framework.yaml
framework:
    # ...
    serializer:
        default_context:
            enable_max_depth: true

此处的文档:https ://symfony.com/doc/current/serializer.html

我只是偶然遇到它,但是,这应该可以开箱即用

于 2022-02-21T07:47:36.610 回答