Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Пошаговое начальство сохранения связанных данных Yii

Anna | 31.05.2014 | нет комментариев

С недавних пор, я начал постигать восхитительный фрэймворк Yii. При разработке, я столкнулся с задачей сохранения данных из одной формы, в несколько таблиц. Погуглив, я не обнаружил приписываемого начальство, которое поясняет полный толк этого сохранения. На официальном, русскоязычном сайте, я обнаружил короткую статью от Александра Макарова, но она, вновь же в всеобщих чертах показывает «соль» этого способа.
Я решил написать эту статью, в жанре tutorial, Дабы дать новичкам вероятность наглядно увидеть полный цикл CRUD при работе с несколькими моделями, а тем кто по-опытней, покритиковать это решение, и объяснить «как делать не нужно».

Постановка задачи

Нужно сделать две таблицы, для хранения данных о пользователе. Одна именуется user — предуготовлена для хранения логина и пароля пользователя, его ранга и его глобального идентификатора, тот, что будет применяться во каждой системе. Вторая user_profile которая предуготовлена для хранения публичных данных о пользователе, его имени и фамилии и т.п. Таблица профиля связана с таблицей пользователей, при помощи внешнего ключа.
Нужно сберегать и редактировать данные о пользователя, из одной цельной формы, которая включает в себя поля как таблицы user так и user_profile

Создание таблиц БД

Сотворим две таблицы такого вида
user — родительская таблица, где создаётся id пользователя
user_profile — дочерняя таблица, имеет внешний ключ user_id на родительскую таблицу

Создание моделей

При помощи генератора кода gii, сотворим модели этих таблиц и назовем их соответственно User и UserProfile.
Так же при помощи gii сотворим CRUD для модели User (подмечу, что для модели UserProfile, я специально не создаю CRUD, так как он нам не потребоваться)

Доработка родительской модели

В родительскую модель, нам нужно добавить поля из дочерней модели:

<?php
class User extends CActiveRecord
{       
////добавление начато
       public $name; 
       public $first_name;
       public $description;
////добавление окончено
...
public function attributeLabels()
{
		return array(
			'id' => 'ID',
			'login' => 'Login',
			'password' => 'Password',
 			'status' => 'Status',
////добавление начато
                        'name'=>'Имя',
                        'first_name'=>'Фамилия',
                        'description'=>'Изложение'
////добавление окончено
		);
	}

А также определить способ AfterSave добавив код:

////добавление начато
 protected function afterSave() {
            parent::afterSave();
            if($this->isNewRecord){  
    	  // если мы создаем нового пользователя, тогда нам нужно сделать 
          // для него запись в таблице профиля с ссылкой на родительскую таблицу
             $user_profile = new UserProfile;
             $user_profile->user_id =     $this->id;
             $user_profile->name =        $this->name;
             $user_profile->first_name =  $this->first_name;
             $user_profile->description = $this->description;
             $user_profile->save();
            } else {
 	// напротив неободимо обновить данные в таблице профиля
             UserProfile::model()->updateAll(array( 'user_id' =>$this->id, 
                                                'name' => $this->name,    
                                                'first_name'=>$this->first_name,
                                                'description'=>$this->description
                    ), 'user_id=:user_id', array(':user_id'=> $this->id));
            }
        }
////добавление окончено

Сейчас по шагам, что здесь случилось:
1) добавили три публичные переменные, которые соответствуют полям модели UserProfile,
сейчас это новые поля в модели User

       public $name; 
       public $first_name;
       public $description;

2) в способе attributeLabels(), создаем изложения для новых полей

          'name'=>'Имя',
          'first_name'=>'Фамилия',
          'description'=>'Изложение'

3) Сейчас создаем способ afterSave, тот, что срабатывает позже сохранения данных в модели User,
и в здесь же будем сберегать данные в UserProfile.

