Next gen ManyToOne error
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 3/5
- Tiempo estimado
- 1-2 días
- Aptitud para principiantes
- 45/100
- Tipo de issue
- Error
- Claridad
- Bastante claro
- Estado de actividad
- Estancado
- Stack tecnológico
- next.js, react, typescript
Línea de trabajo
Comienza con pwa/components/meet/list.tsx y el tipo Meet generado; después, reproduce la salida del generador de Next usando la relación ManyToOne de entreprise mostrada en el issue. Compara el valor de la relación con la forma en que se llama a ReferenceLinks para las notificaciones, los empleados y los clientes; se considera terminado cuando la lista de Meet generada se renderiza sin el error reportado.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
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**
- Lenguaje dominante
- TypeScript
- Estrellas
- 376
- Forks
- 132
- Métricas de merge de PR
- Sin PR fusionados en 30 d
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de api-platform/create-client
-
[potential Security Alert] New `test-vue-app` script added in `@api-platform/client-generator@0.8.0` Abierto
Dificultad 4/5 3-5 días Aptitud para principiantes 35/100
api-platform/create-client#396 ·
-
Dificultad 4/5 3-5 días Aptitud para principiantes 38/100
api-platform/create-client#397 ·
-
Dificultad 3/5 1-2 días Aptitud para principiantes 45/100
api-platform/create-client#395 ·
-
Dificultad 4/5 3-5 días Aptitud para principiantes 35/100
api-platform/create-client#394 ·
-
Dificultad 4/5 3-5 días Aptitud para principiantes 25/100
api-platform/create-client#393 · 1 comentario ·
Todos los issues de api-platform/create-client
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
mksglu/context-mode#1200 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
jaegertracing/jaeger-ui#4506 ·
-
area:desktop area:ui bug platform:macos
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
anthropics/claude-code#96687 ·
-
good first issue
Dificultad 1/5 Menos de una hora Aptitud para principiantes 95/100
AOSSIE-Org/DebateAI#582 · 2 comentarios ·