прежде всего прошу прощения за любую ошибку в письме
Хорошо, позвольте мне объяснить
У меня есть 3 модели: музыкальная модель, модель MusicLink и модель MusicGenre. В MusicController у меня есть действие "Создать".
Затем в форме у меня есть поля «Музыкальная модель» и 2 других поля. Select2 виджет, который позволяет вам выбрать несколько жанров, и другое поле для ссылок (URL-адреса музыкального файла), которые могут быть динамически клонированы плагином jQuery «RelCopy» (максимум до 6 полей)
Музыка может иметь несколько жанров, а также несколько ссылок
Моя проблема в том, как правильно сохранить все эти поля? Надеюсь, я достаточно ясно выразился.
Вот код, который у меня есть до сих пор:
MusicController.php
/**
* Creates a new model.
* If creation is successful, the browser will be redirected to the 'view' page.
*/
public function actionCreate()
{
$music = new Music;
$genre = new MusicGenre;
$link = new MusicLink;
// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($music);
if(isset($_POST['Music']) && isset($_POST['MusicGenre']))
{
CActiveForm::validate($genre);
CActiveForm::validate($link);
$music->attributes=$_POST['Music'];
if($music->save()){
foreach(explode(',',$_POST['MusicGenre']['genre_id']) as $gen)
{
$genre=new MusicGenre;
$genre->genre_id = $gen;
$genre->music_id = $music->id;
if($genre->validate())
$valid[]=true;
else
$valid[]=false;
}
foreach($_POST['Music']['links'] as $lnk)
{
$link=new MusicLink;
$link->link = $lnk;
$link->music_id = $music->id;
$link->host = MusicLink::model()->getHoster($lnk);
if($link->validate())
$valid[]=true;
else
$valid[]=false;
}
if(!in_array(false,$valid)){
$genre->save();
$link->save();
$this->redirect(array('view','id'=>$music->id));
}
}
}
$this->render('create',array(
'music'=>$music,
'genre'=>$genre,
'link'=>$link,
));
}
/**
* Updates a particular model.
* If update is successful, the browser will be redirected to the 'view' page.
* @param integer $id the ID of the model to be updated
*/
public function actionUpdate($id)
{
$music = $this->loadModel($id);
$genre = MusicGenre::model()->findByAttributes(array('music_id'=>$id));//new MusicGenre;
$link = MusicLink::model()->findAll('music_id=:mID',array(':mID'=>$id));;
// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($music);
if(isset($_POST['Music']) && isset($_POST['MusicGenre']))
{
$music->attributes=$_POST['Music'];
if($music->save()){
foreach(explode(',',$_POST['MusicGenre']['genre_id']) as $gen)
{
//$genre = MusicGenre::model()->findByAttributes(array('music_id'=>$music->id));
$genre->genre_id = Genre::model()->nameToId($gen);
$genre->music_id = $music->id;
$valid[]=$genre->save();
}
foreach($_POST['Music']['links'] as $lid => $lnk)
{
$link = MusicLink::model()->find('music_id=:mID AND id=:lID',array(':mID'=>$music->id,':lID'=>$lid));
if($link == null){
$link=new MusicLink;
$link->link = $lnk;
$link->music_id = $music->id;
$link->host = MusicLink::model()->getHoster($lnk);
$valid[]=$link->save();
}else if($link->link != $lnk){
$link->link = $lnk;
$link->music_id = $music->id;
$link->host = MusicLink::model()->getHoster($lnk);
$valid[]=$link->save();
}
}
if(!in_array(false,$valid))
$this->redirect(array('view','id'=>$music->id));
}
}
$this->render('update',array(
'music'=>$music,
'genre'=>$genre,
'link'=>$link,
));
}
\music_form.php
<?php $form=$this->beginWidget('bootstrap.widgets.TbActiveForm',array(
'id'=>'music-form',
'type' => 'horizontal',
'customCssErrors' => 'inline',
'enableAjaxValidation'=>false,
)); ?>
<fieldset>
<legend>
<?php echo $music->isNewRecord ? Yii::t('b2r','Create Music') : Yii::t('b2r','Update Music') ;?>
</legend>
<p class="help-block well well-small"><?php echo Yii::t('b2r','Fields with <span class="required">*</span> are required.'); ?>
</p>
<?php
$models = array($music,$genre);
if (is_array($link))
foreach ($link as $lnk)
$models[] = $lnk;
else
$models[] = $link;
//die(var_dump($models));
?>
<?php echo $form->errorSummary($models); ?>
<div class="span6 first">
<?php echo $form->textFieldRow($music,'artist',array('class'=>'span12','maxlength'=>255)); ?>
<?php echo $form->textFieldRow($music,'title',array('class'=>'span12','maxlength'=>255)); ?>
<?php echo $form->textAreaRow($music,'desc',array('rows'=>3, 'cols'=>60, 'class'=>'span12')); ?>
<?php echo $form->select2Row($genre, 'genre_id', array(
'asDropDownList' => false,
'val' => MusicGenre::model()->getMusicGenresNames($music->id),
'options' => array(
'data' => Genre::model()->getGenres(),
'placeholder' => 'Escreva um ou mais categorias, separadas por virgulas',
'containerCssClass' => 'span12',
'tokenSeparators' => array(','),
'multiple'=>true,
'width'=>'none',
'initSelection' => 'js:function (element, callback) {
var val = [];
$(element.val().split(",")).each(function () {
val.push({id: this, text: this});
});
callback(val);
}'
)
)); ?>
<?php echo $form->maskedTextFieldRow($music,'length',array('mask'=>'99:99?:99','htmlOptions'=>array('class'=>'span12','maxlength'=>8)),array('hint'=>Yii::t('b2r','No formato {f1} ou {f2}',array('{f1}'=>'<i class="label label-info">MM:SS</i>','{f2}'=>'<i class="label label-info">HH:MM:SS</i>')))); ?>
<?php echo $form->maskedTextFieldRow($music,'size',array('mask'=>'?~~~.~~','charMap'=>array('~'=>'^[0-9]+(\.)?[0-9]{0,2}$'),'placeholder'=>'0','htmlOptions'=>array('class'=>'span12','maxlength'=>8)),array('hint'=>Yii::t('b2r','No formato {f1} ou {f2}',array('{f1}'=>'<i class="label label-info">xx.xx</i>','{f2}'=>'<i class="label label-info">xxx.xx</i>')))); ?>
</div>
<div class="span6">
<div class="controls">
<ul class="thumbnails">
<li class="span5">
<a class="thumbnail">
<?php echo CHtml::image('/images/capa.gif',Yii::t('b2r','Previsualização da Imagem'),
array('id'=>'previewHolder','width'=>'170px','height'=>'170px')); ?>
</a>
</li>
</ul>
</div>
<?php echo $form->textFieldRow($music,'image',array('class'=>'span8','maxlength'=>255),array('controlCss'=>'skipcopy','append'=>'<a href="#" id="findcover" data-toggle="tooltip" title="'.Yii::t('b2r','Procurar capa no Google').'"><i class="icon-circle-arrow-right"></i></a>')); ?>
<?php
if ($music->isNewRecord){
echo $form->textFieldRow($link,'link',
array('name'=>'MusicLink[links][0]','value'=>'','maxlength'=>255, 'class'=>'span8'),
array('controlCss'=>'copy clonable','append'=>'<a id="copylink" href="#" rel=".copy"><i class="icon-plus"></i></a> ')
);
}else{
$last = count($link)-1;
foreach ($link as $k => $v)
die(var_dump($link));
$id = (is_null($v)) ? $k : $v->id;
if($k == $last)
echo $form->textFieldRow($v,'link',
array('name'=>'MusicLink[links]['.$id.']','maxlength'=>255, 'class'=>'span8'),
array('controlCss'=>'copy clonable','label'=>'<span class="required">*</span>','append'=>'<a id="copylink" href="#" rel=".copy"><i class="icon-plus"></i></a> ')
);
else
echo $form->textFieldRow($v,'link',
array('name'=>'MusicLink[links]['.$id.']','maxlength'=>255, 'class'=>'span8'),
array('controlCss'=>'clonable')
);
}
?>
<?php
$this->widget('ext.jqrelcopy.JQRelcopy',array(
//the id of the 'Copy' link in the view, see below.
'id' => 'copylink',
//add a icon image tag instead of the text
//leave empty to disable removing
'removeText' => '<i class="icon-remove"></i>',
//htmlOptions of the remove link
'removeHtmlOptions' => array('style'=>'margin-left:2px;padding:3px 10px;','class'=>'btn btn-small btn-danger'),
//options of the plugin, see http://www.andresvidal.com/labs/relcopy.html
'options' => array(
//A class to attach to each copy
'copyClass'=>'newcopy',
// The number of allowed copies. Default: 0 is unlimited
'limit'=>6,
//Option to clear each copies text input fields or textarea
'clearInputs'=>true,
//A jQuery selector used to exclude an element and its children
'excludeSelector'=>'.skipcopy',
//Additional HTML to attach at the end of each copy.
//'append'=>CHtml::tag('span',array('class'=>'hint'),'You can remove this line'),
//'jsAfterNewId' => "if(typeof $(this > input).attr('name') !== 'undefined'){ $(this > input).attr('name', $(this > input).attr('name').replace('new', 'new_'+counter));}",
)
));
?>
</div>
<?php $collapse = $this->beginWidget('bootstrap.widgets.TbCollapse',array('htmlOptions'=>array('class'=>'span12 first'))); ?>
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse"
data-parent="#accordion2" href="#collapseOne">
Avançado
</a>
</div>
<div id="collapseOne" class="accordion-body collapse">
<div class="accordion-inner">
<?php echo $form->textFieldRow($music,'bitrate',array('class'=>'span9')); ?>
</div>
</div>
</div>
<?php $this->endWidget(); ?>
</fieldset>
<div class="form-actions">
<?php $this->widget('bootstrap.widgets.TbButton', array(
'buttonType'=>'submit',
'type'=>'primary',
'label'=>$music->isNewRecord ? Yii::t('b2r','Create') : Yii::t('b2r','Save'),
)); ?>
</div>
<?php $this->endWidget(); ?>
<?php Yii::app()->clientScript->registerScript('script', "
$('#Music_image').change(function() {
$('#previewHolder').attr('src',$(this).val());
});
$('#findcover').click(function() {
var q = $('#Music_artist').val();
q += ' - '+$('#Music_title').val();
q += ' cover';
window.open('https://www.google.pt/search?q='+escape(q)+'&tbm=isch', '_blank');
});
"
, CClientScript::POS_READY);?>
ИЗМЕНИТЬ
С этим кодом я могу сохранить все правильно, но например, если я не выбираю Жанр, или не ввожу ссылку на файл, сохраняет только музыку. Но, например, если отсутствует обязательное поле Music Model, а также MusicGenres или MusicLink, проверяются все три модели. Если ошибки относятся только к модели MusicGenre или MusicLink, музыка сохраняется, но не эти 2 модели
Я использую Yii версии 1.1.14 с YiiBoostrap и YiiBoilerplate.
Вот ссылки на плагины:
http://www.andresvidal.com/labs/relcopy.html