PHP Migration örneği ile Builder Design Pattern
Builder design pattern , oluşturulması karmaşık olan objeleri parçalara bölerek oluşturmamızı sağlayan bir design patterndir. Bu sayede sadece ihtiyacımız olan özellikleri oluşturan fonksiyonları çağırıp, farklı özelliklere sahip yapıları aynı class üzerinden oluşturabiliriz.
Bu konuyu anlamak için en iyi örneklerden biri ev örneğidir. Bir ev classımız olduğunu hayal edelim. Bu evin pencereleri, kapıları, garajı, havuzu olabilir. Fakat her ev bunların hepsine sahip olmayabilir. Burada genelde yaşanan sıkıntı tüm bu özellikleri bir constructor içine parametrik olarak vermek ve onu kullanmaktır.
class House {
public function __construct($rooms, $garden, $pool, $windows)
{
}
Çok sayıda parametre içeren bir constructor olması ve bunların hepsine her zaman ihtiyacımız olmamasına rağmen sürekli yollamamız gerekmesi bir dezavantajdır.
new House(3, false, false, 2);
new House(2, false, true, 3);
Buna çözüm olarak her yapıyı özel olarak oluşturacak bir fonksiyon kullanıp sadece ihtiyacımız olanları çağırabiliriz.
class HouseBuilder {
public function createDoors()
{
}
public function createWindows()
{
}
public function createPool()
{
}
}
$houseBuilder = new HouseBuilder();
$houseWithPool = $houseBuilder->createDoors()->createWindows()->createPool();
$houseWithoutPool = $houseBuilder->createDoors()->createWindows();
Bu şekilde havuzu olan bir ev oluşturmak istiyorsak sadece o fonksiyonu çağırmamız yeterli olacaktır. Constructor içine gereksiz parametreler yollamaktan da kurtulmuş olduk.
Bu örnekten sonra daha sektöre yönelik bir örnek üzerinden ilerleyebiliriz. MySQL ile yaptığımız tablo oluşturma işlemlerini daha kolay hale getirmek için bir migration yapısına ihtiyacımız olduğunu düşünelim.
class Migration
{
private $_pdo;
private $_columns;
private $_tableName;
private $_query;
public function __construct()
{
$config = getConfig();
$this->_pdo = new PDO(
"mysql:host={$config['dbHost']};dbname={$config['dbName']}",
$config['dbUser'],
$config['dbPassword']
);
}
/**
* @param string $columnName
* @param int $size
* @return Migration
*/
public function integer(string $columnName, int $size = 11): Migration
{
$this->_columns[] = "$columnName INT ($size)";
return $this;
}
/**
* @param string $columnName
* @param int $size
* @return Migration
*/
public function varchar(string $columnName, int $size = 255): Migration
{
$this->_columns[] = "$columnName VARCHAR ($size)";
return $this;
}
/**
* @param string $columnName
* @param bool $defaultTimeStamps
* @param bool $onUpdateTimeStamp
* @return Migration
*/
public function dateTime(string $columnName, bool $defaultTimeStamps = false, bool $onUpdateTimeStamp = false): Migration
{
$dateQuery = "$columnName DATETIME";
if ($defaultTimeStamps) {
$dateQuery .= ' DEFAULT CURRENT_TIMESTAMP';
}
if ($onUpdateTimeStamp) {
$dateQuery .= ' ON UPDATE CURRENT_TIMESTAMP';
}
$this->_columns[] = $dateQuery;
return $this;
}
/**
* @param string $columnName
* @param int $size
* @return Migration
*/
public function autoIncrementId(string $columnName = 'id', int $size = 11): Migration
{
$this->_columns[] = "$columnName INT ($size) AUTO_INCREMENT PRIMARY KEY";
return $this;
}
/**
* @param string $tableName
* @return Migration
*/
public function tableName(string $tableName): Migration
{
$this->_tableName = $tableName;
return $this;
}
public function create()
{
$this->_query = 'CREATE TABLE ' . $this->_tableName . '(';
foreach ($this->_columns as $column) {
$this->_query .= $column . ',';
}
$this->_query = rtrim($this->_query, ',') . ')';
return $this->_pdo->exec($this->_query);
}
public function getQuery()
{
return $this->_query;
}
public function getTableName()
{
return $this->_tableName;
}
}
Bu class sayesinde tabloyu oluştururken istediğimiz veri tiplerini fonksiyonları çağırarak kolayca ekleyebiliyoruz. Ayrıca en son create metodunu çağırmak şartıyla diğer fonksiyonları çağırma sıramızda önemli değil ve her fonksiyon obje döndüğü için bunları zincirleme olarak kullanabiliriz.
$migration = new Migration();
$migration
->tableName('Users')
->autoIncrementId('id')
->integer('age')
->varchar('name')
->varchar('email')
->dateTime('created_at', true)
->dateTime('updated_at', true, true)
->create();
Bu şekilde kolayca bir users tablosu oluşturabiliriz.