<?php

declare(strict_types=1);

namespace Doctrine\Tests\ORM\Functional\Ticket;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\JoinColumn;
use Doctrine\ORM\Mapping\ManyToOne;
use Doctrine\ORM\Mapping\OneToMany;
use Doctrine\ORM\Mapping\OrderBy;
use Doctrine\ORM\Mapping\Table;
use Doctrine\Tests\OrmFunctionalTestCase;
use PHPUnit\Framework\Attributes\Group;

#[Group('DDC-1080')]
class DDC1080Test extends OrmFunctionalTestCase
{
    public function testHydration(): void
    {
        $this->createSchemaForModels(
            DDC1080Foo::class,
            DDC1080Bar::class,
            DDC1080FooBar::class,
        );

        $foo1 = new DDC1080Foo();
        $foo1->setFooTitle('foo title 1');
        $foo2 = new DDC1080Foo();
        $foo2->setFooTitle('foo title 2');

        $bar1 = new DDC1080Bar();
        $bar1->setBarTitle('bar title 1');
        $bar2 = new DDC1080Bar();
        $bar2->setBarTitle('bar title 2');
        $bar3 = new DDC1080Bar();
        $bar3->setBarTitle('bar title 3');

        $foobar1 = new DDC1080FooBar();
        $foobar1->setFoo($foo1);
        $foobar1->setBar($bar1);
        $foobar1->setOrderNr(0);

        $foobar2 = new DDC1080FooBar();
        $foobar2->setFoo($foo1);
        $foobar2->setBar($bar2);
        $foobar2->setOrderNr(0);

        $foobar3 = new DDC1080FooBar();
        $foobar3->setFoo($foo1);
        $foobar3->setBar($bar3);
        $foobar3->setOrderNr(0);

        $this->_em->persist($foo1);
        $this->_em->persist($foo2);
        $this->_em->persist($bar1);
        $this->_em->persist($bar2);
        $this->_em->persist($bar3);
        $this->_em->flush();

        $this->_em->persist($foobar1);
        $this->_em->persist($foobar2);
        $this->_em->persist($foobar3);
        $this->_em->flush();
        $this->_em->clear();

        $foo     = $this->_em->find(DDC1080Foo::class, $foo1->getFooID());
        $fooBars = $foo->getFooBars();

        self::assertCount(3, $fooBars, 'Should return three foobars.');
    }
}


#[Table(name: 'foo')]
#[Entity]
class DDC1080Foo
{
    /** @var int */
    #[Id]
    #[Column(name: 'fooID', type: 'integer')]
    #[GeneratedValue(strategy: 'AUTO')]
    protected $fooID;

    /** @var string */
    #[Column(name: 'fooTitle', type: 'string', length: 255)]
    protected $fooTitle;

    /** @phpstan-var Collection<DDC1080FooBar> */
    #[OneToMany(targetEntity: 'DDC1080FooBar', mappedBy: 'foo', cascade: ['persist'])]
    #[OrderBy(['orderNr' => 'ASC'])]
    protected $fooBars;

    public function __construct()
    {
        $this->fooBars = new ArrayCollection();
    }

    public function getFooID(): int
    {
        return $this->fooID;
    }

    public function getFooTitle(): string
    {
        return $this->fooTitle;
    }

    /** @phpstan-return Collection<DDC1080FooBar> */
    public function getFooBars(): Collection
    {
        return $this->fooBars;
    }

    public function setFooID(int $fooID): void
    {
        $this->fooID = $fooID;
    }

    public function setFooTitle(string $fooTitle): void
    {
        $this->fooTitle = $fooTitle;
    }

    public function setFooBars(array $fooBars): void
    {
        $this->fooBars = $fooBars;
    }
}
#[Table(name: 'bar')]
#[Entity]
class DDC1080Bar
{
    /** @var int */
    #[Id]
    #[Column(name: 'barID', type: 'integer')]
    #[GeneratedValue(strategy: 'AUTO')]
    protected $barID;

    /** @var string */
    #[Column(name: 'barTitle', type: 'string', length: 255)]
    protected $barTitle;

    /** @phpstan-var Collection<DDC1080FooBar> */
    #[OneToMany(targetEntity: 'DDC1080FooBar', mappedBy: 'bar', cascade: ['persist'])]
    #[OrderBy(['orderNr' => 'ASC'])]
    protected $fooBars;

    public function __construct()
    {
        $this->fooBars = new ArrayCollection();
    }

    public function getBarID(): int
    {
        return $this->barID;
    }

    public function getBarTitle(): string
    {
        return $this->barTitle;
    }

    /** @phpstan-return Collection<DDC1080FooBar> */
    public function getFooBars(): Collection
    {
        return $this->fooBars;
    }

    public function setBarID(int $barID): void
    {
        $this->barID = $barID;
    }

    public function setBarTitle(string $barTitle): void
    {
        $this->barTitle = $barTitle;
    }

    public function setFooBars(array $fooBars): void
    {
        $this->fooBars = $fooBars;
    }
}

#[Table(name: 'fooBar')]
#[Entity]
class DDC1080FooBar
{
    /** @var DDC1080Foo */
    #[ManyToOne(targetEntity: 'DDC1080Foo')]
    #[JoinColumn(name: 'fooID', referencedColumnName: 'fooID')]
    #[Id]
    protected $foo = null;

    /** @var DDC1080Bar */
    #[ManyToOne(targetEntity: 'DDC1080Bar')]
    #[JoinColumn(name: 'barID', referencedColumnName: 'barID')]
    #[Id]
    protected $bar = null;

    /** @var int orderNr */
    #[Column(name: 'orderNr', type: 'integer', nullable: false)]
    protected $orderNr = null;

    public function getFoo(): DDC1080Foo
    {
        return $this->foo;
    }

    public function setFoo(DDC1080Foo $foo): DDC1080FooBar
    {
        $this->foo = $foo;

        return $this;
    }

    public function getBar(): DDC1080Bar
    {
        return $this->bar;
    }

    public function setBar(DDC1080Bar $bar): DDC1080FooBar
    {
        $this->bar = $bar;

        return $this;
    }

    public function getOrderNr(): int|null
    {
        return $this->orderNr;
    }

    public function setOrderNr(int|null $orderNr): DDC1080FooBar
    {
        $this->orderNr = $orderNr;

        return $this;
    }
}
