Hello! I am searching about how to work with related models. The docs have a method link(). My code works fine but i don’t know if the correct way.
public function actionCreate()
{
$model = new Aplicacao();
$relatedModel = new AplicacaoGoalProfileGoogleAnalytics();
$adsenseModel = new AplicacaoGoalProfileGoogleAdsense();
if ($model->loadAndSave(Yii::$app->request->post())){
$relatedModel->load(Yii::$app->request->post());
$adsenseModel->load(Yii::$app->request->post());
$model->link('aplicacaoGoalProfileGoogleAnalytics', $relatedModel);
$model->link('aplicacaoGoalProfileGoogleAdsense', $adsenseModel);
Yii::$app->session->setFlash('success',Yii::t('app', 'Saved successfully!'));
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('create', [
'model' => $model,
'relatedModel' => $relatedModel,
'adsenseModel' => $adsenseModel
]);
}
}
public function actionUpdate($id)
{
$model = $this->findModel($id);
$relatedModel = AplicacaoGoalProfileGoogleAnalytics::find()->where('id_aplicacao = :id', ['id'=> $model->id])->one();
$adsenseModel = AplicacaoGoalProfileGoogleAdsense::find()->where('id_aplicacao = :id', ['id'=> $model->id])->one();
if(!$relatedModel){
$relatedModel = new AplicacaoGoalProfileGoogleAnalytics();
}
if(!$adsenseModel){
$adsenseModel = new AplicacaoGoalProfileGoogleAdsense();
}
if ($model->loadAndSave(Yii::$app->request->post())) {
$relatedModel->load(Yii::$app->request->post());
$adsenseModel->load(Yii::$app->request->post());
$model->link('aplicacaoGoalProfileGoogleAnalytics', $relatedModel);
$model->link('aplicacaoGoalProfileGoogleAdsense', $adsenseModel);
Yii::$app->session->setFlash('success',Yii::t('app', 'Updated successfully!'));
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('update', [
'model' => $model,
'relatedModel' => $relatedModel,
'adsenseModel' => $adsenseModel
]);
}
}
I can improve my code?
softark
(Softark)
November 13, 2015, 10:45pm
2
Have you read this section of the guide?
http://www.yiiframework.com/doc-2.0/guide-input-multiple-models.html
And you should note that link() doesn’t validate the values of the related models. The API doc says:
I would write like this:
public function actionCreate()
{
$model = new Aplicacao();
$relatedModel = new AplicacaoGoalProfileGoogleAnalytics();
$adsenseModel = new AplicacaoGoalProfileGoogleAdsense();
if ($model->load(Yii::$app->request->post()) &&
$relatedModel->load(Yii::$app->request->post()) &&
$absenseModel->load(Yii::$app->request->post())){
$isValid = $model->validate();
$isValid = $relatedModel->validate() && $isValid;
$isValid = $absenseModel->validate() && $isValid;
if ($isValid) {
$model->save(false);
$relatedModel->id_aplicacao = $model->id;
$relatedModel->save(false);
// or using link()
// $model->link('aplicacaoGoalProfileGoogleAnalytics', $relatedModel);
$absenseModel->id_aplicacao = $model->id;
$absenseModel->save(false);
// or using link()
// $model->link('aplicacaoGoalProfileGoogleAdsense', $adsenseModel);
Yii::$app->session->setFlash('success',Yii::t('app', 'Saved successfully!'));
return $this->redirect(['view', 'id' => $model->id]);
}
}
return $this->render('create', [
'model' => $model,
'relatedModel' => $relatedModel,
'adsenseModel' => $adsenseModel
]);
}
And for update:
public function actionUpdate($id)
{
$model = $this->findModel($id);
$relatedModel = $model->aplicacaoGoalProfileGoogleAnalytics;
if(!$relatedModel){
$relatedModel = new AplicacaoGoalProfileGoogleAnalytics();
}
$adsenseModel = $model->aplicacaoGoalProfileGoogleAdsense;
if(!$adsenseModel){
$adsenseModel = new AplicacaoGoalProfileGoogleAdsense();
}
if ($model->load(Yii::$app->request->post()) &&
$relatedModel->load(Yii::$app->request->post()) &&
$absenseModel->load(Yii::$app->request->post())){
$isValid = $model->validate();
$isValid = $relatedModel->validate() && $isValid;
$isValid = $absenseModel->validate() && $isValid;
if ($isValid) {
$model->save(false);
$relatedModel->id_aplicacao = $model->id;
$relatedModel->save(false);
// or using link()
// $model->link('aplicacaoGoalProfileGoogleAnalytics', $relatedModel);
$absenseModel->id_aplicacao = $model->id;
$absenseModel->save(false);
// or using link()
// $model->link('aplicacaoGoalProfileGoogleAdsense', $adsenseModel);
Yii::$app->session->setFlash('success',Yii::t('app', 'Updated successfully!'));
return $this->redirect(['view', 'id' => $model->id]);
}
}
return $this->render('update', [
'model' => $model,
'relatedModel' => $relatedModel,
'adsenseModel' => $adsenseModel
]);
}
Thanks softark for reply. But i can get the related model?
in model Aplicacao, i have the follow relationship:
/**
* @return \yii\db\ActiveQuery by query model relation
*/
public function getAplicacaoGoalProfileGoogleAnalytics()
{
return $this->hasOne(AplicacaoGoalProfileGoogleAnalytics::className(), ['id_aplicacao' => 'id']);
}
/**
* @return \yii\db\ActiveQuery by query model relation
*/
public function getAplicacaoGoalProfileGoogleAdsense()
{
return $this->hasOne(AplicacaoGoalProfileGoogleAdsense::className(), ['id_aplicacao' => 'id']);
}
And the relation don’t work:
object(backend\modules\aplicacao\models\Aplicacao)[43]
private '_attributes' (yii\db\BaseActiveRecord) =>
array (size=12)
'id' => int 4
'nome' => string 'sococo.com.br' (length=13)
'url' => string 'http://www.sococo.com.br' (length=24)
'url_cms' => string '' (length=0)
'url_webmail' => string '' (length=0)
'codigo_projeto_redmine' => null
'codigo_google_analytics' => string 'UA-2592251-16' (length=13)
'ativo' => int 1
'aplicacao_tipo_id' => int 1
'finlegado_cliente_id' => int 67
'data_proxima_pesquisa' => null
'horas_orcadas' => null
private '_oldAttributes' (yii\db\BaseActiveRecord) =>
array (size=12)
'id' => int 4
'nome' => string 'sococo.com.br' (length=13)
'url' => string 'http://www.sococo.com.br' (length=24)
'url_cms' => string '' (length=0)
'url_webmail' => string '' (length=0)
'codigo_projeto_redmine' => null
'codigo_google_analytics' => string 'UA-2592251-16' (length=13)
'ativo' => int 1
'aplicacao_tipo_id' => int 1
'finlegado_cliente_id' => int 67
'data_proxima_pesquisa' => null
'horas_orcadas' => null
private '_related' (yii\db\BaseActiveRecord) =>
array (size=2)
'aplicacaoGoalProfileGoogleAnalytics' => null
'aplicacaoGoalProfileGoogleAdsense' => null
private '_errors' (yii\base\Model) => null
private '_validators' (yii\base\Model) => null
private '_scenario' (yii\base\Model) => string 'default' (length=7)
private '_events' (yii\base\Component) =>
array (size=0)
empty
private '_behaviors' (yii\base\Component) =>
array (size=0)
empty
returns "null"
softark
(Softark)
November 16, 2015, 12:04pm
4
Where did you var_dump? Just after loading the main model?
$model = $this->findModel($id);
/* here ? */
Or, after having tried to load the related models?
$relatedModel = $model->aplicacaoGoalProfileGoogleAnalytics;
if(!$relatedModel){
$relatedModel = new AplicacaoGoalProfileGoogleAnalytics();
}
$adsenseModel = $model->aplicacaoGoalProfileGoogleAdsense;
if(!$adsenseModel){
$adsenseModel = new AplicacaoGoalProfileGoogleAdsense();
}
/* here ? */
After load model. If i try access $model->aplicacaoGoalProfileGoogleAdsense works, but in var_dump($model) , the section "related" returns NULL:
private '_related' (yii\db\BaseActiveRecord) =>
array (size=2)
'aplicacaoGoalProfileGoogleAnalytics' => null
'aplicacaoGoalProfileGoogleAdsense' => null
This is correct?
softark
(Softark)
November 16, 2015, 1:36pm
6
Yes, it is the expected behavior.
They should be populated with the related models after you have tried to access them via "$model->relatedModel" syntax.
http://www.yiiframework.com/doc-2.0/guide-db-active-record.html#accessing-relational-data
Thank you, softark. A last question about it, please:
I have a custom controller to save/update only the related models ‘aplicacaoGoalProfileGoogleAnalytics’ and ‘aplicacaoGoalProfileGoogleAdsense’. The form is:
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model->aplicacaoGoalProfileGoogleAnalytics, 'user_type_desired')->dropDownList([ 'NEW USER' => 'NEW USER', 'RETURNING USER' => 'RETURNING USER', ], ['prompt' => '']) ?>
<?= $form->field($model->aplicacaoGoalProfileGoogleAnalytics, 'pageviews_month')->textInput() ?>
<?= $form->field($model->aplicacaoGoalProfileGoogleAnalytics, 'users_month')->textInput() ?>
<?= $form->field($model->aplicacaoGoalProfileGoogleAnalytics, 'newusers_month')->textInput() ?>
<?= $form->field($model->aplicacaoGoalProfileGoogleAnalytics, 'session_month')->textInput() ?>
<?= $form->field($model->aplicacaoGoalProfileGoogleAnalytics, 'goals_month')->textInput() ?>
<?= $form->field($model->aplicacaoGoalProfileGoogleAdsense, 'prints_month')->textInput() ?>
<?= $form->field($model->aplicacaoGoalProfileGoogleAdsense, 'crt_month')->textInput() ?>
<div class="form-group">
<?= Html::submitButton('Update', ['class' => 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>
and update:
public function actionUpdate($id)
{
$model = Aplicacao::findOne($id);
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('update', [
'model' => $model,
]);
}
}
The return of Yii::$app->request->post() :
array (size=3)
'_csrf' => string 'V1o1YW1pZzdiGWAMNSIOThULBD43WlJ6ZxFCNFkQLk0CHAAKDhEsUA==' (length=56)
'AplicacaoGoalProfileGoogleAnalytics' =>
array (size=6)
'user_type_desired' => string 'NEW USER' (length=<img src='http://www.yiiframework.com/forum/public/style_emoticons/default/cool.gif' class='bbc_emoticon' alt='8)' />
'pageviews_month' => string '1312312' (length=7)
'users_month' => string '12312312' (length=<img src='http://www.yiiframework.com/forum/public/style_emoticons/default/cool.gif' class='bbc_emoticon' alt='8)' />
'newusers_month' => string '11231231' (length=<img src='http://www.yiiframework.com/forum/public/style_emoticons/default/cool.gif' class='bbc_emoticon' alt='8)' />
'session_month' => string '2147483647' (length=10)
'goals_month' => string '1913232' (length=7)
'AplicacaoGoalProfileGoogleAdsense' =>
array (size=2)
'prints_month' => string '9321123' (length=7)
'crt_month' => string '9213' (length=4)
but $model doens’t save. The load method returns false.
Whats is going wrong?
softark
(Softark)
November 16, 2015, 2:57pm
8
public function actionUpdate($id)
{
$model = Aplicacao::findOne($id);
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('update', [
'model' => $model,
]);
}
}
In the above, $model is an instance of Aplicacao, and it tries to load its attributes from post.
It should fail because the post only has AplicacaoGoalProfileGoogleAnalytics and AplicacaoGoalProfileGoogleAdsense. And the related models are not loaded automatically.
Also, even if the loading had been successful, saving of a model won’t save its related models automatically.
You have to load and save one by one to save the related models.
Thank you! It’s works like a charm! But, i try update the older register in database, when not have values in these related models, i get a error:
Call to a member function formName() on null
public function actionUpdate()
{
$model = Yii::$app->session->get('user.application');
$analyticsModel = $model->aplicacaoGoalProfileGoogleAnalytics;
if(!$analyticsModel){
$analyticsModel = new AplicacaoGoalProfileGoogleAnalytics();
}
$adsenseModel = $model->aplicacaoGoalProfileGoogleAdsense;
if(!$adsenseModel){
$adsenseModel = new AplicacaoGoalProfileGoogleAdsense();
}
if ($analyticsModel->load(Yii::$app->request->post()) &&
$adsenseModel->load(Yii::$app->request->post())){
$isValid = $analyticsModel->validate();
$isValid = $adsenseModel->validate() && $isValid;
if ($isValid) {
$model->save(false);
$analyticsModel->id_aplicacao = $model->id;
$analyticsModel->save(false);
$adsenseModel->id_aplicacao = $model->id;
$adsenseModel->save(false);
return $this->redirect(['view', 'id' => $model->id]);
}
} else {
return $this->render('update', [
'model' => $model
]);
}
}
I changed to:
public function actionUpdate()
{
$model = Yii::$app->session->get('user.application');
$analyticsModel = $model->aplicacaoGoalProfileGoogleAnalytics;
if(!$analyticsModel){
$analyticsModel = new AplicacaoGoalProfileGoogleAnalytics();
$analyticsModel->id_aplicacao = $model->id;
}
$adsenseModel = $model->aplicacaoGoalProfileGoogleAdsense;
if(!$adsenseModel){
$adsenseModel = new AplicacaoGoalProfileGoogleAdsense();
$adsenseModel->id_aplicacao = $model->id;
}
if ($analyticsModel->load(Yii::$app->request->post()) &&
$adsenseModel->load(Yii::$app->request->post())
){
$isValid = $analyticsModel->validate();
$isValid = $adsenseModel->validate() && $isValid;
if ($isValid) {
$model->save(false);
$analyticsModel->save(false);
$adsenseModel->save(false);
Yii::$app->session->set('user.application', $model);
return $this->redirect(['view', 'id' => $model->id]);
}
} else {
return $this->render('update', [
'model' => $model,
'analyticsModel' => $analyticsModel,
'adsenseModel' => $adsenseModel
]);
}
}
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($analyticsModel, 'user_type_desired')->dropDownList([ 'NEW USER' => 'NEW USER', 'RETURNING USER' => 'RETURNING USER', ], ['prompt' => '']) ?>
<?= $form->field($analyticsModel, 'pageviews_month')->textInput() ?>
<?= $form->field($analyticsModel, 'users_month')->textInput() ?>
<?= $form->field($analyticsModel, 'newusers_month')->textInput() ?>
<?= $form->field($analyticsModel, 'session_month')->textInput() ?>
<?= $form->field($analyticsModel, 'goals_month')->textInput() ?>
<?= $form->field($adsenseModel, 'prints_month')->textInput() ?>
<?= $form->field($adsenseModel, 'crt_month')->textInput() ?>
<div class="form-group">
<?= Html::submitButton('Update', ['class' => 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>
and works fine
softark
(Softark)
November 16, 2015, 10:31pm
11
You don’t need to save the main model, because your form deals only with the related models.
But, why do you want to store the main model in session?
In frontend, i get some data from backend and store in session.