<?php
/**
 * Zend Framework (http://framework.zend.com/)
 *
 * @link      http://github.com/zendframework/zf2 for the canonical source repository
 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
 * @license   http://framework.zend.com/license/new-bsd New BSD License
 */

namespace Zend\Db\TableGateway\Feature;

use 
Zend\Db\Sql\Insert;
use 
Zend\Db\Adapter\Driver\StatementInterface;
use 
Zend\Db\Adapter\Driver\ResultInterface;

class 
SequenceFeature extends AbstractFeature
{
    
/**
     * @var string
     */
    
protected $primaryKeyField;

    
/**
     * @var string
     */
    
protected $sequenceName;

    
/**
     * @var int
     */
    
protected $sequenceValue;


    
/**
     * @param string $primaryKeyField
     * @param string $sequenceName
     */
    
public function __construct($primaryKeyField$sequenceName)
    {
        
$this->primaryKeyField $primaryKeyField;
        
$this->sequenceName    $sequenceName;
    }


    public function 
preInsert(Insert $insert)
    {
        
$columns $insert->getRawState('columns');
        
$values $insert->getRawState('values');
        
$key array_search($this->primaryKeyField$columns);
        if (
$key !== false) {
            
$this->sequenceValue $values[$key];
            return 
$insert;
        }

        
$this->sequenceValue $this->nextSequenceId();
        if (
$this->sequenceValue === null)
            return 
$insert;

        
array_push($columns$this->primaryKeyField);
        
array_push($values$this->sequenceValue);
        
$insert->columns($columns);
        
$insert->values($values);
        return 
$insert;
    }

    public function 
postInsert(StatementInterface $statementResultInterface $result)
    {
        if (
$this->sequenceValue !== null)
            
$this->tableGateway->lastInsertValue $this->sequenceValue;
    }

    
/**
     * Generate a new value from the specified sequence in the database, and return it.
     * @return int
     */
    
public function nextSequenceId()
    {
        
$platform $this->tableGateway->adapter->getPlatform();
        
$platformName $platform->getName();

        
$sql '';
        switch (
$platformName) {
            case 
'Oracle':
                
$sql 'SELECT ' $platform->quoteIdentifier($this->sequenceName) . '.NEXTVAL FROM dual';
                break;
            case 
'PostgreSQL':
                
$sql 'SELECT NEXTVAL(\'' $this->sequenceName '\')';
                break;
            default :
                return 
null;
        }

        
$statement $this->tableGateway->adapter->createStatement();
        
$statement->prepare($sql);
        
$result $statement->execute();
        
$sequence $result->getResource()->fetch(\PDO::FETCH_ASSOC);
        unset(
$statement$result);
        return 
$sequence['nextval'];
    }

    
/**
     * Return the most recent value from the specified sequence in the database.
     * @return int
     */
    
public function lastSequenceId()
    {
        
$platform $this->tableGateway->adapter->getPlatform();
        
$platformName $platform->getName();

        
$sql '';
        switch (
$platformName) {
            case 
'Oracle':
                
$sql 'SELECT ' $platform->quoteIdentifier($this->sequenceName) . '.CURRVAL FROM dual';
                break;
            case 
'PostgreSQL':
                
$sql 'SELECT CURRVAL(\'' $this->sequenceName '\')';
                break;
            default :
                return 
null;
        }

        
$statement $this->tableGateway->adapter->createStatement();
        
$statement->prepare($sql);
        
$result $statement->execute();
        
$sequence $result->getResource()->fetch(\PDO::FETCH_ASSOC);
        unset(
$statement$result);
        return 
$sequence['currval'];
    }
}
ace $resultResultSetInterface $resultSet)
    {
        
$this->event->setName(__FUNCTION__);
        
$this->event->setParams(array(
            
'statement' => $statement,
            
'result' => $result,
            
'result_set' => $resultSet
        
));
        
$this->eventManager->trigger($this->event);
    }

    
/**
     * Trigger the "preInsert" event
     *
     * Triggers the "preInsert" event mapping the following parameters:
     * - $insert as "insert"
     *
     * @param  Insert $insert
     * @return void
     */
    
public function preInsert(Insert $insert)
    {
        
$this->event->setName(__FUNCTION__);
        
$this->event->setParams(array('insert' => $insert));
        
$this->eventManager->trigger($this->event);
    }

    
/**
     * Trigger the "postInsert" event
     *
     * Triggers the "postInsert" event mapping the following parameters:
     * - $statement as "statement"
     * - $result as "result"
     *
     * @param  StatementInterface $statement
     * @param  ResultInterface $result
     * @return void
     */
    
public function postInsert(StatementInterface $statementResultInterface $result)
    {
        
$this->event->setName(__FUNCTION__);
        
$this->event->setParams(array(
            
'statement' => $statement,
            
'result' => $result,
        ));
        
$this->eventManager->trigger($this->event);
    }

    
/**
     * Trigger the "preUpdate" event
     *
     * Triggers the "preUpdate" event mapping the following parameters:
     * - $update as "update"
     *
     * @param  Update $update
     * @return void
     */
    
public function preUpdate(Update $update)
    {
        
$this->event->setName(__FUNCTION__);
        
$this->event->setParams(array('update' => $update));
        
$this->eventManager->trigger($this->event);
    }

    
/**
     * Trigger the "postUpdate" event
     *
     * Triggers the "postUpdate" event mapping the following parameters:
     * - $statement as "statement"
     * - $result as "result"
     *
     * @param  StatementInterface $statement
     * @param  ResultInterface $result
     * @return void
     */
    
public function postUpdate(StatementInterface $statementResultInterface $result)
    {
        
$this->event->setName(__FUNCTION__);
        
$this->event->setParams(array(
            
'statement' => $statement,
            
'result' => $result,
        ));
        
$this->eventManager->trigger($this->event);
    }

    
/**
     * Trigger the "preDelete" event
     *
     * Triggers the "preDelete" event mapping the following parameters:
     * - $delete as "delete"
     *
     * @param  Delete $delete
     * @return void
     */
    
public function preDelete(Delete $delete)
    {
        
$this->event->setName(__FUNCTION__);
        
$this->event->setParams(array('delete' => $delete));
        
$this->eventManager->trigger($this->event);
    }

    
/**
     * Trigger the "postDelete" event
     *
     * Triggers the "postDelete" event mapping the following parameters:
     * - $statement as "statement"
     * - $result as "result"
     *
     * @param  StatementInterface $statement
     * @param  ResultInterface $result
     * @return void
     */
    
public function postDelete(StatementInterface $statementResultInterface $result)
    {
        
$this->event->setName(__FUNCTION__);
        
$this->event->setParams(array(
            
'statement' => $statement,
            
'result' => $result,
        ));
        
$this->eventManager->trigger($this->event);
    }
}