Next gen ManyToOne error
まだ誰も着手していません。
評価
- 難易度
- 3/5
- 見積もり時間
- 1〜2日
- 初心者へのやさしさ
- 45/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 停滞
- 技術スタック
- next.js, react, typescript
調査の方向性
pwa/components/meet/list.tsx と生成された Meet 型から始め、issue に示されている ManyToOne entreprise リレーションを使用して Next ジェネレーターの出力を再現します。リレーションの値を、通知、従業員、顧客に対して ReferenceLinks が呼び出される方法と比較します。生成された Meet リストが報告されたエラーなしでレンダリングされれば完了です。
索引モデルが issue の本文から書いたものです。
説明
API Platform version(s) affected: 3.2.11
Description
If an entity contains a manytoone relation, the pwa/component/nameOfEntity/list.tsx generate by Next gen contains error
I have two entity : Entreprise and Meet.
Class Entreprise
<?php
namespace App\Entity;
use ApiPlatform\Metadata\ApiResource;
use App\Repository\EntrepriseRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use ApiPlatform\Metadata\Delete;
use Symfony\Component\Serializer\Annotation\Groups;
#[ORM\Entity(repositoryClass: EntrepriseRepository::class)]
#[ApiResource(
normalizationContext: ['groups' => ['entreprise:read']],
denormalizationContext: ['groups' => ['entreprise:write']],
)]
class Entreprise
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
#[Groups(['entreprise:read'])]
private ?int $id = null;
#[ORM\Column(length: 255)]
#[Groups(['entreprise:read', 'entreprise:write', 'user:read'])]
private ?string $name = null;
#[ORM\Column(length: 255, nullable: true)]
#[Groups(['entreprise:read', 'entreprise:write', 'user:read'])]
private ?string $address_street = null;
#[ORM\Column(length: 255, nullable: true)]
#[Groups(['entreprise:read', 'entreprise:write', 'user:read'])]
private ?string $address_city = null;
#[ORM\Column(length: 255, nullable: true)]
#[Groups(['entreprise:read', 'entreprise:write', 'user:read'])]
private ?string $address_cp = null;
#[ORM\Column(options: ['default' => 0])]
#[Groups(['entreprise:read', 'entreprise:write', 'user:read'])]
private ?int $type = null;
#[ORM\OneToMany(mappedBy: 'entreprise_id', targetEntity: Meet::class, orphanRemoval: true)]
#[Groups(['entreprise:read', 'user:read'])]
private Collection $meets;
#[ORM\OneToMany(mappedBy: 'entreprise_id', targetEntity: Customer::class, orphanRemoval: true)]
#[Groups(['entreprise:read', 'user:read'])]
private Collection $customers;
#[ORM\OneToMany(mappedBy: 'entreprise_id', targetEntity: Employee::class, orphanRemoval: true)]
#[Groups(['entreprise:read', 'user:read'])]
private Collection $employees;
#[ORM\OneToMany(mappedBy: 'entreprise_id', targetEntity: User::class)]
#[Groups(['entreprise:read'])]
private Collection $users;
Class Meet
<?php
namespace App\Entity;
use ApiPlatform\Metadata\ApiResource;
use App\Repository\MeetRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use ApiPlatform\Metadata\Delete;
use Symfony\Component\Serializer\Annotation\Groups;
#[ORM\Entity(repositoryClass: MeetRepository::class)]
#[ApiResource(
normalizationContext: ['groups' => ['meet:read']],
denormalizationContext: ['groups' => ['meet:write']],
)]
class Meet
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
#[Groups(['meet:read', 'entreprise:read'])]
private ?int $id = null;
#[ORM\Column(type: Types::DATETIME_MUTABLE)]
#[Groups(['meet:read', 'meet:write', 'entreprise:read'])]
private ?\DateTimeInterface $date_start = null;
#[ORM\Column]
#[Groups(['meet:read', 'meet:write', 'entreprise:read'])]
private ?int $duration = null;
#[ORM\ManyToOne(inversedBy: 'meets')]
#[ORM\JoinColumn(nullable: false)]
#[Groups(['meet:read', 'meet:write'])]
private ?Entreprise $entreprise_id = null;
#[ORM\OneToMany(mappedBy: 'meet_id', targetEntity: Notification::class, orphanRemoval: true)]
#[Groups(['meet:read', 'meet:write', 'entreprise:read'])]
private Collection $notifications;
#[ORM\ManyToMany(targetEntity: Employee::class, mappedBy: 'meets')]
#[Groups(['meet:read', 'meet:write', 'entreprise:read'])]
private Collection $employees;
#[ORM\ManyToMany(targetEntity: Customer::class, inversedBy: 'meets')]
#[Groups(['meet:read', 'meet:write', 'entreprise:read'])]
private Collection $customers;
public function __construct()
{
$this->notifications = new ArrayCollection();
$this->employees = new ArrayCollection();
$this->customers = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getDateStart(): ?\DateTimeInterface
{
return $this->date_start;
}
public function setDateStart(\DateTimeInterface $date_start): static
{
$this->date_start = $date_start;
return $this;
}
public function getDuration(): ?int
{
return $this->duration;
}
public function setDuration(int $duration): static
{
$this->duration = $duration;
return $this;
}
public function getEntrepriseId(): ?Entreprise
{
return $this->entreprise_id;
}
public function setEntrepriseId(?Entreprise $entreprise_id): static
{
$this->entreprise_id = $entreprise_id;
return $this;
}
/**
* @return Collection<int, Notification>
*/
public function getNotifications(): Collection
{
return $this->notifications;
}
public function addNotification(Notification $notification): static
{
if (!$this->notifications->contains($notification)) {
$this->notifications->add($notification);
$notification->setMeetId($this);
}
return $this;
}
public function removeNotification(Notification $notification): static
{
if ($this->notifications->removeElement($notification)) {
// set the owning side to null (unless already changed)
if ($notification->getMeetId() === $this) {
$notification->setMeetId(null);
}
}
return $this;
}
/**
* @return Collection<int, Employee>
*/
public function getEmployees(): Collection
{
return $this->employees;
}
public function addEmployee(Employee $employee): static
{
if (!$this->employees->contains($employee)) {
$this->employees->add($employee);
$employee->addMeet($this);
}
return $this;
}
public function removeEmployee(Employee $employee): static
{
if ($this->employees->removeElement($employee)) {
$employee->removeMeet($this);
}
return $this;
}
/**
* @return Collection<int, Customer>
*/
public function getCustomers(): Collection
{
return $this->customers;
}
public function addCustomer(Customer $customer): static
{
if (!$this->customers->contains($customer)) {
$this->customers->add($customer);
}
return $this;
}
public function removeCustomer(Customer $customer): static
{
$this->customers->removeElement($customer);
return $this;
}
}
pwa/components/meet/list.tsx
import { FunctionComponent } from "react";
import Link from "next/link";
import ReferenceLinks from "../common/ReferenceLinks";
import { getItemPath } from "../../utils/dataAccess";
import { Meet } from "../../types/Meet";
interface Props {
meets: Meet[];
}
export const List: FunctionComponent<Props> = ({ meets }) => (
<div className="p-4">
<div className="flex justify-between items-center">
<h1 className="text-3xl mb-2">Meet List</h1>
<Link
href="/meets/create"
className="bg-cyan-500 hover:bg-cyan-700 text-white text-sm font-bold py-2 px-4 rounded"
>
Create
</Link>
</div>
<table
cellPadding={10}
className="shadow-md table border-collapse min-w-full leading-normal table-auto text-left my-3"
>
<thead className="w-full text-xs uppercase font-light text-gray-700 bg-gray-200 py-2 px-4">
<tr>
<th>id</th>
<th>date_start</th>
<th>duration</th>
<th>entreprise_id</th>
<th>notifications</th>
<th>employees</th>
<th>customers</th>
<th colSpan={2} />
</tr>
</thead>
<tbody className="text-sm divide-y divide-gray-200">
{meets &&
meets.length !== 0 &&
meets.map(
(meet) =>
meet["@id"] && (
<tr className="py-2" key={meet["@id"]}>
<th scope="row">
<ReferenceLinks
items={{
href: getItemPath(meet["@id"], "/meets/[id]"),
name: meet["@id"],
}}
/>
</th>
<td>{meet["date_start"]?.toLocaleString()}</td>
<td>{meet["duration"]}</td>
<td>
{console.log()}
<ReferenceLinks
items={meet["entreprise_id"].map((ref: any) => ({
href: getItemPath(ref, "/entreprises/[id]"),
name: ref,
}))}/>
</td>
<td>
<ReferenceLinks
items={meet["notifications"].map((emb: any) => ({
href: getItemPath(emb["@id"], "/notifications/[id]"),
name: emb["@id"],
}))}
/>
</td>
<td>
<ReferenceLinks
items={meet["employees"].map((ref: any) => ({
href: getItemPath(ref, "/employees/[id]"),
name: ref,
}))}
/>
</td>
<td>
<ReferenceLinks
items={meet["customers"].map((ref: any) => ({
href: getItemPath(ref, "/customers/[id]"),
name: ref,
}))}
/>
</td>
<td className="w-8">
<Link
href={getItemPath(meet["@id"], "/meets/[id]")}
className="text-cyan-500"
>
Show
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
className="w-6 h-6"
>
<path d="M12 15a3 3 0 100-6 3 3 0 000 6z" />
<path
fillRule="evenodd"
d="M1.323 11.447C2.811 6.976 7.028 3.75 12.001 3.75c4.97 0 9.185 3.223 10.675 7.69.12.362.12.752 0 1.113-1.487 4.471-5.705 7.697-10.677 7.697-4.97 0-9.186-3.223-10.675-7.69a1.762 1.762 0 010-1.113zM17.25 12a5.25 5.25 0 11-10.5 0 5.25 5.25 0 0110.5 0z"
clipRule="evenodd"
/>
</svg>
</Link>
</td>
<td className="w-8">
<Link
href={getItemPath(meet["@id"], "/meets/[id]/edit")}
className="text-cyan-500"
>
Edit
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
className="w-6 h-6"
>
<path d="M21.731 2.269a2.625 2.625 0 00-3.712 0l-1.157 1.157 3.712 3.712 1.157-1.157a2.625 2.625 0 000-3.712zM19.513 8.199l-3.712-3.712-8.4 8.4a5.25 5.25 0 00-1.32 2.214l-.8 2.685a.75.75 0 00.933.933l2.685-.8a5.25 5.25 0 002.214-1.32l8.4-8.4z" />
<path d="M5.25 5.25a3 3 0 00-3 3v10.5a3 3 0 003 3h10.5a3 3 0 003-3V13.5a.75.75 0 00-1.5 0v5.25a1.5 1.5 0 01-1.5 1.5H5.25a1.5 1.5 0 01-1.5-1.5V8.25a1.5 1.5 0 011.5-1.5h5.25a.75.75 0 000-1.5H5.25z" />
</svg>
</Link>
</td>
</tr>
)
)}
</tbody>
</table>
</div>
);
Possible Solution
Error TypeError: meet.entreprise_id.map is not a function come from this code
<ReferenceLinks
items={meet["entreprise_id"].map((ref: any) => ({
href: getItemPath(ref, "/entreprises/[id]"),
name: ref,
}))}/>
meet["entreprise_id"] is not an array so it's impossible to map it
It's possible to solve with
items={[meet["entreprise_id"]].map((ref: any) => ({
href: getItemPath(ref, "/entreprises/[id]"),
name: ref,
}))}/>```
**Additional Context**
- 主要言語
- TypeScript
- スター
- 376
- フォーク
- 132
- PR マージ指標
- 30日以内にマージされた PR はありません
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
api-platform/create-client のほかの issue
-
[potential Security Alert] New `test-vue-app` script added in `@api-platform/client-generator@0.8.0` オープン
難易度 4/5 3〜5日 初心者へのやさしさ 35/100
api-platform/create-client#396 ·
-
難易度 4/5 3〜5日 初心者へのやさしさ 38/100
api-platform/create-client#397 ·
-
難易度 3/5 1〜2日 初心者へのやさしさ 45/100
api-platform/create-client#395 ·
-
難易度 4/5 3〜5日 初心者へのやさしさ 35/100
api-platform/create-client#394 ·
-
難易度 4/5 3〜5日 初心者へのやさしさ 25/100
api-platform/create-client#393 · コメント 1 件 ·
api-platform/create-client の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
mksglu/context-mode#1200 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
jaegertracing/jaeger-ui#4506 ·
-
area:desktop area:ui bug platform:macos
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
anthropics/claude-code#96687 ·
-
good first issue
難易度 1/5 1時間未満 初心者へのやさしさ 95/100
AOSSIE-Org/DebateAI#582 · コメント 2 件 ·