While I am testing yii2 multiple select2 tutorial, I faced the error "Class 'common\models\LinkAllBehavior' not found".
Here is my model code,
public $tag_ids;
public static function tableName()
{
return 'post';
}
public function rules()
{
return [
[['title', 'body','tag_ids'], 'required'],
[['body'], 'string'],
[['title'], 'string', 'max' => 255],
];
}
public function attributeLabels()
{return [
'id' => 'ID',
'title' => 'Title',
'body' => 'Body',
];}
public function behaviors()
{
return [
LinkAllBehavior::className(),
];
}
public function afterSave($insert, $changedAttributes)
{
$tags = [];
foreach ($this->tag_ids as $tag_name) {
$tag = Tag::getTagByName($tag_name);
if ($tag) {
$tags[] = $tag;
}
}
$this->linkAll('tags', $tags);
parent::afterSave($insert, $changedAttributes);
}
public function getPostToTags()
{
return $this->hasMany(PostToTag::className(), ['post_id' => 'id']);
}
public function getTags()
{
return $this->hasMany(Tag::className(), ['id' => 'tag_id'])->viaTable('post_to_tag', ['post_id' => 'id']);
}
}
So, I would like to know what is LinkAllBehavior and how does it work?
Thanks
LinkAllBehavior::className()
above line is causing this, if you are using yii2-linkall
try adding
use cornernote\linkall\LinkAllBehavior;
on top of your model code along with other use statements
Related
I encountered such a problem, a certain query "name", which the user entered, is not stored in the database, and even this stupid error with which I can not cope at all takes off .. apparently I'm more stupid than her .. please tell me what is the catch?
Here is the error in full format:
PHP Fatal Error – yii\base\ErrorException
Class 'app\models\' not found
1. in /var/www/u0598324/public_html/webstels.com/models/ShopPromoItem.php at line 40
return [
'status' => 'Статус',
];
}
public static function get($id)
{
$item = ShopPromoItem::findOne($id);
$class = 'app\\models\\' . $item->class;
return $class::findOne($id);
}
public function getTitle()
{
return Html::encode($this->title);
}
public function getPriceArray()
{
2. yii\base\ErrorHandler::handleFatalError()
$_GET = [
'username' => 'swallowsveta1997',
];
$_POST = [
'_csrf' => '2dWdOMdf_z2HrgmbtpnKKN1f-mQnpLEkeqpEkFg8zj6OoOR-sAa2DrOcQ-GG7otyuxSIXEzn6R0M5jX5Cw2cVw==',
'ShopPromoItemBuyForm' => [
'name' => 'name',
'item_id' => '1',
],
];
$_COOKIE = [
'_identity' => 'd669e918ca5f102ab0802a521e1d3fc241689f04dbb51253b7b8ab7b54713c5ca:2:{i:0;s:9:"_identity";i:1;s:50:"[22727,"gkEvlaqhpnAtz8mz4v9Fk96QOpkIrssI",2592000]";}',
'PHPSESSID' => 'abe468adef98b859d2100b97cb6da127',
'_csrf' => '542d3bc58acd73dd28aadc1e388c74c2697098a4c8d8bb4b855417ada2ebe4ffa:2:{i:0;s:5:"_csrf";i:1;s:32:"WuyFwYI342Jz0wAZfKr8kCX9vLqiS1Ri";}',
];
$_SESSION = [
'__flash' => [],
'__id' => 22727,
'__authKey' => 'gkEvlaqhpnAtz8mz4v9Fk96QOpkIrssI',
'__expire' => 1543857954,
'__captcha/site/captcha' => 'lesafiq',
'__captcha/site/captchacount' => 1,
];
Here is the model ShopPromoItem.php:
<?php
namespace app\models;
use app\helpers\BalanceHelper;
use app\models\User;
use app\models\UserBalance;
use yii\db\ActiveRecord;
use yii\helpers\Html;
use yii\helpers\Json;
class ShopPromoItem extends ActiveRecord
{
const STATUS_ENABLED = 'enabled';
const STATUS_DISABLED = 'disabled';
const STATUS_DELETED = 'deleted';
public static function tableName()
{
return '{{%shop_promo_item}}';
}
public function rules()
{
return [
];
}
public function attributeLabels()
{
return [
'status' => 'Статус',
];
}
public static function get($id)
{
$item = ShopPromoItem::findOne($id);
$class = '#app/models/' . $item->class;
return $class::findOne($id);
}
public function getTitle()
{
return Html::encode($this->title);
}
public function getPriceArray()
{
return Json::decode($this->price);
}
public function getPriceString()
{
$prices = $this->getPriceArray();
$result = '';
foreach ($prices as $currency => $price) {
$result .= '<img src="/images/' . $currency . '.png" style="vertical-align: middle; width: 24px;"> ' . BalanceHelper::convertToDigits($price);
}
return $result;
}
public function giveTo(User $user)
{
}
}
Here is ShopPromoItemBuyForm.php:
<?php
namespace app\models\forms;
use app\helpers\BalanceHelper;
use app\helpers\RefererHelper;
use app\helpers\SettingHelper;
use app\models\ShopPromoItem;
use app\models\User;
use app\models\UserPromo;
use app\models\UserBalance;
use app\models\UserOperation;
use yii\validators\IpValidator;
class ShopPromoItemBuyForm extends UserPromo
{
public $item_id;
public function rules()
{
return [
['item_id', 'required'],
['item_id', 'integer'],
['item_id', 'exist',
'targetClass' => '\app\models\ShopPromoItem',
'targetAttribute' => 'id',
'filter' => ['status' => ShopPromoItem::STATUS_ENABLED]
],
['name', 'multProtect']
];
}
public function scenarios()
{
return [
self::SCENARIO_DEFAULT => ['name']
];
}
public function multProtect()
{
return;
// disable for debug mode
if (YII_DEBUG)
return;
// check evercookie
if (isset($_COOKIE['was_promo']) && $_COOKIE['was_promo'] == "true") {
$this->addError('name', \Yii::t('app', 'Вы уже заказывали сайт с таким названием на проекте, повторный заказ сайта с таким именем запрещён'));
}
$validator = new IpValidator();
if ($validator->validate(\Yii::$app->request->userPromoIP)) {
$ip = \Yii::$app->request->userPromoIP;
$userPromo = UserPromo::find()->where(['id' => $ip])->limit(1)->one();
if ($userPromo !== null) {
$this->addError('name', \Yii::t('app', 'Вы уже заказывали сайт с таким названием на проекте, повторный заказ сайта с таким именем запрещён'));
}
} else {
$this->addError('name', \Yii::t('app', 'Вы уже заказывали сайт с таким названием на проекте, повторный заказ сайта с таким именем запрещён'));
}
}
public function buy(User $user)
{
if (!$this->validate()) {
\Yii::$app->getSession()->setFlash('warning', implode('<br />', $this->getFirstErrors()));
return false;
}
if (\Yii::$app->mutex->acquire('balance_' . $user->id)) {
\Yii::$app->db->transaction(function() use ($user) {
$item = ShopPromoItem::get($this->item_id);
$prices = $item->getPriceArray();
// check balance
foreach ($prices as $currency => $price) {
if (!$user->balance->has($currency, BalanceHelper::convertToDigits($price))) {
\Yii::$app->getSession()->setFlash('warning', \Yii::t('app', 'Недостаточно средств на балансе'));
return false;
}
}
// decrease balance
foreach ($prices as $currency => $price) {
$user->balance->decrease($currency, BalanceHelper::convertToDigits($price));
$user->operation->create(UserOperation::OPERATION_SHOP_PROMO_BUY, $currency, BalanceHelper::convertToDigits($price), [
'ShopPromoItem_id' => $this->item_id
]);
}
$item->giveTo($user);
// give reward to referer
RefererHelper::giveReward($user, UserBalance::CURRENCY_USD, BalanceHelper::convertToDigits($prices['usd']));
$message = '';
foreach ($prices as $currency => $price) {
$message .= \Yii::t('app', '{sum} долларов', ['sum' => BalanceHelper::convertToDigits($price)]);
}
\Yii::$app->getSession()->setFlash('success', \Yii::t('app', 'Вы купили «{title}»', ['title' => \Yii::t('app', $item->getTitle())]) .
'<br />' . \Yii::t('app', 'Потрачено {price}', ['price' => $message]));
return true;
});
}
}
}
UserPromo.php:
<?php
namespace app\models;
use yii\db\ActiveRecord;
use yii\helpers\Html;
class UserPromo extends ActiveRecord
{
const STATUS_ENABLED = 'enabled';
const STATUS_DISABLED = 'disabled';
const STATUS_DELETED = 'deleted';
public static function tableName()
{
return '{{%user_promo}}';
}
public function rules()
{
return [
['id', 'exist'],
['user_id', 'integer'],
['name', 'required'],
['name', 'filter', 'filter' => 'trim'],
['name', 'match', 'pattern' => '#^[\w_-]+$#i'],
['name', 'unique', 'targetClass' => self::className(), 'message' => \Yii::t('app', 'Указанное название для вашего сайта уже занято')],
['name', 'string', 'min' => 2, 'max' => 255],
];
}
public function attributeLabels()
{
return [
'status' => 'Статус',
'name' => \Yii::t('app', 'Название'),
];
}
public static function findIdentity($id)
{
$identity = static::findOne(['id' => $id]);
return $identity;
}
public static function findByName($name)
{
return static::findOne(['name' => $name]);
}
public function getName()
{
return Html::encode($this->name);
}
public function getPromo()
{
return $this->hasOne(Promo::className(), ['id' => 'promo_id']);
}
public function getUser()
{
return $this->hasOne(User::className(), ['id' => 'user_id']);
}
public function getTitle()
{
return $this->promo->getTitle();
}
public function getType()
{
return $this->promo->getType();
}
public function getProfit($type)
{
return $this->promo->{$type . '_profit'};
}
}
PromoSiteShopItem.php:
<?php
namespace app\models;
use app\helpers\BalanceHelper;
use app\helpers\SettingHelper;
class PromoSiteShopItem extends ShopPromoItem
{
public function giveTo(User $user)
{
(new UserPromo([
'user_id' => $user->id,
'promo_id' => 21,
'created_at' => time(),
'status' => UserPromo::STATUS_ENABLED
]))->save(false);
$prices = $this->getPriceArray();
// increase reserve
$value = SettingHelper::get('reserve.promo.sum') + intval(BalanceHelper::convertToDigits($prices['usd']) / 100 * 50);
SettingHelper::set('reserve.promo.sum', $value);
}
}
Promo.php:
<?php
namespace app\models;
use yii\db\ActiveRecord;
use yii\helpers\Html;
class Promo extends ActiveRecord
{
const TYPE_PROMO = 'promo';
const STATUS_ENABLED = 'enabled';
const STATUS_DISABLED = 'disabled';
const STATUS_DELETED = 'deleted';
public static function tableName()
{
return '{{%promo}}';
}
public function rules()
{
return [
['user_id', 'integer'],
];
}
public function attributeLabels()
{
return [
'status' => 'Статус',
];
}
public function getType()
{
return $this->type;
}
public function getTitle()
{
return Html::encode($this->title);
}
}
Controller:
<?php
namespace app\controllers\user\main\services;
use app\components\Controller;
use app\models\ShopPromoItem;
use app\models\forms\ShopPromoItemBuyForm;
use yii\filters\AccessControl;
use yii\web\ForbiddenHttpException;
use yii\filters\VerbFilter;
use yii\helpers\Url;
use app\models\UserPromo;
class PromoController extends Controller
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'allow' => true,
'roles' => ['#'],
],
],
],
];
}
public function beforeAction($action)
{
if (\Yii::$app->params['user']['promo']['temporaryDisabled']) {
throw new ForbiddenHttpException('Заказ временно приостановлен');
}
return parent::beforeAction($action);
}
public function actionIndex()
{
$this->layout = 'page';
$items = ShopPromoItem::find()->where([
'status' => ShopPromoItem::STATUS_ENABLED
])->all();
$model = new ShopPromoItemBuyForm();
if ($model->load(\Yii::$app->request->post())) {
$model->buy(\Yii::$app->user->identity);
}
$promo = UserPromo::find()->where([
'user_id' => \Yii::$app->user->identity->id,
'status' => UserPromo::STATUS_ENABLED
])->with('promo')->orderBy('promo_id DESC')->all();
return $this->render('index', [
'items' => $items,
'model' => $model,
'promo' => $promo,
]);
}
}
I am getting model object 3 times (Yii2) to load view controller. This makes my page to load slow. How to reduce it?
public function behaviors()
{
return [
'httpCache' => [
'class' => 'yii\filters\HttpCache',
'only' => ['view'],
'lastModified' => function ($action, $params) {
$post = $this->findModel(Yii::$app->request->get('id'));
return strtotime($post->updated);
},
'etagSeed' => function ($action, $params) {
$post = $this->findModel(Yii::$app->request->get('id'));
return serialize([$post->updated, $post->views, $post->comments, Yii::$app->user->isGuest ? 0 : 1]);
}
],
];
}
public function actionView($id)
{
$model = $this->findModel($id);
return $this->render('view', [
'model' => $model,
]);
}
You can cache model instance at controller level:
private $_models = [];
protected function findModel($id) {
if (!array_key_exists($id, $this->_models)) {
$this->_models[$id] = MyModel::findOne($id);
if ($this->_models[$id] === null) {
$this->notFound();
}
}
return $this->_models[$id];
}
Only first call of findModel() will query DB, next calls will return already instantiated object.
I have a REST API endpoint that i use to get a user logged in and retrieve informations about his account.
That implementation was running fine...but now it's broken.
I am using basicauth override to use USERNAME:PASSWORD instead of the token
Below controller and MODEL code
Into the response i find now all the users...instead of one
can't understand as in the first place we use findOne to select ONE user and THEN password is checked.
Maybe i missed something here :/
USER MODEL :
<?php
namespace common\models;
use yii\base\NotSupportedException;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
class User extends ActiveRecord implements IdentityInterface
{
public static function tableName()
{
return '{{%user}}';
}
public function behaviors()
{
return [
TimestampBehavior::className(),
];
}
public function rules()
{
return [
[['username', 'auth_key', 'password_hash', 'email'], 'required'],
[['status', 'created_at', 'updated_at', 'background'], 'integer'],
[['username', 'password_hash', 'password_reset_token', 'email', 'hmac_shopify', 'shop_address', 'room_id', 'wp_address', 'blog_address', 'iosRegisterID', 'androidRegisterID', 'timeZone'], 'string', 'max' => 255],
[['auth_key'], 'string', 'max' => 32],
[['account_level'], 'string', 'max' => 45],
[['username'], 'unique'],
[['email'], 'unique'],
[['password_reset_token'], 'unique'],
];
}
public static function findIdentity($id)
{
return static::findOne(['id' => $id]);
}
public static function findIdentityByAccessToken($token, $type = null)
{
return static::findOne(['auth_key' => $token]);
}
public static function findByUsername($username)
{
return static::findOne(['username' => $username]);
}
public static function findByPasswordResetToken($token)
{
if (!static::isPasswordResetTokenValid($token)) {
return null;
}
return static::findOne([
'password_reset_token' => $token,
'status' => self::STATUS_ACTIVE,
]);
}
public static function isPasswordResetTokenValid($token)
{
if (empty($token)) {
return false;
}
$timestamp = (int) substr($token, strrpos($token, '_') + 1);
$expire = Yii::$app->params['user.passwordResetTokenExpire'];
return $timestamp + $expire >= time();
}
public function getId()
{
return $this->getPrimaryKey();
}
public function getAuthKey()
{
return $this->auth_key;
return $this->hmac_shopify;
}
public function validateAuthKey($authKey)
{
return $this->getAuthKey() === $authKey;
}
public function validatePassword($password)
{
return Yii::$app->security->validatePassword($password, $this->password_hash);
}
public function setPassword($password)
{
$this->password_hash = Yii::$app->security->generatePasswordHash($password);
}
public function generateAuthKey()
{
$this->auth_key = Yii::$app->security->generateRandomString();
$this->room_id = "_r_".Yii::$app->security->generateRandomString();
}
public function generatePasswordResetToken()
{
$this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();
}
public function removePasswordResetToken()
{
$this->password_reset_token = null;
}
public static function find()
{
return new UserQuery(get_called_class());
}
}
This is controller :
<?php
namespace api\controllers;
use yii;
use yii\rest\ActiveController;
use \common\models\User;
class RestController extends ActiveController
{
public $modelClass = '\common\models\User';
public $password_hash;
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['verbs'] = [
'class' => \yii\filters\VerbFilter::className(),
'actions' => [
'index' => ['get', 'head'],
],
];
$behaviors['access'] = [
'class' => \yii\filters\AccessControl::className(),
'only' => ['index'],
'rules' => [
[
'actions' => ['index'],
'allow' => true,
'roles' => ['#'],
],
],
];
$behaviors['authenticator'] = [
'class' => \yii\filters\auth\HttpBasicAuth::className(),
'auth' => function ($username, $password) {
$user = \common\models\User::findByUsername($username);
if ($user ) {
$password_valid = \common\models\User::validatePassword($password,$user->password_hash);
if($password_valid)
return $user;
}
}
];
return $behaviors;
}
}
Data response from REST AUTH
<pre>
<response>
<item>...</item>
<item>...</item>
<item>...</item>
<item>...</item>
<item>...</item>
<item>...</item>
<item>...</item>
</response>
</pre>
That was def. the default behavior, i had to edit the prepareDataProvider function in in \yii2\rest\indexAction.php
I try to save multilanguaged content in model. I have two models
PostLang
class PostLang extends \yii\db\ActiveRecord
{
public static function tableName()
{
return 'postlang';
}
public function rules()
{
return [
[['post_id', 'lang_id', 'title', 'content'], 'safe'],
[['post_id', 'lang_id'], 'integer'],
[['title', 'content'], 'string'],
[['post_id'], 'exist', 'skipOnError' => true, 'targetClass' => Post::className(), 'targetAttribute' => ['post_id' => 'id']],
];
}
...
public function getPost()
{
return $this->hasOne(Post::className(), ['id' => 'post_id']);
}
}
and Post
class Post extends \yii\db\ActiveRecord {
public static function tableName() {
return 'post';
}
public function behaviors() {
return [
'timestamp' => [
'class' => 'yii\behaviors\TimestampBehavior',
'attributes' => [
\yii\db\ActiveRecord::EVENT_BEFORE_INSERT => ['date_create', 'date_update'],
\yii\db\ActiveRecord::EVENT_BEFORE_UPDATE => ['date_update'],
],
],
];
}
public function rules() {
return [
[['status', 'date_update', 'date_create'], 'integer'],
[['date_update', 'date_create'], 'safe'],
];
}
...
public function getPostlangs() {
return $this->hasMany(Postlang::className(), ['post_id' => 'id']);
}
}
i created a PostController with create method
public function actionCreate() {
$model = new Post();
$post_ru = new PostLang();
$post_en = new PostLang();
if ($model->load(Yii::$app->request->post())) {
if ($model->save()) {
$dbPost = new PostLang();
$dbPost->title = need to save title;
$dbPost->content = need to save content;
$dbPost->lang_id = need to save lang_id;
$dbPost->post_id = $model->id;
$dbPost->save();
}
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
I need to save it in foreach but i don't understand how can i do it.
Form
...
<?= $form->field($post_ru, 'title')->textInput() ?>
<?= $form->field($post_ru, 'content')->textInput() ?>
<?= $form->field($post_en, 'title')->textInput() ?>
<?= $form->field($post_en, 'content')->textInput() ?>
...
You should separate models in your activeForm,because only last model will save.
Form:
<?= $form->field($post_ru, "[0]title")->textInput() ?>
<?= $form->field($post_ru, "[0]content")->textInput() ?>
<?= $form->field($post_en, "[1]title")->textInput() ?>
<?= $form->field($post_en, "[1]content")->textInput() ?>
Controller:
public function actionCreate()
{
$model = new Post();
$post_ru = new PostLang();
$post_en = new PostLang();
$postData = Yii::$app->request->post('PostLang');
if ($model->load(Yii::$app->request->post())) {
if ($model->save()) {
$post_ru->load($postData[0]);
$post_en->load($postData[1]);
if ($post_ru->save()) {
$post_ru->link('post', $model);
}
if ($post_en->save()) {
$post_en->link('post', $model);
}
}
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
Don`t forget to +rep,if it was useful.
I get an error while using getAttributes method : "Call to a member function getAttributes() on a non-object".
Now, In my Controller:
$notifications = Notifications::return_new()->getAttributes();
var_dump($notifications);
In model
public static function return_new(){
return Notifications::find()->where(['is_seen' => 0])->all();
}
Now, the Yii docs say that getAttribute() takes an array as a parameter, so I've tried
$notifications = Notifications::return_new()->getAttributes('text');
but it still persists with the same error. Any help?
Here is the model
<?php
namespace frontend\models;
use Yii;
*/
class Notifications extends \yii\db\ActiveRecord
{
public static function tableName()
{
return 'notifications';
}
public function rules()
{
return [
[['created_on', 'user_id', 'text'], 'required'],
[['user_id'], 'integer'],
[['created_on'], 'safe'],
[['text'], 'string', 'max' => 255]
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'created_on' => 'Created On',
'user_id' => 'User ID',
'text' => 'Text',
];
}
public static function count_new()
{
$new = Notifications::find()->where(['is_seen' => 0])->all();
return count($new);
}
public static function return_new(){
return Notifications::find()->where(['is_seen' => 0])->all();
}
public function return_all(){
return Notifications::find()->all();
}
public static function checkst(){
return Notifications::find()->where(['id' => 3])->one();
}
public function return_by_date () {
// write something here.
}
}
If you use all() you obtain a collection of models and then you should refere to
Notifications::return_new()[0]->getAttributes();
otherwise you can
public static function return_new(){
return Notifications::find()->where(['is_seen' => 0])->one();
}
and in this case you can use
$notifications = Notifications::return_new()->getAttributes();