Валідація даних вкладених документів MongoDB в Yii2

Можливо, все, що я напишу нижче – очевидно, і всі цим користуються давно, але я ось недавно тільки це зрозумів і придумав, так що, може, комусь і стане в нагоді.
Yii2 і розширення yii2-mongodb на жаль, не працює з вкладеними документами, тим самим залишаючи за бортом суттєву перевагу документоориентированной БД.
В документації пропонують використовувати розширення для вкладених документів, але можна обійтися і без нього.
Припустимо, у нас є модель, що формує PDF-файл для завантаження, і ми хочемо стежити за кількістю його завантажень, IP-адресами скачали і, наприклад, часом, коли файл був завантажений.
Для простоти я припускаю, що сам файл зберігається в рядку, але це, звичайно, може бути зовсім не так – він може лежати десь у сховище або формуватися функцією.
Основна модель (частина)
/**
* @property string $pdf_data стоку з даними, яка потім перетворюється в файл
* @property array $downloads_data тут зберігаються відомості про завантаження
*
*/
Class PdfData extends \yii\mongodb\ActiveRecord

/** @inheritdoc */
public static function collectionName()
{
return ['database', 'pdf"']
}

/** @inheritdoc */
public function attributes()
{
return [
'pdf_data',
'downloads_data'
];
}

Додаткова модель – для перевірки та присвоєння значень елементів масиву

use \MongoDB\BSON\UTCDateTime

/**
* Клас для формування відомостей про факт завантаження файлу
*/
class DowmnloadData extends \yii\base\Model
{
/** @var \MongoDB\BSON\UTCDateTime $datetime */
public $datetime;
/** @var string $clientIp */
public $clientIp;
/** @var string $clientHost */
public $clientHost;
/** @var string $clientUserAgent */
public $clientUserAgent;
/** @var string $referer */
public $referer;
/** @var bool $result */
public $result = false;

/** @inheritdoc */
public function rules()
{
return [
['datetime', 'default', 'value' => function() 
{ return new UTCDateTime(strtotime("now") * 1000); }],
['clientIp', 'default', 'value' => function() 
{ return Yii::$app->request->getUserIP(); }],
['clientHost', 'default', 'value' => function() 
{ return Yii::$app->request->getUserHost(); }],
['clientUserAgent', 'default', 'value' => function() 
{ return Yii::$app->request->getUserAgent(); }],
['referer', 'default', 'value' => function() 
{ return Yii::$app->request->getReferrer(); }],
['result', 'boolean'],
];
}

Далі, в дії контролера, яке віддає файл назовні, приблизно наступне:
// -- skip --

/**
* @param string $id ідентифікатор основної моделі
* @return null
* @throws \yii\web\NotFoundHttpException
*/
public function actionDownload($id)
{
if(($model = PdfData::findOne($id)) === null)
throw new \yii\web\NotFoundHttpException(Yii::t('app', 'File not found'));

$downloadData = new DowmnloadData();
if(!empty($model->pdf_data))
{
$downloadData->result = true;
$downloadData->validate(); // Так ми добиваємося присвоєння значень за замовчуванням
$data = $model->downloads_data; // Забрали існуючі відомості про завантаження
$data[] = $downloadData->attributes; // Додали до них нові
// array_values для гарантироанного збереження масиву (а не об'єкта) mongodb
$model->updateAttributes(['downloads_data' => array_values($data)]); 

// Відправляємо файл
Yii::$app->response->sendContentAsFile($model->pdf_data, 'we are the champions.pdf', [
'mimeType' => 'text/xml',
'inline' => true
]);
}
return null;
}

Таким чином всередині масиву
downloads_data
основної моделі ми маємо всі атрибути, які придумали
DowmnloadData
, і можемо їх потім як завгодно показувати і аналізувати, не множачи понад необхідного при цьому ні атрибути основної моделі, ні кількість колекцій в БД.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.