Location: PHPKode > projects > Agile Toolkit > atk4-atk4-addons-efc6814/filestore/lib/Model/File.php
<?php
namespace filestore;
class Model_File extends \Model_Table {
	public $table='filestore_file';

	public $entity_filestore_type='Type';
	public $entity_filestore_volume='Volume';

    public $import_mode=null;
	public $import_source=null;

	function init(){
		parent::init();
		$this->hasOne('filestore/'.$this->entity_filestore_type,'filestore_type_id')
			->caption('File Type')
			->mandatory(true)
			;
		$this->hasOne('filestore/'.$this->entity_filestore_volume,'filestore_volume_id')
			->caption('Volume')
			->mandatory(true)
			;

		/*
		$this->addField('filenum')
			->datatype('int')
			;
			*/
		$this->newField('original_filename')
			->datatype('text')
			->caption('Original Name')
			;
		$this->newField('filename')
			->datatype('string')
			->caption('Internal Name')
			;
		$this->newField('filesize')
			->datatype('int')
            ->defaultValue(0)
			;
		$this->newField('deleted')
			->datatype('boolean')
            ->defaultValue(false)
			;

		$this->newField('name_size')
			->calculated(true)
			;
        $this->addHook('beforeSave',$this);
	}
	function calculate_name_size(){
		return 'concat("[",filestore_file.id,"] ",coalesce(original_filename,"??")," (",coalesce(round(filesize/1024),"?"),"k)")';
	}
	function toStringSQL($source_field, $dest_fieldname){
		return $source_field.' '.$dest_fieldname;
	}
	public function getListFields(){
		return array('id'=>'id','name_size'=>'name');
	}
	function beforeSave($m){
        if(!$this->loaded()){
            // New record, generate the name
            $this->set('filestore_volume_id',$x=$this->getAvailableVolumeID());
            $this->set('filename',$this->generateFilename());
        }
		if($this->import_mode){
			$this->performImport();
		}
	}
	function getAvailableVolumeID(){
		// Determine best suited volume and returns it's ID
		$c=$this->add('filestore/Model_'.$this->entity_filestore_volume)
			->addCondition('enabled',true)
			->addCondition('stored_files_cnt','<',4096*256*256)
			;
		$id=$c->dsql('select')
			->order('rand()')
			->limit(1)
			->field('id')
			->do_getOne();
		$c->loadData($id);

        /*
		if(disk_free_space($c->get('dirname')<$filesize)){
			throw new Exception_Filestore_Physical('Out of disks space on volume '.$c);
		}
         */

		return $id;
	}
	function getFiletypeID($mime_type = null, $add = false){
        if($mime_type == null){
            $path = $this->get('filename')?$this->getPath():$this->import_source;
            if(!$path)throw $this->exception('Load file entry from filestore or import');
            $mime_type=mime_content_type($path);
        }
        $c=$this->add('filestore/Model_'.$this->entity_filestore_type);
        $data = $c->getBy('mime_type',$mime_type);
        if(!$data['id']){
            if ($add){
                $c->update(array("mime_type" => $mime_type, "name" => $mime_type));
                $data = $c->get();
            } else { 
                throw $this->exception('This file type is not allowed for upload')
                    ->addMoreInfo('type',$mime_type);
            }
		}
		return $data['id'];
	}
	function generateFilename(){
        $this->hook("beforeGenerateFilename");
        if ($filename = $this->get("filename")){
            return $filename;
        }
		$v=$this->getRef('filestore_volume_id'); //won't work because of MVCFieldDefinition, line 304, isInstanceLoaded check
		$dirname=$v->get('dirname');
		$seq=$v->getFileNumber();

		// Initially we store 4000 files per node until we reach 256 nodes. After that we will
		// determine node to use by modding filecounter. This method ensures we don't create too
		// many directories initially and will grow files in directories indefenetely

		$limit=4000*256;

		if($seq<$limit){
			$node=floor($seq / 4000);
		}else{
			$node=$seq % 256;
		}

		$d=$dirname.'/'.dechex($node);
		if(!is_dir($d))mkdir($d);

		// Generate temporary file
		$file=basename(tempnam($d,'fs'));

		// Verify that file was created
		if(!file_exists($d.'/'.$file)){
			throw $this->exception('Could not create file')->addMoreInfo('inside',$d)->addMoreInfo('file',$file);
		}

		return dechex($node).'/'.$file;
	}

	function import($source,$mode='upload'){
		/*
		   Import file from different location. 

		   $mode can be
		    - upload - for moving uploaded files. (additional validations apply)
			- move - original file will be removed
			- copy - original file will be kept
			- string - data is passed inside $source and is not an existant file
		   */
		$this->import_source=$source;
		$this->import_mode=$mode;

        if($this->isInstanceLoaded() && $this->id){// -- if we have this, then we 
            // can import right now

			// If file is already in database - put it into store
			$this->performImport();
			$this->save();
        }
        return $this;
	}

	function getPath(){
        $volume = $this->getRef('filestore_volume_id');
		return $volume->get('dirname').'/'.$this->get('filename');
	}
    function getMimeType(){
        return $this->getRef('filestore_type_id')
            ->get('mime_type');
    }
	function performImport(){
		/*
		   After our filename is determined - performs the operation
		   */
		$destination=$this->getPath();
		switch($this->import_mode){
        case'upload':
				move_uploaded_file($this->import_source,$destination);
				break;
			case'move':
				rename($this->import_source,$destination);
				break;
			case'copy':
				copy($this->import_source,$destination);
				break;
			case'string':
				$fd=fopen($destination,'w');
				fwrite($fd,$this->import_source);
				fclose($fd);
				break;
            case'none': // file is already in place
                break;
			default:
				throw new Exception_Filestore('Incorrect import mode specified: '.$this->import_mode);
		}
        chmod($destination, $this->api->getConfig('filestore/chmod',0660));
		clearstatcache();
		$this->set('filesize',$f=filesize($destination));
		$this->set('deleted',false);
        $this->set('filestore_type_id',$this->getFiletypeID());
		$this->import_source=null;
		$this->import_mode=null;
        return $this;
	}
	/*
	function beforeDelete(&$data){
		// Truncate but do not delete file completely
		parent::beforeDelete($data);
		$fd=fopen($this->getPath(),'w');
		fclose($fd);
	}
	*/
}
Return current item: Agile Toolkit