Слой бизнес логики¶
В платформе oxwall все классы для работы с бизнес логикой принято хранить в директории bol внутри плагина (подробнее в разделе - “Структура плагина”).
База данных¶
Для работы с базой данных нужно описать классы DTO (Data Transfer Object) и DAO (Data Access Object) для для каждой таблицы базы данных используемых в плагине.
DTO - Data Transfer Object¶
Класс DTO описывает сущность таблицы и используется при добавлении или изменении данных в таблице. Пример класса описывающий сущность - “message”:
<?php
class MYSUPERPLUGIN_BOL_Message extends OW_Entity
{
/**
* Title
*
* @var string
*/
public $title;
/**
* Message
*
* @var string
*/
public $message;
/**
* Created timestamp
*
* @var integer
*/
public $createdTimestamp;
/**
* Approved flag
*
* @var integer
*/
public $approved;
}
Как видно на примере, класс MYSUPERPLUGIN_BOL_Message описывает структуру таблицы message, перечисляя в этом классе все поля, а также значения по умолчанию этих полей если нужно.
DAO - Data Access Object¶
В классе DAO описывается вся бизнес логика работы с базой данных: поиск, создание и удаление записей. Все классы DAO всегда реализуют паттерн - Singleton Object. Пример класса DAO:
<?php
class MYSUPERPLUGIN_BOL_MessageDao extends OW_BaseDao
{
/**
* Approved status
*/
const APPROVED_STATUS = 1;
/**
* Disapproved status
*/
const DISAPPROVED_STATUS = -1;
/**
* Singleton instance.
*
* @var MYSUPERPLUGIN_BOL_MessageDao
*/
private static $classInstance;
/**
* Returns an instance of class (singleton pattern implementation).
*
* @return MYSUPERPLUGIN_BOL_MessageDao
*/
public static function getInstance()
{
if ( self::$classInstance === null )
{
self::$classInstance = new self();
}
return self::$classInstance;
}
/**
* Constructor.
*/
protected function __construct()
{
parent::__construct();
}
/**
* Get DTO class name
*
* @return string
*/
public function getDtoClassName()
{
return 'MYSUPERPLUGIN_BOL_Message';
}
/**
* Get table name
*
* @return string
*/
public function getTableName()
{
return OW_DB_PREFIX . 'mysuperplugin_message';
}
/**
* Delete message
*
* @param integer $userId
* @param integer $recipientId
* @return void
*/
public function deleteMessage($userId, $recipientId)
{
$example = new OW_Example();
$example->andFieldEqual('userId', $userId);
$example->andFieldEqual('recipientId', $recipientId);
$this->deleteByExample($example);
}
/**
* Find active messages
*
* @param integer $limit
* @return array
*/
public function findActiveMessages($limit)
{
$example = new OW_Example();
$example->setOrder('`id` ASC');
$example->andFieldEqual('status', self::APPROVED_STATUS);
$example->setLimitClause(0, $limit);
return $this->findListByExample($example);
}
/**
* Find active messages using the raw sql
*
* @param integer $limit
* @return array
*/
public function findActiveMessagesRawSql($limit)
{
$query = "SELECT * FROM `" . $this->getTableName() . "` LIMIT ?";
return $this->dbo->queryForList($query, array($limit));
}
}
В данном классе нужно указать название таблицы базы данных в методе getTableName, а также название DTO класса в методе getDtoClassName. Следует отметить тот факт, что если вы работаете только с одной таблицей то необходимо использовать конструктор запросов - OW_Example, а если в запросе необходимы сложные объединения тогда нужно писать сырые запросы к базе данных, как это сделано в методе - findActiveMessagesRawSql.
Сервис¶
Класс service.php является центральным для плагина, так как именно его нужно использовать в качестве провайдера данных, а также инкапсулировать в нем всю бизнес логику плагина (даже если вы не работаете с БД). Стоит отметить, что если вы используете работу с базой данных то класс service.php будет выступать как бы промежуточным слоем, т.е нельзя из кода контроллеров или откуда-либо еще напрямую обращаться к классам для работы с базой данных для этого нужен сервис. Класс service.php так же как и классы DAO всегда реализует паттерн - Singleton. Пример сервиса и инкапсуляции в нем работы с базой данных :
<?php
class MYSUPERPLUGIN_BOL_Service
{
/**
* Class instance
*
* @var MYSUPERPLUGIN_BOL_Service
*/
private static $classInstance;
/**
* Message DAO
*
* @var MYSUPERPLUGIN_BOL_MessageDao
*/
private $messageDao;
/**
* Class constructor
*/
private function __construct()
{
$this->messageDao = MYSUPERPLUGIN_BOL_MessageDao::getInstance();
}
/**
* Returns class instance
*
* @return MYSUPERPLUGIN_BOL_Service
*/
public static function getInstance()
{
if ( self::$classInstance === null )
{
self::$classInstance = new self();
}
return self::$classInstance;
}
/**
* Add message
*
* @param MYSUPERPLUGIN_BOL_Message $messageDto
* @return void
*/
public function addMessage(MYSUPERPLUGIN_BOL_Message $messageDto)
{
$messageDto->createdTimestamp = time();
$messageDto->approved = MYSUPERPLUGIN_BOL_MessageDao::APPROVED_STATUS;
$this->messageDao->save($messageDto);
}
/**
* Remove message
*
* @param integer $messageId
* @return void
*/
public function deleteMessage($messageId)
{
$this->messageDao->deleteById($messageId);
}
/**
* Find active messages
*
* @param integer $limit
* @return array
*/
public function findActiveMessages($limit)
{
return $this->messageDao->findActiveMessages($limit);
}
// … etc
}
PS: По возможности нужно максимально выносить логику из контроллеров и компонентов в сервисы и делать эти методы готовыми к повторному использованию.