Reputation: 2302
Images fail to upload when I create a new item but on updating the newly created item the file is successfully uploaded. Any reasons?
Trending News Model
class TrendingNews extends \yii\db\ActiveRecord
{
const EVENT_ADD_TRENDING_NEWS = 'add-trending-news';
public $featuredFile;
public function init() {
$this->on(self::EVENT_ADD_TRENDING_NEWS, [$this, 'saveToLog']);
}
/**
* @inheritdoc
*/
public static function tableName()
{
return 'trending_news';
}
/**
* @inheritdoc
*/
public function rules()
{
return [
[['headline_text','news_info', 'news_url', 'author', 'published', 'date_added', 'date_modified'], 'required'],
[['headline_text', 'image_url', 'news_info', 'news_url'], 'string'],
[['date_added', 'date_modified'], 'safe'],
[['author'], 'string', 'max' => 20],
[['published'], 'string', 'max' => 2],
[['featuredFile'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg'],
];
}
/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'headline_text' => 'Headline',
'image_url' => 'Image Url',
'news_info' => 'Source',
'news_url' => 'News Url',
'author' => 'Author',
'published' => 'Published',
'date_added' => 'Date Added',
'date_modified' => 'Date Modified',
'featuredFile' => 'Featured Image',
];
}
public function uploadBanner()
{
if ($this->validate()) {
$ymd = date("Ymd");
$save_path = \Yii::getAlias('@backend') . '/web/uploads/' . $ymd . '/';
if (!file_exists($save_path)) {
mkdir($save_path, 0777, true);
}
$fileName = "trending_".Yii::$app->security->generateRandomString(20);
$this->featuredFile->saveAs($save_path . $fileName .'.' . $this->featuredFile->extension);
$this->image_url = $ymd . '/'. $fileName . '.' . $this->featuredFile->extension;
return true;
} else {
return false;
}
}
public function upload()
{
if ($this->validate()) {
$ymd = date("Ymd");
$save_path = \Yii::getAlias('@backend') . '/web/uploads/' . $ymd . '/';
if (!file_exists($save_path)) {
mkdir($save_path, 0777, true);
}
$fileName = Yii::$app->security->generateRandomString(20);
$this->featuredFile->saveAs($save_path . $fileName .'.' . $this->featuredFile->extension);
$this->image_url = $ymd . '/'. $fileName . '.' . $this->featuredFile->extension;
return true;
} else {
return false;
}
}
public function beforeSave($insert)
{
if (parent::beforeSave($insert)) {
if ($this->isNewRecord) {
$this->date_added = date("YmdHis");
$this->author = Yii::$app->user->identity->id;
}
else {
$this->date_modified = date("YmdHis");
}
return true;
}
else{
return false;
}
}
public function saveToLog($event)
{
//assigning attributes
// echo 'mail sent to admin using the event';
$app_log_model = new AppLog();
$app_log_model->log_time = date("YmdHis");
$app_log_model->log_activity = 'Added a trending news';
$app_log_model->user_id = Yii::$app->user->identity->id;
$app_log_model->device = "1";
if ($app_log_model->save()) {
return true;
} else {
return $app_log_model->getErrors() ;
}
}
}
usage
public function actionCreate()
{
$model = new TrendingNews();
if ($model->load(Yii::$app->request->post())) {
$model->featuredFile = UploadedFile::getInstance($model, 'featuredFile');
if(isset($model->featuredFile)){
$model->upload();
$model->save(false);
} else {
// file is uploaded successfully
$model->save();
//$model->trigger(BlogArticle::EVENT_EDIT_ARTICLE);
}
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
public function actionUpdate($id)
{
$model = $this->findModel($id);
if ($model->load(Yii::$app->request->post())) {
$model->featuredFile = UploadedFile::getInstance($model, 'featuredFile');
if(isset($model->featuredFile)){
$model->upload();
$model->save(false);
} else {
$model->save();
}
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('update', [
'model' => $model,
]);
}
}
the app log shows this
$_FILES = [
'TrendingNews' => [
'name' => [
'featuredFile' => 'another_evento.jpg'
]
'type' => [
'featuredFile' => ''
]
'tmp_name' => [
'featuredFile' => ''
]
'error' => [
'featuredFile' => 3
]
'size' => [
'featuredFile' => 0
]
]
]
featuredFile
is not a database field
Is there something that is being done wrong?
I am using xampp,tried on a live server and the issue is same
Upvotes: 0
Views: 294
Reputation: 23778
You are doing it wrong if you have to require a file input on insert and not on the update you should add a scenario for it so that it asks you to provide file when adding a new record only.
Secondly you are using the same ActiveRecord
model and added a custom attribute in it to be used as a file input and in the upload()
function you are calling validate()
and returning false if not validated but on the same time you are not checking for true
or false
in you controller action and on the very next line you are calling $model->save(false)
with false so technically your script would never intimate the user if there is any validation error.
The file should be uploaded after the record is saved not before saving the record so that there are no extra files uploaded in case of error, although you want the file to be required on insert
so technically if file is not uploaded the record should not be saved, and for this reason we have transactions for database insertions you should use a transaction block to save the rcord and the file along with it
You should only call the validate()
method for file uploading if you have a separate FormModel
for file uploading otherwise you should load the instance from the UploadedFile
to the model field and call the $model->save()
which will automatically validate the model before saving you should just check for the empty filename before uploading so that when you are updating any record and not submitting a file the previous file should be kept as is.
You need to update your validation rules to the following first
/**
* @inheritdoc
*/
public function rules()
{
return [
[['headline_text','news_info', 'news_url', 'author', 'published', 'date_added', 'date_modified'], 'required'],
[['headline_text', 'image_url', 'news_info', 'news_url'], 'string'],
[['date_added', 'date_modified'], 'safe'],
[['author'], 'string', 'max' => 20],
[['published'], 'string', 'max' => 2],
[ [ 'featuredFile' ] , 'required' , 'on' => 'insert' ] ,
[ [ 'featuredFile' ] , 'file' , 'extensions' => 'png, jpg' , 'maxSize' => 200000 , 'tooBig' => 'Limit is 500KB' ] ,
];
}
Change the upload()
function to the following
public function upload( $ymd , $fileName ) {
if ( $this->featuredFile !== null && $this->featuredFile->name !== '' ) {
$save_path = \Yii::getAlias ( '@backend' ) . '/web/uploads/' . $ymd . '/';
if ( !file_exists ( $save_path ) ) {
mkdir ( $save_path , 0777 , true );
}
if ( !$this->featuredFile->saveAs ( $save_path . $fileName ) ) {
$this->addError ( 'featuredFile' , 'File could not be uploaded' );
throw new \Exception ( 'File upload error' );
}
}
}
Then add another method inside your model to remove old file in case of new file uploaded on update
public function unlinkOldFile( $filename ) {
if ( $filename !== '' ) {
$save_path = \Yii::getAlias ( '@backend' ) . '/web/uploads/' . $filename;
unlink ( $save_path );
}
}
after that change your create
and update
actions to the following so that they use transation
blocks for database operations
public function actionCreate() {
$model = new TrendingNews(['scenario'=>'insert']);
if ( $model->load ( Yii::$app->request->post () ) ) {
$model->featuredFile = UploadedFile::getInstance ( $model , 'featuredFile' );
if ( $model->featuredFile !== null ) {
$ymd = date ( "Ymd" );
$fileName = Yii::$app->security->generateRandomString ( 20 ) . '.' . $model->featuredFile->extension;
$model->image_url = $ymd . '/' . $fileName;
}
$transaction = Yii::$app->db->beginTransaction ();
try {
if ( !$model->save () ) {
throw new \Exception ( 'Error Occoured' );
}
$model->upload ( $ymd , $fileName );
$transaction->commit ();
return $this->redirect ( [ 'view' , 'id' => $model->id ] );
} catch ( \Exception $ex ) {
$transaction->rollBack ();
}
}
return $this->render ( 'create' , [
'model' => $model ,
] );
}
public function actionUpdate( $id ) {
$model = $this->findModel ( $id );
if ( $model->load ( Yii::$app->request->post () ) ) {
$model->featuredFile = UploadedFile::getInstance ( $model , 'featuredFile' );
//$oldFile = '';
$oldFile = $model->image_url;
if ( $model->featuredFile !== null ) {
$ymd = date ( "Ymd" );
$fileName = Yii::$app->security->generateRandomString ( 20 ) . '.' . $model->featuredFile->extension;
$model->image_url = $ymd . '/' . $fileName;
}
$transaction = Yii::$app->db->beginTransaction ();
try {
if ( !$model->save () ) {
throw new \Exception ( 'Model error' );
}
$model->upload ( $ymd , $fileName );
$model->unlinkOldFile ( $oldFile );
$transaction->commit ();
return $this->redirect ( [ 'view' , 'id' => $model->id ] );
} catch ( Exception $ex ) {
$transaction->rollBack ();
}
}
return $this->render ( 'update' , [
'model' => $model ,
] );
}
Upvotes: 1