I'm refactoring parts of my application and replace some fetch(PDO::FETCH_ASSOC)
to dedicated classes with fetchObject()
.
Is there a way to access the pdo instance inside the generated class? See this example:
class User
{
private $id;
private $username;
private $firstname;
private $lastname;
public function setFirstname($newValue)
{
if (empty($newValue) || !is_string($newValue)) throw new Exception('Wrong');
$this->firstname = $newValue;
}
public function save()
{
// IMPORTANT PART:
// I don't want to use the global object container here
$dbh = Application::getInstance()->getPDO();
$sth = $dbh->prepare('UPDATE main_user SET firstname = :firstname WHERE id = :id');
$sth->execute([
'id' => $this->id,
'firstname' => $this->firstname,
]);
}
}
$dbh = $application->getPDO();
$sth = $dbh->prepare('SELECT * FROM main_user WHERE id = ?');
$sth->execute([ 10 ]);
$user = $sth->fetchObject('User');
$user->setFirstname('Test');
$user->save();
Parts of my application use multiple databases and thus multiple pdo objects. To get reuseable code, I'd like to prevent using my global container class - and global
of course.
You can pass the PDO Instance so you don't have to call Application::getInstance()->getPDO() again.
public function save(PDO $dbh)
{
$sth = $dbh->prepare('UPDATE main_user SET firstname = :firstname WHERE id = :id');
$sth->execute([
'id' => $this->id,
'firstname' => $this->firstname,
]);
}
// and pass the (already available) $dbh to the save-Method at the buttom
$user->save($dbh);
or as CD001 mentioned in the comments, you can also pass it to the constructor:
class User
{
// ...
private $conn;
public function __construct(PDO $conn)
{
$this->conn = $conn;
}
}
// ... later at the bottom when fetching the Object:
$user = $sth->fetchObject('User', [ $dbh ]);
You should have an user repository which will save the user to db:
use \Path\To\User\Model\User;
class UserRepository extends AbstractRepository
{
public function save(User $user)
{
$sth = $this->db->prepare('UPDATE main_user SET firstname = :firstname WHERE id = :id');
$sth->execute([
'id' => $user->id, // make sure these properties are public on the model
'firstname' => $user->firstname,
]);
}
}
class AbstractRepository
{
protected $db;
// inject it using Dependency Injection
public function __construct(DbInterface $db)
{
$this->db = $db;
}
}
Then, in your Model you can use the user repository to save it to db:
namespace \Path\To\User\Model;
class User
{
public $id;
public $username;
public $firstname;
public $lastname;
protected $userRepository;
// inject it with DI
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
public function setFirstname($firstname)
{
if (empty($firstname) || !is_string($firstname)) {
throw new Exception('Wrong firstname!');
}
$this->firstname = $firstname;
return $this;
}
public function save()
{
return $this->userRepository->save($this);
}
}
Now you need to register these classes to a Dependency Injection Framework such as PHP-DI and to use them appropriately..
$user = $container->get('User');
$user->setFirstname('MyUser');
$user->create();
If you are refactoring your app then you should do it right.
Please note that the examples above are just informative and they need many improvements to be used in production.