Same query on different tables... in one case it returns an error

these are the 2 methods (in different classes) completely similar/equal that “act” on 2 different tables:

public function list() {
    return ['title' => 'News list',
            'template' => 'ntn7_listnews.html.php',
            'variables' => [
                'news' => $this->newsTable->findAll()
            ]
        ];
}
public function list() {
    return ['title' => 'Lista Campionati',
            'template' => 'ntn7_listcamp.html.php',
            'variables' => [
                'camps' => $this->campTable->findAll()
            ]
        ];
}

Here is the findAll() method:

    public function findAll() {
        $stmt = $this->pdo->prepare('SELECT * FROM `' . $this->table . '`');
        $stmt->execute();

        return $stmt->fetchAll(\PDO::FETCH_CLASS | \PDO::FETCH_PROPS_LATE, $this->className, $this->constructorArgs);
    }

…and this is the error that is returned ONLY by the first method (the one that should fetch data from the “news” table):

Database error: SQLSTATE[HY000]: General error: could not call class constructor in/volume1/Web/ntn7/Ninja/DbTable.php:46

Line 46 is the “return $stmt…” line.
I’ve done a few tests and searched the web, but nothing conclusive. The last thing that comes to mind is that there’s a connection with the data structure/type of the two tables. That seems unlikely.

Thanks, Gabriele

The problem is with the class definition. There either isn’t a constructor defined or the constructor’s arguments don’t match. What are the values in $this->className and $this->constructorArgs for both cases and what is/are the class definition/s for what is in $this->className?

Here I am
This is the definition of the “News” class:

<?php
namespace Dct\Controllers;

class News {
    
    public function __construct(private \Ninja\DbTable $newsTable) {
    }

This is the definition of the “Campionato” class.

<?php
namespace Dct\Controllers;

class Campionato {
    
    public function __construct(private \Ninja\DbTable $campTable) {
    }

This is the definition of the “DbTable” class.

<?php
namespace Ninja;

class DbTable {

    public function __construct(private \PDO $pdo, private string $table, private string $primaryKey, private string $className = '\stdClass', private array $constructorArgs = []) {
    }

This is the definition of the “DctWebsite” class.

<?php
namespace Dct;

class DctWebsite implements \Ninja\Website {
    private ?\Ninja\DbTable $newsTable;
    private ?\Ninja\DbTable $campTable;
    
