AI Reading
Quick summary of this article
Zend Framework 3 (ZF3) uses the ZendDb component to handle database operations, with the TableGateway pattern being the recommended way to perform CRUD actions. Models represent data entities, and the Service Manager injects the database adapter into these models for clean separation of concerns.
- Configure the database connection in the module's config file using the ZendDbAdapterAdapterServiceFactory, specifying driver, database name, username, password, and hostname.
- Create model classes with an exchangeArray() method to map database rows to object properties, and use TableGateway classes to handle select, insert, update, and delete operations.
- Register TableGateway services in Module.php using factories that set up the ResultSet prototype and bind the model to the database table.
- Inject the TableGateway-based model into controllers via the constructor so actions can easily fetch and display data from the database.
- Always use TableGateway's built-in prepared statements to prevent SQL injection, and keep business logic in models rather than controllers.
✅ Introduction
In modern web applications, data storage and retrieval is crucial. Zend Framework 3 (ZF3) provides multiple ways to interact with databases. The most common and recommended approach is to use the Zend\Db component, which offers a structured way to write queries, build models, and perform CRUD operations.
✅ Key Concepts
- Zend\Db\Adapter: The database connection handler.
- Zend\Db\TableGateway: A simple way to map tables to classes for CRUD operations.
- Models: PHP classes representing business logic and data entities.
- Service Manager: Injects database adapter into your models.
✅ Setting Up Database Adapter
Open module.config.php of your module and configure the database adapter in service_manager:
return [
'service_manager' => [
'factories' => [
Zend\Db\Adapter\Adapter::class => Zend\Db\Adapter\AdapterServiceFactory::class,
],
],
];
Then, in your global.php or local.php config file:
return [
'db' => [
'driver' => 'Pdo_Mysql',
'database' => 'zf3_tutorial',
'username' => 'root',
'password' => '',
'hostname' => 'localhost',
],
];
✅ Creating a Model
Let’s create a model class for a users table:
namespace Application\Model;
class User
{
public $id;
public $name;
public $email;
public function exchangeArray(array $data)
{
$this->id = !empty($data['id']) ? $data['id'] : null;
$this->name = !empty($data['name']) ? $data['name'] : null;
$this->email = !empty($data['email']) ? $data['email'] : null;
}
}
✅ Using TableGateway
Now create a UserTable class that uses TableGateway:
namespace Application\Model;
use RuntimeException;
use Zend\Db\TableGateway\TableGatewayInterface;
class UserTable
{
private $tableGateway;
public function __construct(TableGatewayInterface $tableGateway)
{
$this->tableGateway = $tableGateway;
}
public function fetchAll()
{
return $this->tableGateway->select();
}
public function getUser($id)
{
$id = (int) $id;
$rowset = $this->tableGateway->select(['id' => $id]);
$row = $rowset->current();
if (! $row) {
throw new RuntimeException(sprintf(
'Could not find user with id %d',
$id
));
}
return $row;
}
public function saveUser(User $user)
{
$data = [
'name' => $user->name,
'email' => $user->email,
];
$id = (int) $user->id;
if ($id === 0) {
$this->tableGateway->insert($data);
return;
}
if (! $this->getUser($id)) {
throw new RuntimeException(sprintf(
'Cannot update user with id %d; does not exist',
$id
));
}
$this->tableGateway->update($data, ['id' => $id]);
}
public function deleteUser($id)
{
$this->tableGateway->delete(['id' => (int) $id]);
}
}
✅ Registering the Table in Module
Update Module.php of your module to register the service:
public function getServiceConfig()
{
return [
'factories' => [
Model\UserTable::class => function($container) {
$tableGateway = $container->get(Model\UserTableGateway::class);
return new Model\UserTable($tableGateway);
},
Model\UserTableGateway::class => function ($container) {
$dbAdapter = $container->get(AdapterInterface::class);
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Model\User());
return new TableGateway('users', $dbAdapter, null, $resultSetPrototype);
},
],
];
}
✅ Using the Model in a Controller
Finally, inject UserTable into a controller:
namespace Application\Controller;
use Application\Model\UserTable;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
class UserController extends AbstractActionController
{
private $table;
public function __construct(UserTable $table)
{
$this->table = $table;
}
public function indexAction()
{
return new ViewModel([
'users' => $this->table->fetchAll(),
]);
}
}
✅ Best Practices
- Always use prepared statements via TableGateway to avoid SQL injection.
- Keep business logic in models, not in controllers.
- Use ResultSet to map DB results to objects.
✅ Exercise
- Create a
poststable and correspondingPostmodel. - Build a
PostTablewith CRUD operations. - Display posts in a new controller action.
