1

I have a inheritance of three levels using class table inheritance like this:

Class Test

namespace App\Entities\Test;

use Doctrine\ORM\Mapping as ORM;

/**
 * Class Test
 * @package App\Entities\Test
 * @ORM\Entity
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="discr", type="string")
 * @ORM\DiscriminatorMap({"TestA" = "TestA", "TestB" = "TestB"})
 * @ORM\Table(name="test")
 */
abstract class Test {

  /**
   * @var integer
   * @ORM\Column(type="integer")
   * @ORM\Id
   * @ORM\GeneratedValue(strategy="IDENTITY")
   */
  protected $id;

  /**
   * @var string
   * @ORM\Column(type="string")
   */
  protected $columnTest;
}

Class TestM extends Test

namespace App\Entities\Test;

use Doctrine\ORM\Mapping as ORM;

/**
 * Class TestM
 * @package App\Entities\Test
 * @ORM\Entity
 */
abstract class TestM extends Test{

  /**
   * @var string
   * @ORM\Column(type="string")
   */
  protected $columnTestM;

}

Class TestA extends TestM

namespace App\Entities\Test;

use Doctrine\ORM\Mapping as ORM;

/**
 * Class TestA
 * @package App\Entities\Test
 * @ORM\Entity
 */
class TestA extends TestM{

  /**
   * @var string
   * @ORM\Column(type="string")
   */
  private $columnTestA;

  public function __construct(string $columnTest, string $columnTestM, string $columnTestA) {
    $this->columnTest = $columnTest;
    $this->columnTestM = $columnTestM;
    $this->columnTestA = $columnTestA;
  }

  /**
   * @return string
   */
  public function getColumnTest(): string {
    return $this->columnTest;
  }

  /**
   * @param string $columnTest
   */
  public function setColumnTest(string $columnTest): void {
    $this->columnTest = $columnTest;
  }

  /**
   * @return string
   */
  public function getColumnTestM(): string {
    return $this->columnTestM;
  }

  /**
   * @param string $columnTestM
   */
  public function setColumnTestM(string $columnTestM): void {
    $this->columnTestM = $columnTestM;
  }

  /**
   * @return string
   */
  public function getColumnTestA(): string {
    return $this->columnTestA;
  }

  /**
   * @param string $columnTestA
   */
  public function setColumnTestA(string $columnTestA): void {
    $this->columnTestA = $columnTestA;
  }
}

I'm having problem because, when I'm going to retrieve the entity from my DB, it comes with the second level with no data, only the first and last levels comes with all the data. Notice that columnTestM is blank. What am I missing? It's persisting with all three levels with data, the problem is only when I have to get it. As an example I put the column's content with it's own name

>>> print_r(\EntityManager::getRepository('App\Entities\Test\Test')->find(1));
App\Entities\Test\TestA Object
(
    [columnTestA:App\Entities\Test\TestA:private] => columnTestA
    [columnTestM:protected] => 
    [id:protected] => 1
    [columnTest:protected] => columnTest
)

EDIT:

Maybe it's a bug and I filed an issue at GitHub about a wrong query generation. I put my MariaDB to log all queries to check the query being generated when I try to retrieve the data back and that's the result:

SELECT 
    t0.id AS id_3,
    t0.column_test AS column_test_4,
    t0.discr,
    t1.column_test_a AS column_test_a_5,
    t2.column_test_b AS column_test_b_6
FROM
    test t0
        LEFT JOIN
    test_as t1 ON t0.id = t1.id
        LEFT JOIN
    test_bs t2 ON t0.id = t2.id
WHERE
    t0.id = 1

It tries to left join with TestB instead of doing the join with TestM

Leandro Jacques
  • 413
  • 5
  • 19
  • without having tested it, perhaps your issue is the inheritance with two abstract classes in the chain, while I appreciate that it should work, perhaps you investigate there. one potentially question I found is here: https://stackoverflow.com/questions/7269641/php-abstract-class-extending-another-abstract-class – LBA Apr 30 '20 at 12:30
  • @lba it persists normally, so it works. Doctrine is able to recognize this when persisting, but it doesn't work properly when retrieving. That's the strange thing, if it would be a problem two abstract classes, the object persistence would fail in the second level too, leaving the middle table empty I think. – Leandro Jacques Apr 30 '20 at 12:50
  • but persistence and object hydration works a bit differently, so still it could be related, but indeed an interesting behaviour – LBA Apr 30 '20 at 15:25
  • Have you tried to put a @MappedSuperclass on TestM instead of @Entity? – Alessandro Chitolina May 03 '20 at 00:24
  • @lba is right, I tried with concrete class in the middle and worked. But it should work. – Leandro Jacques May 05 '20 at 19:51

1 Answers1

0

As stated by @LBA the problem is two abstract classes in the chain. It should work even with two abstract classes, but only the first is retrieved, but all the others in the middle stays blank. Issue already reported in doctrine's github project.

Leandro Jacques
  • 413
  • 5
  • 19