    public function __construct() {
        $pdo = new \PDO('mysql:host=localhost;dbname=* * * *;charset=utf8', '* * * *', '* * * *');

        $this->newsTable = new \Ninja\DbTable($pdo, 'TB_News', 'ID_News', '\Dct\Entity\News', [&$this->campTable]);
        $this->campTable = new \Ninja\DbTable($pdo, 'TB_Campionato', 'ID_Campionato', '\Dct\Entity\Campionato', [&$this->newsTable]);

This is the definition of the “Campionato” entity class.

<?php
namespace Dct\Entity;

class Campionato {
    public $ID_Campionato;
    public $ID_Lega;
    public $Anno;
    public $ID_Partecipante;
    public $Chiave_Xor;
    

    public function __construct(private \Ninja\DbTable $newsTable) {
    }
    

    public function getNews() {
        return $this->newsTable->find('ID_Campionato', $this->ID_Campionato);
    }

This is the definition of the “News” entity class

<?php
namespace Dct\Entity;

class News {
    public int $ID_News;
    public int $ID_Campionato;
    public string $TestoNews;
    public string $DataNews;
    public string $Scade;
    private ?object $camp;

    public function __construct(private \Ninja\DbTable $campTable) {
    }
    
    public function getCamp() {
        if (empty($this->camp)) {
            $this->camp = $this->campTable->find('ID_Campionato', $this->ID_Campionato)[0];
        }
        
        return $this->camp;
    }
}

I think I put everything in…

Gabriele

Here’s the likely problem. The last parameter in each line are swapped. The first line should be &$this->newsTable, and the second line should be &$this->campTable.

No the objects appear to be trying to cross-reference each other, so the constructor is attempting to pass an object reference.

But the second object reference doesnt exist when the first object tries to invoke its constructor, leading to problems? I think?

Wouldnt you need to instantiate the second object, pass it (or it’s reference) to the first object’s constructor, and then redefine the second object’s pointer to point at the first object? Because when this line fires:
$this->newsTable = new \Ninja\DbTable($pdo, 'TB_News', 'ID_News', '\Dct\Entity\News', [&$this->campTable]);

the campTable reference is pointing at null.

Wouldnt it be better to pass the Website object reference into the constructors, and do your references via $this->Website->campTable ?
(If for no other reason than when you add a third, or fourth table, you dont need to keep adding new references to all your objects…)

Thanks, this evening I’ll check Tom (Butler)'s book, where this cross-reference “mechanism” is explained, to see if I’ve applied it incorrectly.

Wouldnt it be better to pass the Website object reference into the constructors, and do your references via $this->Website->campTable ?
(If for no other reason than when you add a third, or fourth table, you dont need to keep adding new references to all your objects…)

I’m not qualified, given my skills, to “deviate” from what’s explained in the book… so for now, I’d like to make the site work this way.

Regards, Gabriele

Ah i see. You’re following NTN. Well, mostly following NTN, because you’re already varying things. Trying to make heads or tails out of segmented code like this is always… fun. MVC coding always reads as complete haywire to me…

What’s the structure of the TB_News and TB_Campionato tables? Are you trying to stuff a square peg in a round hole accidentally?

I’m currently adapting the book’s instructions to the website I’d like to create… but I haven’t completed the “path” yet, so the solution might be further down the line. Anyway, I want to check if I’ve applied the “references” and “array-to-object transition” correctly.

I’ll post the table structure this evening… I’m in the office now. :man_facepalming:

I hope not :joy: :joy:

PS: But could the fact that it works with one table and not with another depend on the position in which they are instantiated? If I invert them, does “News” work but “Campionato” not? :thinking:

Its definitely something to test…

The reason for the square peg and round hole thing is if you havent reproduced the table structure correctly in your object, then the constructor will return this error message as well - it tries to construct an object from the table result, and fails because the table “shape” (the square peg) doesnt match the object “shape” (the round hole) so the constructor doesnt know how to instantiate.

CREATE TABLE `TB_Campionato` (
  `ID_Campionato` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `ID_Lega` int(11) NOT NULL,
  `Anno` varchar(10) NOT NULL,
  `ID_Partecipante` int(11) DEFAULT NULL,
  `Chiave_Xor` varchar(75)
) ENGINE=InnoDB;
CREATE TABLE `TB_News` (
  `ID_News` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `ID_Campionato` int(11) NOT NULL,
  `TestoNews` text,
  `DataNews` datetime DEFAULT NULL,
  `Scade` tinyint(1) DEFAULT NULL
) ENGINE=InnoDB;
class News {
    public int $ID_News;
    public int $ID_Campionato;
    public string $TestoNews;
    public string $DataNews;
    public int $Scade;
    private ?object $camp;

Actually, while in the “Campionato” entity class the table fields are not typed… in the “News” entity class the various fields are “declared” and I noticed that the “Scade” field is definitely of type int (I corrected the class but the error remains) and “DataNews” is declared as a “string”… should I change this? How do I declare the date format? with “date”? is correct?

So News doesnt work, Camp does.
Camp’s structure reads:

and it’s table reads:

A 1-1 match.

News DOESNT work. It’s object definition reads:

And it’s table structure reads:

… so what happens if you remove the definition for $camp from the News class, and define it 1-1 with its table? (IE: Is the Entity constructor complaining because it doesnt know the definition for $camp ? Could this maybe be solved by giving a default value to $camp of null? [I don’t actually know this. I’ve never tried to use PDO::FETCH_CLASS, so…])

Looking back at the book, this instruction (private ?object $camp;) is only used to implement a technique called “transparent caching” for quicker access to certain data.

The only difference is in the definition of the “DataNews” field (which in the DB has the “datetime” format), which isn’t present in the example in the book.

The cross-reference I applied is also as explained in the book.

I’m currently considering whether to get to the end and see if there are any instructions that could solve the problem, or to go back and reapply each individual instruction and see when the problem arises… who knows?

bye, Gabriele

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.