OneToMany or OneToOne, am I on the right or wrong path?

I have this DB model:  single database

Then I created these objects (I'll just leave the relationship part as the other is not relevant):

Orders.php

class Orders {
    /**
     * @ORM\ManyToOne(targetEntity="Person", inversedBy="orders")
     * @ORM\JoinColumn(name="person_id", referencedColumnName="id")
     * */
    protected $person;

    public function setPerson(Person $person)
    {
        $this->person = $person;
        return $this;
    }

    public function getPerson()
    {
        return $this->person;
    }

}

      

Person.php

class Person {
    /**
     * @ORM\OneToMany(targetEntity="NaturalPerson", mappedBy="person")
     * */
    private $naturals;

    /**
     * @ORM\OneToMany(targetEntity="LegalPerson", mappedBy="person")
     * */
    private $legals;

    /**
     * @ORM\OneToMany(targetEntity="Orders", mappedBy="person")
     * */
    private $orders;

    public function __construct()
    {
        $this->naturals = new ArrayCollection();
        $this->legals = new ArrayCollection();
        $this->orders = new ArrayCollection();
    }

    public function getNaturals()
    {
        return $this->naturals;
    }

    public function getLegals()
    {
        return $this->legals;
    }

    public function getOrders()
    {
        return $this->orders;
    }

}

      

NaturalPerson.php

class NaturalPerson {

    /**
     * @ORM\Id
     * @ORM\ManyToOne(targetEntity="Person", inversedBy="naturals")
     * @ORM\JoinColumn(name="person_id", referencedColumnName="id")
     */
    protected $person;

    /**
     * @ORM\Column(name="identification_type", type="ci_type", nullable=false)
     * @DoctrineAssert\Enum(entity="Tanane\FrontendBundle\DBAL\Types\CIType")
     */
    protected $identification_type;

    /**
     * @ORM\Column(name="ci", type="integer", nullable=false)
     */
    protected $ci;

    public function setPerson(Person $person)
    {
        $this->person = $person;
        return $this;
    }

    public function getPerson()
    {
        return $this->person;
    }

    public function setIdentificationType($identification_type)
    {
        $this->identification_type = $identification_type;
        return $this;
    }

    public function getIdentificationType()
    {
        return $this->identification_type;
    }

    public function setCI($ci)
    {
        $this->ci = $ci;
        return $this;
    }

    public function getCI()
    {
        return $this->ci;
    }

}

      

I missed LegalPerson

since it is almost the same as NaturalPerson

here is the problem. The display looks good, but how do I get related posts from Orders

?

The idea behind this is for everyone Orders

I need to know to which Person

(Orders) belongs , as well as additional information stored in NaturalPerson

or LegalPerson

depending on person.type

.

See this code:

public function getOrdersAction()
{
    $response = array();
    $em = $this->getDoctrine()->getManager();

    $entities = $em->getRepository("FrontendBundle:Orders")->findAll();

    if (!$entities)
    {
        $response['message'] = "No se encontraron resultados";
    }

    $orders = array();
    foreach ($entities as $entity)
    {

        $personType = $entity->getPerson()->getPersonType();

        $order = array();
        $order[] = $entity->getNickname();

        // Here I'm trying to access to `Naturals` methods from `Orders` 
        if ($personType == 1)
        {
            $order[] = $entity->getPerson()->getNaturals()[0]->getIdentificationType() . $entity->getPerson()->getNaturals()[0]->getCI();
        }
        elseif ($personType == 2)
        {
            $order[] = $entity->getPerson()->getLegals()[0]->getIdentificationType() . $entity->getPerson()->getLegals()[0]->getRIF();
        }

        $orders[] = $order;
    }

    $response['data'] = $orders;
    return new JsonResponse($response);
}

      

But I am getting this error:

Error: Calling member function getIdentificationType () on a non-object in /var/www/html/tanane/src/Tanane/BackendBundle/Controller/OrderController.php line 115

Maybe my mapping is wrong, since I must have OneToOne

between Person

and NaturalPerson

(and it doesn't sound right to my logic, as DER shows) or maybe not, but then I don't know how to get bound properties for just one entry, I read the docs here and also in here , but they didn't talk about this part, or I don't see it, any advice? ideas? tips?

Trying to use repositories and DQL to solve the problem

I am creating a function in a class Repository

to retrieve the data and it doesn't get complicated as apparently my problem, so I did this:

public function getOrders($person_type = 1)
{
    $qb = $this->getEntityManager()->createQueryBuilder();

    $qb
            ->select('ord.*, ps.*')
            ->from("FrontendBundle:Orders", "ord")
            ->join('FrontendBUndle:Person', 'ps', 'WITH', 'ps.id = ord.person_id')
            ->orderBy('ord.created', 'DESC');

    if ($person_type == 1)
    {
        $qb
                ->select('np.*')
                ->join('FrontendBundle:NaturalPerson', 'np', 'WITH', 'ps.id = np.person'); // Join NaturalPerson table
    }
    elseif ($person_type == 2)
    {
        $qb
                ->select('lp.*')
                ->join('FrontendBundle:LegalPerson', 'lp', 'WITH', 'ps.id = lp.person'); // Join NaturalPerson table
    }

    return $qb->getQuery()->getResult();
}

      

I haven't tested it yet, so maybe it won't work, but if the idea is to get more information for both tables, then with this DQL I did how to pass $person_type

which is inside the Person

Table? This gets a little tricky, at least for me.

Running a raw query to see if columns are NULL

I am creating this simple query just to check if the results are NULL

:

SELECT
    ord.id,
    ord.person_id as ord_person_id,
  ord.nickname,
  ps.id,
  ps.description,
  np.person_id as natural_person_id,
  np.identification_type,
    np.ci
FROM
    orders ord
LEFT JOIN person ps ON ord.person_id = ps.id
LEFT JOIN natural_person np ON np.person_id = ps.id
WHERE
    ps.person_type = 1;

      

And this query returns:

enter image description here

So there are no NULL columns here.

CRUD for creating new orders

// Set Person entity
$entityPerson = new Person();
$person_type === 1 ? $entityPerson->setDescription($orders['nat']['person']['description']) : $entityPerson->setDescription($orders['leg']['person']['description']);
$person_type === 1 ? $entityPerson->setContactPerson($orders['nat']['person']['contact_person']) : $entityPerson->setContactPerson($orders['leg']['person']['contact_person']);
$entityPerson->setPersonType($person_type);

$em->persist($entityPerson);
$em->flush();

...

if ($person_type === 1)
{
    // Set NaturalPerson entity
    $entityNatural = new NaturalPerson();
    $entityNatural->setIdentificationType($orders['nat']['identification_type']);
    $entityNatural->setCI($orders['nat']['ci']);

    $em->persist($entityNatural);
    $em->flush();
}
elseif ($person_type === 2)
{
    // Set LegalPerson entity
    $entityLegal = new LegalPerson();
    $entityLegal->setIdentificationType($orders['leg']['identification_type']);
    $entityLegal->setRIF($orders['leg']['rif']);

    $em->persist($entityLegal);
    $em->flush();
}

      

+3


source to share


2 answers


Since LegalPerson

and NaturalPerson

are specializations Person

, I would recommend using something that causes Doctrine Class Inheritance table ( documentation ).

You will have:

Person.php

/**
 * @ORM\Table(name="person")
 * @ORM\Entity
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="discr", type="string")
 * @ORM\DiscriminatorMap({
 *     "natural" = "NaturalPerson",
 *     "legal" = "LegalPerson",
 * })
 */
class Person {
    /**
     * @ORM\OneToMany(targetEntity="Orders", mappedBy="person")
     * */
    private $orders;

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

    public function getOrders()
    {
        return $this->orders;
    }

}

      

NaturalPerson.php

/**
 * @ORM\Table(name="natural_person")
 * @ORM\Entity
 */
class NaturalPerson extends Person {
    /**
     * @ORM\Column(name="identification_type", type="ci_type", nullable=false)
     * @DoctrineAssert\Enum(entity="Tanane\FrontendBundle\DBAL\Types\CIType")
     */
    protected $identification_type;

    /**
     * @ORM\Column(name="ci", type="integer", nullable=false)
     */
    protected $ci;

    public function setIdentificationType($identification_type)
    {
        $this->identification_type = $identification_type;
        return $this;
    }

    public function getIdentificationType()
    {
        return $this->identification_type;
    }

    public function setCI($ci)
    {
        $this->ci = $ci;
        return $this;
    }

    public function getCI()
    {
        return $this->ci;
    }
}

      

Order.php

remains unchanged.

As you can see now NaturalPerson

and LegalPerson

expand Person

. Since you changed the definition of entities, you will have to update the database schema.



Now, in yours, Controller

you only need to do this:

foreach ($entities as $entity)
{
    $person = $entity->getPerson();

    $order = array();
    $order[] = $entity->getNickname();

    if ($person instanceof NaturalPerson)
    {
        $order[] = $person->getIdentificationType() . $person->getCI();
    }
    else // it has to be LegalPerson
    {
        $order[] = $person->getIdentificationType() . $person->getRIF();
    }

    $orders[] = $order;
}

      

Don't forget to add an operator use

for NaturalPerson

!

This way, you only work with instances of NaturalPerson

or LegalPerson

. I'm sure you can improve this.

Finally, you will have to change your CRUD for this. You are not working with anymore Person

(actually it should be abstract

), so now you need to handle CRUD for NaturalPerson

and for LegalPerson

separately. Each of them will have Type

, Controller

, presentation, etc.

Your code will now look like this:

if ($person_type === 1)
{
    $entityPerson = new NaturalPerson();
    $entityPerson->setDescription($orders['nat']['person']['description']);
    $entityPerson->setContactPerson($orders['nat']['person']['contact_person']);
    $entityPerson->setIdentificationType($orders['nat']['identification_type']);
    $entityPerson->setCI($orders['nat']['ci']);

    $em->persist($entityPerson);
    $em->flush();
}
elseif ($person_type === 2)
{
    $entityPerson = new LegalPerson();
    $entityPerson->setDescription($orders['leg']['person']['description']);
    $entityPerson->setContactPerson($orders['leg']['person']['contact_person']);
    $entityPerson->setIdentificationType($orders['leg']['identification_type']);
    $entityPerson->setRIF($orders['leg']['rif']);

    $em->persist($entityPerson);
    $em->flush();
}

      

+1


source


Perhaps the problem lies elsewhere. You may forget to assign an object to NaturalPerson

or LegalPerson

to Person

. Therefore, you need to check it before calling getIdentificationType()

:



if($personType == 1){
    if(null !== $natural = $entity->getPerson()->getNaturals()[0]){
       $order[] = $natural->getIdentificationType() . $natural->getCI();
    }
}elseif($personType == 2){
    if(null !== $legal = $entity->getPerson()->getLegals()[0]){
       $order[] = $legal->getIdentificationType() . $legal->getRIF();
    }
}

      

+1


source







All Articles