Blog

Jan
22
2012

Yii with the Filemaker API

This is my first entry in my blog and I wish to start by sharing some code I wrote recently whilst integrating the Filemaker API into Yii. I started by looking in the Extensions section of the Yii main website to see if I could find anything that someone else had written but without success. I came to the realization that this had not been done yet or not created as an extension so I began on integrating it myself. The following are the steps I followed to get a functional Filemaker/Yii website working ( most likely not the best way but it works ).

  • I started by creating a vendors folder within the protected folder of my Yii site and imported the API.
  • I added an entry into config/main.php to automatically import the API.
    'import'=>array(
            'application.models.*',
    	'application.components.*',
    	'application.vendors.*',
    ),
  • I then added a few application-level parameters for connection to the API.
    'params'=>array(
    	'fm_host' => 'example.com',
    	'fm_file' => 'myfile.fp7',
    	'fm_user' => 'myusername',
    	'fm_pass' => 'mypass',
    ),
  • I decided that creating a new behaviour class would be the best approach since I can attach this to any class. So I created a CFilemakerBehaviour class and placed it within the components sections of the protected folder. Here are some basics of the class.
    class CFileMakerBehaviour extends CBehavior
    {
    	public $fm;
    	public $layout;
     
    	public function __construct($layout,$attributes = array())
    	{
    		$host = Yii::app()->params['fm_host'];
    		$file = Yii::app()->params['fm_file'];
    		$user = Yii::app()->params['fm_user'];
    		$pass = Yii::app()->params['fm_pass'];
     
    		$this->fm = new FileMaker($file,$host,$user,$pass);
     
    		$this->layout = $layout;
    	}	
    	//conditions requires an associative array i.e key => value
    	//if you want to add less than or greater than add it to the value i.e price => '> 15'
     
    	//gets all records for the layout
    	public function findAllRecords($conditions=array())
    	{
    		$find_command = $this->fm->newFindCommand($this->layout);
    		if (FileMaker::isError($find_command)) {
    			throw new FileMakerException($find_command->getMessage(),$find_command->getCode());
    		}
     
    		if (count($conditions) > 0)
    		{
    			foreach ($conditions as $label => $value)
    				$find_command->addFindCriterion($label,$value);
    		}
    		$result = $find_command->execute();
    		if (FileMaker::isError($result))
    		{
    			throw new FileMakerException($result->getMessage(),$result->getCode());
    		}
     
    		return $result->getRecords();
    	}
     
            //conditions requires an associative array i.e key => value
    	//if you want to add less than or greater than add it to the value i.e price => '> 15'
     
    	//gets a single record
            public function findRecord($conditions=array())
            {
                  $find_command = $this->fm->newFindCommand($this->layout);
    		if (FileMaker::isError($find_command)) {
    			throw new FileMakerException($find_command->getMessage(),$find_command->getCode());
    		}
     
    		if (count($conditions) > 0)
    		{
    			foreach ($conditions as $label => $value)
    			{
    				$find_command->addFindCriterion($label,$value);
    			}
    		}
     
    		$find_command->setRange(0,1);
    		$result = $find_command->execute();
    		if (FileMaker::isError($result))
    		{
    			return false;
    		}
    		return $result->getFirstRecord(); 
    	}
     
    	//gets the maximum value of a specific field
    	public function getFieldMaximum($field,$conditions=array())
    	{
    		$find_command = $this->fm->newFindCommand($this->layout);
    		if (FileMaker::isError($find_command)) {
    			throw new FileMakerException($find_command->getMessage(),$find_command->getCode());
    		}
     
    		if (count($conditions) > 0)
    		{
    			foreach ($conditions as $label => $value)
    			{
    				$find_command->addFindCriterion($label,$value);
    			}
    		}
     
    		$find_command->addSortRule($field,1,FILEMAKER_SORT_DESCEND);
    		$find_command->setRange(0,1);
    		$result = $find_command->execute();
    		if (FileMaker::isError($result))
    		{
    			return false;
    		}
    		$record = $result->getFirstRecord();
    		return $record->getField($field);
    	}
     
    	//gets the minimum value of a specific field
    	public function getFieldMinimum($field,$conditions=array())
    	{
    		$find_command = $this->fm->newFindCommand($this->layout);
    		if (FileMaker::isError($find_command)) {
    			throw new FileMakerException($find_command->getMessage(),$find_command->getCode());
    		}
     
    		if (count($conditions) > 0)
    		{
    			foreach ($conditions as $label => $value)
    			{
    				$find_command->addFindCriterion($label,$value);
    			}
    		}
     
    		$find_command->addSortRule($field,1,FILEMAKER_SORT_ASCEND);
    		$find_command->setRange(0,1);
    		$result = $find_command->execute();
    		if (FileMaker::isError($result))
    		{
    			return false;
    		}
    		$record = $result->getFirstRecord();
    		return $record->getField($field);
    	}
    }
     
    class CFileMakerException extends Exception
    {
     
    }
  • I also created a dataprovider class which is handy for cGridView:
    class CFileMakerProvider extends CDataProvider
    {
    	public $keyField;
    	private $fields;
    	private $result;
    	private $keys_array = array();
    	private $image_columns = array();
    	private $select = array();
    	private $where = array();
     
    	public function __construct($layout,$config = array())
    	{
    		$this->attachBehaviour('filemakerbehaviour',new FileMakerBehaviour($layout));
     
    		$this->fields = $this->layout->getFields();
     
    		foreach($config as $key=>$value)
    			$this->$key=$value;
    	}
     
    	protected function fetchData()
    	{	
    		$find_command = $this->fm->newFindCommand($this->layout);
     
    		if (count($this->where))
    		{
    			foreach ($this->where as $label => $value)
    				$find_command->addFindCriterion($label,$value);
    		}
     
    		if(($pagination=$this->getPagination())!==false)
    		{
    			$pagination->setItemCount($this->getTotalItemCount());
    			$find_command->setRange($pagination->getOffset(), $pagination->getLimit());
    			$this->result = $find_command->execute();
    			if (FileMaker::isError($this->result)) {
    				return 0;
    			}
    			return $this->convertRecordsToArray($this->result->getRecords());
    		}
    		else
    		{
    			$this->result = $find_command->execute();
    			if (FileMaker::isError($this->result)) {
    				return 0;
    			}
    			return $this->convertRecordsToArray($this->result->getRecords());
    		}
     
    	}
     
    	protected function convertRecordsToArray($records)
    	{
    		$data = array();
    		foreach ($records as $i => $record)
    		{
    			foreach ($this->fields as $field)
    			{
    				$field_name = $field->getName();
    				if (!count($this->select) || in_array($field_name,$this->select))
    				{
    					if (in_array($field_name,$this->image_columns))
    					{
    						$field_data = $record->getField($field_name);
    						if (!empty($field_data))
    						{
    							$raw_image = $this->fm->getContainerData($field_data);
    							if (preg_match('/\.(jpg|jpeg|JPG)/',$field_data))
    								$mime = 'image/jpeg';
    							if (preg_match('/\.png/',$field_data))
    								$mime = 'image/png';
    							if (preg_match('/\.gif/',$field_data))
    								$mime = 'image/gif';
     
    							if (isset($mime))
    							{
    								$data[$i][$field_name] = CHtml::image("data:{$mime};base64,".base64_encode($raw_image),'');
    							}
    							else
    							{
    								$data[$i][$field_name] = 'No Image.';
    							}
    						}
    						else
    						{
    							$data[$i][$field_name] = 'No Image.';
    						}
    					}
    					elseif (in_array($field_name,$this->doc_columns))
    					{
    						$field_data = $record->getField($field_name);
    						$data[$i][$field_name] = $record->getField($field_name);
    					}
    					else
    						$data[$i][$field_name] = $record->getField($field_name);
    				}
    			}
    			$this->keys_array[$i] = $record->getField($this->keyField);
    		}
    		return $data;
    	}
     
    	protected function fetchKeys()
    	{
    		return $this->keys_array;
    	}
     
    	protected function calculateTotalItemCount()
    	{
    		$find_command = $this->fm->newFindCommand($this->layout);
    		if (count($this->where))
    		{
    			foreach ($this->where as $label => $value)
    				$find_command->addFindCriterion($label,$value);
    		}
    		if(($pagination=$this->getPagination())!==false)
    			$find_command->setRange($pagination->getOffset(), $pagination->getLimit());
    		$this->result = $find_command->execute();
    		if (FileMaker::isError($this->result)) {
    			return 0;
    		}
    		return $this->result->getFoundSetCount();
    	}
    }
     
    class FileMakerProviderException extends Exception{}

To use the above classes I created models that extended the CFormModel then attached the CFileMakerBehaviour and manually loaded in what I needed.
Anyway these are the real basics and is only for a readonly website at the moment. I might create an extension later if I end up using this API more often (hopefully not).

Posted in Yii | Tagged , , | 2 Comments
Copyright © 2012 by damiandennis.com.
All Rights Reserved.