这可能是一个愚蠢的问题。但是对于许多框架来说,其中一件非常令人沮丧的事情是,当某些东西被期望如此简单和直接以至于甚至没有被提及时,然后当它需要几个小时才能弄清楚时,这是非常令人沮丧的。
我再次学习 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(json_encode($this->findAll())) 时,我得到相同的错误,即编码方法无法转换对象。Symfony 文档确实说 json_encode 可以用作 Serialise 组件的替代品?