Is there a way to json parse string before making it a class with PDO? I don't like using union types.
In the example below contact is of type json in the database.
PDO
$stmt = $DB->prepare("SELECT first_name, last_name, contact FROM users");
$stmt->execute();
$stmt->fetchAll(PDO::FETCH_CLASS, 'User');
User class
<?php
class User {
public string $first_name;
public string $last_name;
public string | object $contact;
public function __construct() {
$this->contact = json_decode($this->contact);
}
}
CodePudding user response:
As Movahhedi suggested you could use PDO::FETCH_FUNC
, but the json_decode()
should take place in the passed function, not in the constructor. My suggestion would be to create a UserFactory
class with a method like createFromDbRow()
, although just defining it as a bare function would work just as well too, of course:
class User {
public string $first_name;
public string $last_name;
public object $contact;
}
class UserFactory {
public function createFromDbRow(string $first_name, string $last_name, string $contact) : User {
$user = new User();
$user->first_name = $first_name;
$user->last_name = $last_name;
$user->contact = json_decode( $contact );
return $user;
}
}
$db = new PDO('sqlite::memory:');
$db->exec('CREATE TABLE "users" ( "id" INTEGER, "first_name" TEXT, "last_name" TExT, "contact" TEXT )');
$db->exec('INSERT INTO "users" VALUES( 1, \'John\', \'Doe\', \'{"email":"[email protected]"}\')');
$db->exec('INSERT INTO "users" VALUES( 2, \'Jane\', \'Doe\', \'{"email":"[email protected]"}\')');
$userFactory = new UserFactory();
$stmt = $db->prepare("SELECT first_name, last_name, contact FROM users");
$stmt->execute();
$users = $stmt->fetchAll(PDO::FETCH_FUNC, [$userFactory, 'createFromDbRow' ]);
var_dump( $users );
Since the User
properties are all public I left out a constructor, but you could of course define a constructor as well:
class User {
public string $first_name;
public string $last_name;
public object $contact;
public function __construct(string $first_name, string $last_name, object $contact) {
$this->first_name = $first_name;
$this->last_name = $last_name;
$this->contact = $contact;
}
}
...and then create the User
s in UserFactory::createFromDbRow()
by utilizing the constructor:
class UserFactory {
public function createFromDbRow(string $first_name, string $last_name, string $contact) : User {
return new User(
$first_name,
$last_name,
json_decode( $contact )
);
}
}
CodePudding user response:
You can use FETCH_FUNC
The function we define actually does what the constructor does
function customConstruct(first_name, $last_name, $contact) {
return new User($first_name, $last_name, $contact);
}
Now we do it
$stmt = $DB->prepare("SELECT first_name, last_name, contact FROM users");
$stmt->execute();
$stmt->fetchAll(PDO::FETCH_CLASS, 'User');
$results = $stmt->fetchAll(PDO::FETCH_FUNC, "customConstruct");
User class
class User {
public string $first_name;
public string $last_name;
public object $contact;
public function __construct($first_name, $last_name, $contact) {
$this->first_name = $first_name;
$this->last_name = $last_name;
$this->contact = json_decode($contact);
}
}
if you need an array, use:
$this->contact = json_decode($contact, true);
EDIT
We maybe able to put the new function in the class. I'm not 100% sure though.
class User {
public string $first_name;
public string $last_name;
public object $contact;
public function __construct($first_name, $last_name, $contact) {
$this->first_name = $first_name;
$this->last_name = $last_name;
$this->contact = json_decode($contact);
}
function customConstruct(first_name, $last_name, $contact) {
return new User($first_name, $last_name, $contact);
}
}