Invalidating A Record (With Afterfind?)

Hi after a while. I have this case:

A MySQL table lists “files” which are physically located in a hard drive. Ocasionally a file is deleted from disk but not from the table, so the table has pointers to inexistent disk files. I’d like to test if each file [font=“Courier New”]is_readable()[/font] before I return the results of a[font=“Courier New”] findAll()[/font] which lists the files in the table, so if a file does not exist on disk, it is not listed on screen. My current code looks like:


protected function afterFind()

   {

  	parent::afterFind();


  	if (!is_readable($this->path.$this->hashed)) {

     	print "Sorry, file deleted.";

  	}

   }

How can I invalidate the record instead of print the message?

Thanks.

Maybe implement a simple garbage collector like this:

  1. Add a column to mark deleted files.

  2. Occasionally run some code that will verify if all files exist.

  3. Such could could also be run before running the real findAll().

Of course there can be a race condition when some files are deleted after checking them. You should check again every time when refering to that file.

This creates a lot of overhead so the best solution is to mark files at the same time they are deleted. If that’s not possible, there are solutions to monitor directory in the operating system and detect such operations - it’s called inotify in Linux, but that requires running a daemon or script in the background all the time.

try this


 $file1 = $baseUrl.'/upload/'.$model->file_name;

if($file!='' && file_exists(Yii::app()->request->baseUrl.'/upload/').$file) {

}else {

}



It could be possible, but it means running a cronjob. Thanks.

Thanks Ankit. I’m doing this already outside the model, but I’d like to do it inside the model so I don’t copy&paste the code everywhere I call the model’s find methods. What I’d like to do is:

  1. For single finds (find()) return null,

  2. For multiple finds (findAll() etc.) return the array without the records which don’t have a file in disk.

But this could be applied for other thins, for instance, in a table wich keeps bookmarks to sites, on findAll check whether the site is alive and if it is not, mark it as inactiva and don’t return it.

You can override find() and findAll() methods.

Custom find() should call parent::find and then return either parent’s result or null (in case of missing file).

Custom findAll should call parent::findAll and then filter array of results, removing records with missing files.

There will be some bad caveats with pagination though, so you’ll have to either do an extra query for filling removed records, or move this logic to DB-side (postgreSQL can do that)

Btw it seems like DB-stored files (BLOB), which are usually considered to be a bad practice, fit well in your case.

All other solutions are either non-realtime, or relatively complex.

Not so quite, files are sometimes really big in my case. Thanks anyway for the suggestion.

Will try this, thanks.