Планирование большого приложения Yii2

Я думаю о том, как создать большое приложение для клиента в Yii2. Мой опыт основан на нескольких небольших проектах Yii2.

Какие основные решения должны быть приняты на первых этапах, которые впоследствии не могут быть легко изменены, и каковы типичные шаблоны решения Yii2 для этого?

Вот некоторые особенности, о которых я думаю:

Администрирование пользователей

Начальным шагом является расширение Yii2-user или Yii2-usario. Предоставляет управление пользователями, вход в систему, функции сброса пароля и тому подобное.

Мульти аренды

Для управления несколькими клиентами в одной базе данных рекомендуется добавлять идентификатор клиента в каждую таблицу и использовать поведение Yii2 для добавления этого поля таблицы в каждый запрос к базе данных.

Дополнительные / сложные функции

Yii2 предоставляет «модули» для разделения кода. Модули Yii2 могут иметь компоненты, модели, виды, контроллеры и … идеально подходят для предоставления независимых функций на более позднем этапе. Или отделить функции от основного приложения.

Существуют ли похожие шаблоны Yii2, о которых нужно знать с самого начала проекта, чтобы избежать значительного рефакторинга в ходе проекта?

2

Решение

Важная скороговорка, доступная в Yii2, для меня RBAC (авторизация по ролям) ..

Если приложение большое, помните, что вам может понадобиться Internazionalization на дату, валюту, формат и мультиязычность

аудит для проверки, кто имеет доступ к чему-либо (для этого тоже есть хорошее расширение)

2

Другие решения

в yii2 вы можете запускать несколько приложений из одной кодовой базы. Расширенный шаблон yii2 дает вам отличную отправную точку, но у вас может быть более одного «внешнего» приложения. это поможет тебе поделиться или разделить конфигурации (включая базы данных) для ваших интерфейсов. так что вы можете повторно использовать общие модули в своих приложениях, а также иметь свободу делать что-то совершенно другое.

возможно, это выходит за рамки, но для реализации мультитенантности я ограничил доступ к строкам данных только для членов группы посредством поведения.
предложение where автоматически применяется ко всем выборкам, поэтому вы можете вернуть клиенту только те строки, которые ему принадлежат. в своем коде вы теперь можете выбирать и присоединяться, не думая о владении.

ActiveRecord.php

<?php
namespace common\models;

use Yii;
use yii\helpers\Url;

class ActiveRecord extends \yii\db\ActiveRecord
{

public function behaviors()
{
return [
'group' => [
'class'     => \x1\data\behaviors\GroupBehavior::className(),
'map'       => ['gid' => 'group_id'],
'className' => \common\models\Group::className(),
],
];
}public static function checkAccess() {
if (!Yii::$app instanceof \yii\console\Application) {
$user     = Yii::$app->get('user', false);
$identity = ($user) ? $user->getIdentity() : null;

if (empty($identity)) {
if (!empty($user->loginUrl))
return Yii::$app->getResponse()->redirect($user->loginUrl);
else
throw new \yii\web\UnauthorizedHttpException;
}
}
}//
//  select only rows within the user's group,
//  except for console app
//
public static function find() {
self::checkAccess();
return (new ActiveQuery(get_called_class()))->current();
}

}

?>

GroupBehaviour.php

<?php
namespace x1\data\behaviors;

use Yii;
use yii\base\Event;
use yii\db\BaseActiveRecord;

/*

class myModel extends \yii\db\ActiveRecord
{

public function behaviors()
{
return [
'group' => [
'class'     => \x1\data\behaviors\GroupBehavior::className(),
'map'       => ['gid' => 'group_id'],
'className' => \common\models\Group::className(),
],
];
}

}

*/
class GroupBehavior extends \yii\behaviors\AttributeBehavior
{
public $map       = ['gid' => 'group_id'];
public $className = null;
public $value;public function getGroup() {
return $this->owner->hasOne($this->className, $this->map);
}/**
* @inheritdoc
*/
public function init()
{
parent::init();

if ($this->className == null) {
throw new \yii\base\InvalidConfigException("'className' must be set");
}

if (!is_array($this->map)) {
throw new \yii\base\InvalidConfigException("'map' must be an array; e.g.: ['gid' => 'group_id']");
} else {
if (!count($this->map) > 0) {
throw new \yii\base\InvalidConfigException("'map' must contain the mapping group => local; e.g.: ['gid' => 'group_id']");
}
}

if (!Yii::$app instanceof \yii\console\Application) {
if (empty($this->attributes)) {
$this->attributes = [
BaseActiveRecord::EVENT_BEFORE_INSERT => array_values($this->map)[0],
];
}
}
}

/**
* Evaluates the value of the user.
* The return result of this method will be assigned to the current attribute(s).
* @param Event $event
* @return mixed the value of the user.
*/
protected function getValue($event)
{
if ($this->value === null) {
$user  = Yii::$app->get('user', false);
$group = array_keys($this->map)[0];
return ($user && !$user->isGuest) ? $user->identity->group->$group : null;
} else {
return call_user_func($this->value, $event);
}
}

}

ActiveQuery.php

<?php
namespace common\models;
use Yii;

class ActiveQuery extends \yii\db\ActiveQuery
{
private $_alias = null;

private function getAlias() {

if ($this->_alias === null) {

if (empty($this->from)) {
$modelClass = $this->modelClass;
$tableName  = $modelClass::tableName();
} else {
foreach ($this->from as $alias => $tableName) {
if (is_string($alias)) {
$this->_alias = $alias;
return $this->_alias;
} else {
break;
}
}
}

if (preg_match('/^(.*?)\s+({{\w+}}|\w+)$/', $tableName, $matches)) {
$this->_alias = $matches[2];
} else {
$this->_alias = $tableName;
}

}
return $this->_alias;
}

public function current()
{
$alias = $this->getAlias();

if (!Yii::$app instanceof \yii\console\Application)
$this->andWhere(['IN', sprintf('COALESCE(%s.group_id,0)', $alias), [0, Yii::$app->user->identity->group_id]]);

return $this;
}public function rawSql() {
return $this->prepare(Yii::$app->db->queryBuilder)->createCommand()->rawSql;
}

}

?>
1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector