Ponieważ jakiś czas już grzebię sobie w Yii Framework jednym z nurtujących mnie zagadnień do zrealizowania było stworzenie formularza z możliwością uploadu pliku, zdjęcia. Mój formularz dodaje zdjęcie i plik dla przykładu wykorzystałem tutorialowy blog Yii. W tworzeniu stron internetowych niezwykle ważne są elementu formularza typu file. A więc zacznijmy od kontrolera, który będzie miał za zadanie zapisanie naszego pliku w określonej przez nas lokalizacji. Dla kontrolera musimy utworzyć bądź zmodyfikować dwie akcje actionCreate(), actionUpdate().
Kontroler:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public function actionCreate() { $model=new Post; if(isset($_POST['Post'])) { $model->attributes=$_POST['Post']; //Pobieramy atrybuty z formularza $model->image=CUploadedFile::getInstance($model,'image'); //Przypisujemy nazwę wysłanego pliku do atrybutu image modelu Post $model->file=CUploadedFile::getInstance($model,'file'); //Przypisujemy nazwę wysłanego pliku do atrybutu file modelu Post if($model->save()) { $images_path = realpath(Yii::app()->basePath . '/../files/images'); //określamy ścieżkę zapisu zdjęcia $files_path = realpath(Yii::app()->basePath . '/../files/files'); //określamy ścieżkę zapisu pliku $model->image->saveAs($images_path . '/' . $model->image); //zapis image $model->file->saveAs($files_path . '/' . $model->file); //zapis pliku // redirect to success page $this->redirect(array('view','id'=>$model->id)); } } $this->render('create',array( 'model'=>$model, )); } |
Funkcja Create jest dość prosta, ponieważ polega ona na pobraniu nazwy zdjęcia i pliku do zapisu w bazie danych, oraz na zapisie nowych plików pobranych poprzez formularz. Większy problem zaczyna się przy akcji Update, co opisałem dokładnie krok po kroku:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
public function actionUpdate() { $model=$this->loadModel(); if(isset($_POST['Post'])) { $old_image = $model->image; // Zapisujemy w zmiennej stary atrybut image $old_file = $model->file; // Zapisujemy w zmiennej stary atrybut pliku $model->attributes=$_POST['Post']; / Pobieramy atrybuty z formularza //Zapisujemy do zmiennej pobrane dane z formularzy(jeśli pola były użyte) $image = CUploadedFile::getInstance($model,'image'); //Zapisujemy do zmiennej pobrane dane $file = CUploadedFile::getInstance($model,'file'); //Sprawdzamy, czy pole image było wypełnione, jeśli nie to zostanie użyta zmienna $old_image if (is_object($image) && get_class($image)==='CUploadedFile') { $model->image = $image; } else { $model->image = $old_image; } //Sprawdzamy, czy pole file było wypełnione, jeśli nie to zostanie użyta zmienna $old_file if (is_object($file) && get_class($file)==='CUploadedFile') { $model->file = $file; } else { $model->file = $old_file; } //Zapis plików if($model->save()){ if (is_object($image) && get_class($image)==='CUploadedFile') { $images_path = realpath(Yii::app()->basePath . '/../files/images/'); $model->image->saveAs($images_path.$model->image); } if (is_object($file) && get_class($file)==='CUploadedFile') { $files_path = realpath(Yii::app()->basePath . '/../files/files/'); $model->file->saveAs($files_path.$model->file); } $this->redirect(array('view','id'=>$model->id)); } } $this->render('update',array( 'model'=>$model, )); } |
Kolejnym elementem naszego formularza który przeanalizuję będzie model w którym ustawimy wszystkie reguły. Na początek definiujemy nasze dwie zmienne image, oraz file.
Model:
1 2 3 4 5 6 7 |
<?php class Post extends CActiveRecord { public $image; public $file; |
Teraz przechodzimy do funkcji rules(), gdzie ustawimy nasze reguły. Ja z powodu braku takiej potrzeby nie ustawiałem żadnych reguł po za rodzajem pliku.
Model:
1 2 3 4 5 |
public function rules() { return array( array('image', 'file', 'types'=>'jpg, gif, png, jpeg', 'allowEmpty'=>true), array('file', 'file', 'types'=>'zip, rar', 'allowEmpty'=>true), |
A więc jedyne, co nam pozostało do wykonania to edycja pliku widoku. Tak jak wspominałem, korzystałem z tutorialowego blogu yii tak więc edytowałem plik _form.php dla widoku Post, lecz można to zrobić z dowolnym formularzem np. wygenerowanym przez Gii. Wystarczy teraz wkleić kod widoku naszych pól image i file formularza.
Widok:
1 2 3 4 5 6 7 8 9 10 11 |
<div class="row"> <?php echo $form->labelEx($model, 'image'); ?> <?php echo $form->fileField($model, 'image'); ?> <?php echo $form->error($model, 'image'); ?> </div> <div class="row"> <?php echo $form->labelEx($model, 'file'); ?> <?php echo $form->fileField($model, 'file'); ?> <?php echo $form->error($model, 'file'); ?> </div> |
Najlepiej to wkleić przed ostatnimi elementami formularza lecz ułożenie jest dowolne 🙂
1 2 3 4 5 |
<div class="row buttons"> <?php echo CHtml::submitButton($model->isNewRecord ? 'Create' : 'Save'); ?> </div> <?php $this->endWidget(); ?> |
Od teraz możemy się cieszyć uploadem plików i zdjęć z naszego formularza. Na dzień dzisiejszy nie potrzebowałem tworzyć akcji usuwania plików lecz może zabiorę się za to już wkrótce:)
Thanks for laret 🙂
Genialnie! Jest naprawdę fajnie.
Szkoda że nie zrobiłeś pobieranie tych plików, bardzo by się przydało 🙂
Stronę z pobieraniem można zrobić w widgecie CListView lub CGridView zresztą na to poświęcę osobny post jak tylko znajdę trochę czasu. 🙂
A wiesz może coś na temat maskowania indexu.php i wszystkich niepotrzebnych znaków?
Chodzi o usuwanie index.php z adresu url i tworzenie prostych linków?
Dokładnie, ale poradziłem sobie z tym, większy problem robi mi wrzucenie $data do view.php gdzie będą dane z innej tabeli niż z tabeli od $modelu. Gdybyś miał chwilę, i wiedział jak poradzić sobie z tym to odezwij się na emial. Dzieki 🙂
Zajrzyj tutaj:
http://stackoverflow.com/questions/8648382/multiple-dataproviders-yii
http://www.yiiframework.com/forum/index.php/topic/21071-provide-two-dataproviders-from-controller/
http://www.yiiframework.com/forum/index.php/topic/32188-cgridview-to-display-data-from-two-tables/
dzieki :). Lecz cały czas nie mogę się uporać z:
ublic function defaultScope() {
if (Yii::app()->user->checkAccess(‘admin’)) {
return array();
} else {
$tabAlias = Task::model()->getTableAlias();
return array(
‘condition’ => $tabAlias . “.user_id = ‘” . Yii::app()->user->id . “‘”,
);
}
}
Posiadam tabele Task i Projekt, project nie posiada usr_id a Task posiada. Zadaniem mojej funkcji jest wyświetlenie wszystkich zadań w projektach które mają user_id zalogowanego.
Jednakże gdy chcę wyświetlić dostaję błąd:
CDbCommand failed to execute the SQL statement: SQLSTATE[42S22]: Column not found: 1054 Unknown column ‘t.user_id’ in ‘where clause’. The SQL statement executed was: SELECT COUNT(DISTINCT
t
.id
) FROMproject
t
LEFT OUTER JOINuser_project
users_users
ON (t
.id
=users_users
.project_id
) LEFT OUTER JOINuser
users
ON (users
.id
=users_users
.user_id
) LEFT OUTER JOINuser
author
ON (t
.author_id
=author
.id
) LEFT OUTER JOINtask
tasks
ON (tasks
.project_id
=t
.id
) WHERE (t.user_id = ’49’)Według tej funckji co jest powyżej jest: t(alias->task).user_id = user_id <- zalogowanego..