Home > front end >  PDO json_decode before fetch into class
PDO json_decode before fetch into class

Time:10-19

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 Users 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);
    }
}
  •  Tags:  
  • php
  • Related