Таким образом, мы проверяем, что теперь происходит: создание новой записи либо редактирование присутствующей.

  if($this->isNewRecord){  

Если создался новейший пользователь, то:

  • Создаю экземпляр модели UserProfile
  • Получаем ID сделанного пользователя, и присваиваем это значение полю
    $user_profile->user_id = $this->id;
  • Присваиваю полям модели UserProfile, значения пришедшие из формы (то как мы получаем эти данные из формы, глядим действие actionCreate в котнтроллере UserController)
  • Исполняем способ save() у модели UserProfile

Если это была операция редактирования, то:

  • нужно исполнить способ updateAll для модели UserProfile

 

UserProfile::model()->updateAll(array( 'user_id' =>$this->id, 
                                                'name' => $this->name,    
                                                'first_name'=>$this->first_name,
                                                'description'=>$this->description
                    ), 'user_id=:user_id', array(':user_id'=> $this->id));

Тут значения заполняются из действия actionUpdate контроллера UserController

Доработка контроллера

Сейчас открываем свеже-сгенирированный контроллер UserController.
В нём, нам предстоит исправить два действия actionCreate и actionUpdate,
и одну функцию loadModel

actionCreate

Присваиваем значения, публичным переменным, которые мы добавили в модели.
Вот отсель применяются данные, в способе afterSave

public function actionCreate()
	{
 	$model=new User;
   	   if(isset($_POST['User']))
		{       
			$model->attributes=$_POST['User'];
////добавление начато
                        $model->name = $_POST['User']['name'];
                        $model->first_name = $_POST['User']['first_name'];
                        $model->description = $_POST['User']['description'];
////добавление оконченно
			if($model->save())
				$this->redirect(array('view','id'=>$model->id));
		}
		$this->render('create',array(
			'model'=>$model,
		));
	}
actionUpdate

Тут, происходит подобный процесс, что и при создании пользователя

	public function actionUpdate($id)
	{
		$model=$this->loadModel($id);
    	      if(isset($_POST['User']))
		{
			$model->attributes=$_POST['User'];
////добавление начато
                        $model->name = $_POST['User']['name'];
                        $model->first_name = $_POST['User']['first_name'];
                        $model->description = $_POST['User']['description'];
////добавление оконченно			if($model->save())
				$this->redirect(array('view','id'=>$model->id));
		}

		$this->render('update',array(
			'model'=>$model,
		));
	}
loadModel

Здесь мы добавляем такие строки.
Нам нужно загрузить данные из таблицы профиля пользователя, обнаруженные по его user_id.

	public function loadModel($id)
	{
		$model=User::model()->findByPk($id);
////добавление начато
$modelprofile=UserProfile::model()->find('user_id=:user_id', array(':user_id'=> $id));
                $model->name =  $modelprofile->name;
                $model->first_name = $modelprofile->first_name;
                $model->description = $modelprofile->description;
////добавление оконченно
		if($model===null)
			throw new CHttpException(404,'The requested page does not exist.');
		return $model;
	}

Это нужно для того, Дабы данные загружались в форму, когда мы нажимаем на ссылку Update User,
и для отображении информации в просмотровом представлении

Доработка родительской формы

В форме, которая находиться по адресу protected/views/user/_form.php 
нам нужно добавить элементы для ввода имени, фамилии и изложения пользователя

<?php
<div>
<?php $form=$this->beginWidget('CActiveForm', array(
	'id'=>'user-form',
	'enableAjaxValidation'=>false,
)); ?>
	<p>Fields with <span>*</span> are required.</p>
	<?php echo $form->errorSummary($model); ?>
	<div>
		<?php echo $form->labelEx($model,'login'); ?>
		<?php echo $form->textField($model,'login',array('size'=>45,'maxlength'=>45)); ?>
		<?php echo $form->error($model,'login'); ?>
	</div>
.....
////добавление начато
        <div>
		<?php echo $form->labelEx($model,'name'); ?>
		<?php echo $form->textField($model,'name',array('size'=>45,'maxlength'=>45)); ?>
		<?php echo $form->error($model,'name'); ?>
	</div>
       	<div>
		<?php echo $form->labelEx($model,'first_name'); ?>
		<?php echo $form->textField($model,'first_name',array('size'=>45,'maxlength'=>45)); ?>
		<?php echo $form->error($model,'first_name'); ?>
	</div>
	<div>
		<?php echo $form->labelEx($model,'description'); ?>
		<?php echo $form->textField($model,'description',array('size'=>45,'maxlength'=>45)); ?>
		<?php echo $form->error($model,'description'); ?>
	</div>
////добавление оконченно        
	<div>
		<?php echo CHtml::submitButton($model->isNewRecord ? 'Create' : 'Save'); ?>
	</div>
<?php $this->endWidget(); ?>
</div><!-- form -->

Доработка представления

Файл представления, тот, что находиться по адресу protected/views/user/view.php, мы, так же добаляем наши новые поля в виджет детального отображения


<?php

....
<?php $this->widget('zii.widgets.CDetailView', array(
	'data'=>$model,
	'attributes'=>array(
		'id',
		'login',
		'password',
		'status',
////добавление начато
                'name',
                'first_name',
                'description'
////добавление оконченно        
	),
)); ?>

а во вспомогательном файле protected/views/user/_view.php добавим следующее:

<?php
/* @var $this UserController */
/* @var $data User */
?>

<div>
	<b><?php echo CHtml::encode($data->getAttributeLabel('id')); ?>:</b>
	<?php echo CHtml::link(CHtml::encode($data->id), array('view', 'id'=>$data->id)); ?>
	<br />
...
////добавление начато
 <b><?php echo CHtml::encode($data->getAttributeLabel('name')); ?>:</b>
	<?php echo CHtml::encode($data->name); ?>
	<br />
        <b><?php echo CHtml::encode($data->getAttributeLabel('first_name')); ?>:</b>
	<?php echo CHtml::encode($data->first_name); ?>
	<br />
        <b><?php echo CHtml::encode($data->getAttributeLabel('descrption')); ?>:</b>
	<?php echo CHtml::encode($data->descrption); ?>
<br />
////добавление оконченно        
</div>

Проверка итога

Сейчас, если всё сделанно как описанно выше, переходим по адресу
localhost/YourProjectName/index.php?r=user/create

Заполняем все поля, и нажимаем Create.
Позже чего, обязаны увидеть такой итог:

Если мы хотим редактировать эту запись, нажимаем на ссылку Update User,
наша форма заполнится данными

Outro

Я верю, что статья будет пригодна начинающим разработчикам, и сэкономит время при поиске аналогичного решения.
Принимается любая конструктивная критика, опытных разработчиков, сдобренная личными примерами.

Спасибо за внимание!

Применяемая письменность

Статья из раздела рецепты “Сохранение связанных данных“.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB