<?php
/**
 * Openbizx Framework
 *
 * LICENSE
 *
 * This source file is subject to the BSD license that is bundled
 * with this package in the file LICENSE.txt.
 *
 * @package   openbiz.bin.data
 * @copyright Copyright (c) 2005-2011, Rocky Swen
 * @license   http://www.opensource.org/licenses/bsd-license.php
 * @link      http://www.phpopenbiz.org/
 * @version   $Id: BizDataObj.php 4108 2011-05-08 06:01:30Z jixian2003 $
 */

namespace Openbizx\Data;

use Openbizx\Openbizx;
use Openbizx\Object\ObjectFactoryHelper;
use Openbizx\Data\Tools\BizDataObj_Assoc;

/**
 * BizDataObj class is the base class of all data object classes
 *
 * @package openbiz.bin.data
 * @author Rocky Swen
 * @copyright Copyright (c) 2005-2009
 * @access public
 */
class BizDataObj extends BizDataObj_Lite
{

    public $useTransaction = true;

    public $m_db = null;
    public $bizFormName = null;

    /**
     * Initialize BizDataObj_Abstract with xml array
     *
     * @param array $xmlArr
     * @return void
     */
    function __construct(&$xmlArr)
    {
        parent::__construct($xmlArr);
    }

    /**
     * Validate user input data and trigger error message and adjust BizField if invalid.
     *
     * @return boolean
     * @todo: throw Openbizx\Data\Exception
     * */
    public function validateInput()
    {
        $this->errorFields = array();
        foreach ($this->bizRecord->inputFields as $fld) {

            /* @var $bizField BizField */
            $bizField = $this->bizRecord->get($fld);
            if ($bizField->encrypted == "Y") {
                if ($bizField->checkRequired() == true &&
                        ($bizField->value === null || $bizField->value === "")) {
                    $this->errorMessage = $this->getMessage("DATA_FIELD_REQUIRED", array($fld));
                    $this->errorFields[$bizField->objectName] = $this->errorMessage;
                }
                continue;
            }
            if ($bizField->checkRequired() == true &&
                    ($bizField->value === null || $bizField->value === "")) {
                $this->errorMessage = $this->getMessage("DATA_FIELD_REQUIRED", array($fld));
                $this->errorFields[$bizField->objectName] = $this->errorMessage;
            } elseif ($bizField->value !== null && $bizField->checkValueType() == false) {
                $this->errorMessage = $this->getMessage("DATA_FIELD_INCORRECT_TYPE", array($fld, $bizField->type));
                $this->errorFields[$bizField->objectName] = $this->errorMessage;
            } elseif ($bizField->value !== null && $bizField->Validate() == false) {

                /* @var $validateService validateService */
                $validateService = Openbizx::getService(VALIDATE_SERVICE);
                $this->errorMessage = $validateService->getErrorMessage($bizField->validator, $bizField->objectName);
                if ($this->errorMessage == false) { //Couldn't get a clear error message so let's try this
                    $this->errorMessage = $this->getMessage("DATA_FIELD_INVALID_INPUT", array($fld, $value, $bizField->validator));                //
                }
                $this->errorFields[$bizField->objectName] = $this->errorMessage;
            }
        }
        if (count($this->errorFields) > 0) {
            //print_r($this->errorFields);
            throw new Openbizx\Validation\Exception($this->errorFields);
            //return false;
        }

        // validate uniqueness
        if ($this->validateUniqueness() == false) {
            return false;
        }

        return true;
    }

    /**
     * Validate uniqueness
     * Uniqueness = "fld1,fld2;fld3,fld4;..."
     *
     * @return boolean
     */
    protected function validateUniqueness()
    {
        if (!$this->uniqueness)
            return true;
        $groupList = explode(";", $this->uniqueness);
        foreach ($groupList as $group) {
            $searchRule = "";
            $needCheck = true;
            $fields = explode(",", $group);
            foreach ($fields as $fld) {
                $bizField = $this->bizRecord->get($fld);
                if ($bizField->value === null || $bizField->value === "" || $bizField->value == $bizField->oldValue) {
                    $needCheck = false;
                    break;
                }
                if ($searchRule == "") {
                    $searchRule = "[" . $bizField->objectName . "]='" . addslashes($bizField->value) . "'";
                } else {
                    $searchRule .= " AND [" . $bizField->objectName . "]='" . addslashes($bizField->value) . "'";
                }
            }
            if ($needCheck) {
                $recordList = $this->directFetch($searchRule, 1);
                if ($recordList->count() > 0) {
                    $this->errorMessage = $this->getMessage("DATA_NOT_UNIQUE", array($group));
                    foreach ($fields as $fld) {
                        $this->errorFields[$fld] = $this->errorMessage;
                    }
                }
            }
        }
        if (count($this->errorFields) > 0) {
            throw new Openbizx\Validation\Exception($this->errorFields);
            return false;
        }
        return true;
    }

    /**
     * Check if the current record can be updated
     *
     * @return boolean
     */
    public function canUpdateRecord($record = null)
    {

        if ($this->dataPermControl == 'Y') {
            $svcObj = Openbizx::getService(OPENBIZ_DATAPERM_SERVICE);
            if (!$record) {
                $record = $this->getActiveRecord();
            }
            $result = $svcObj->checkDataPerm($record, 2, $this);
            if ($result == false) {
                return false;
            }
        }

        $result = $this->canUpdateRecordCondition();
        return $result;
    }

    public function canUpdateRecordCondition()
    {
        if ($this->updateCondition) {
            //return Expression::evaluateExpression($this->updateCondition,$this);
            return $this->allowAccess($this->updateCondition);
        }
        return true;
    }

    /**
     * Check if the current record can be deleted
     *
     * @return boolean
     */
    public function canDeleteRecord($record = null)
    {
        if ($this->dataPermControl == 'Y') {
            $svcObj = Openbizx::getService(OPENBIZ_DATAPERM_SERVICE);
            if (!$record) {
                $record = $this->getActiveRecord();
            }
            $result = $svcObj->checkDataPerm($record, 3, $this);
            if ($result == false) {
                return false;
            }
        }

        $result = $this->canDeleteRecordCondition();
        return $result;
    }

    /**
     *
     * @return boolean
     */
    public function canDeleteRecordCondition()
    {
        if ($this->deleteCondition) {
            // return Expression::evaluateExpression($this->deleteCondition,$this);
            return $this->allowAccess($this->deleteCondition);
        }
        return true;
    }

    /**
     * Update record using given input record array
     *
     * @param array $recArr - associated array whose keys are field names of this BizDataObj
     * @param array $oldRecord - associated array who is the old record field name / value pairs
     * @return boolean - if return false, the caller can call GetErrorMessage to get the error.
     * */
    public function updateRecord($recArr, $oldRecord = null)
    {
        $this->events()->trigger(__FUNCTION__ . '.pre', $this, array('record' => $recArr, 'old_record' => $oldRecord));
        if (!$this->canUpdateRecord($oldRecord)) {
            $this->errorMessage = MessageHelper::getMessage("DATA_NO_PERMISSION_UPDATE", $this->objectName);
            throw new Openbizx\Data\Exception($this->errorMessage);
            return false;
        }

        if (!$oldRecord)
            $oldRecord = $this->getActiveRecord();

        if (!$recArr["Id"])
            $recArr["Id"] = $this->getFieldValue("Id");

        // save the old values
        $this->bizRecord->saveOldRecord($oldRecord);
        // set the new values
        $this->bizRecord->setInputRecord($recArr);

        if (!$this->validateInput())
            return false;

        $sql = $this->getSQLHelper()->buildUpdateSQL($this);

        if ($sql) {
            $db = $this->getDBConnection("WRITE");
            if ($this->useTransaction)
                $db->beginTransaction();

            try {
                $this->cascadeUpdate(); // cascade update

                Openbizx::$app->getLog()->log(LOG_DEBUG, "DATAOBJ", "Update Sql = $sql");
                $db->query($sql);

                if ($this->useTransaction)
                    $db->commit();
            } catch (Exception $e) {
                if ($this->useTransaction)
                    $db->rollBack();

                if ($e instanceof Openbizx\Data\Exception)
                    throw $e;
                else {
                    Openbizx::$app->getLog()->log(LOG_ERR, "DATAOBJ", "Query error : " . $e->getMessage());
                    $this->errorMessage = $this->getMessage("DATA_ERROR_QUERY") . ": " . $sql . ". " . $e->getMessage();
                    throw new Openbizx\Data\Exception($this->errorMessage);
                }
                return false;
            }

            $this->cleanCache(); //clean cached data
            $this->_postUpdateLobFields($recArr);
            $this->currentRecord = null;
            $this->_postUpdateRecord($recArr);
        }
        $this->events()->trigger(__FUNCTION__ . '.post', $this, array('record' => $recArr, 'old_record' => $oldRecord));
        return true;
    }

    /**
     *
     * @param type $setValue
     * @param type $condition
     * @return boolean
     * @throws Openbizx\Data\Exception
     */
    public function updateRecords($setValue, $condition = null)
    {
        if (!$this->canUpdateRecordCondition()) {
            $this->errorMessage = MessageHelper::getMessage("DATA_NO_PERMISSION_UPDATE", $this->objectName);
            return false;
        }
        /* 当$setValue是数组时转成[field]=value格式 */
        if (is_array($setValue)) {
            $setValue_srt = '';
            foreach ($setValue as $key => $value) {
                if ($value != '') {
                    $setValue_srt.=$setValue_srt ? ",[$key]='$value'" : "[$key]='$value'";
                }
            }
            $setValue = $setValue_srt;
        }
        $sql = $this->getSQLHelper()->buildUpdateSQLwithCondition($this, $setValue, $condition);
        $db = $this->getDBConnection("WRITE");

        try {
            if ($sql) {  // delete joint table first then delete main table's data'
                Openbizx::$app->getLog()->log(LOG_DEBUG, "DATAOBJ", "Delete Sql = $sql");
                $db->query($sql);
            }
        } catch (Exception $e) {
            Openbizx::$app->getLog()->log(LOG_ERR, "DATAOBJ", "Query error : " . $e->getMessage());
            $this->errorMessage = $this->getMessage("DATA_ERROR_QUERY") . ": " . $sql . ". " . $e->getMessage();
            throw new Openbizx\Data\Exception($this->errorMessage);
            return false;
        }

        //clean cached data
        $this->cleanCache();
        return true;
    }

    /**
     * Check if the field is blob/clob type.
     * In the lob case, update (lob value only)
     *
     * @param array $recArr
     * @return mixed boolean or null
     */
    private function _postUpdateLobFields(&$recArr)
    {
        $searchRule = $this->bizRecord->getKeySearchRule(false, true);
        foreach ($this->bizRecord as $field) {
            if (isset($recArr[$field->objectName]) && $field->isLobField() && $field->column != "") {
                $db = $this->getDBConnection("WRITE");
                $sql = "UPDATE " . $this->mainTableName . " SET " . $field->column . "=? WHERE $searchRule";
                Openbizx::$app->getLog()->log(LOG_DEBUG, "DATAOBJ", "Update lob Sql = $sql");
                $stmt = $db->prepare($sql);

                $fp = fopen($recArr[$field->objectName], 'rb');
                $stmt->bindParam(1, $fp, PDO::PARAM_LOB);

                try {
                    $stmt->execute();
                } catch (Exception $e) {
                    $this->errorMessage = $this->getMessage("DATA_ERROR_QUERY") . ": " . $sql . ". " . $e->getMessage();
                    Openbizx::$app->getLog()->log(LOG_ERR, "DATAOBJ", "Update lob error = $sql");
                    fclose($fp);
                    throw new Openbizx\Data\Exception($this->errorMessage);
                    return null;
                }

                fclose($fp);
                return true;
            }
        }
        return true;
    }

    /**
     * Action after update record is done
     *
     * @param array $recArr
     * @return void
     */
    private function _postUpdateRecord($recArr)
    {
        // run DO trigger
        $this->_runDOTrigger("UPDATE");
    }

    /**
     * Create an empty new record
     *
     * @return array - empty record array with default values
     * */
    public function newRecord()
    {
        $recArr = $this->bizRecord->getEmptyRecordArr();

        // if association is 1-M, set the field (pointing to the column) value as the FieldRefVal
        if ($this->association["Relationship"] == "1-M") {
            foreach ($this->bizRecord as $field) {
                if ($field->column == $this->association["Column"] && !$field->join) {
                    $recArr[$field->objectName] = $this->association["FieldRefVal"];
                    break;
                }
            }
        }

        return $recArr;
    }

    /**
     * Generate Id according to the IdGeneration attribute
     *
     * @param boolean $isBeforeInsert
     * @param string $tableName
     * @param string $idCloumnName
     * @return long|string|boolean
     */
    protected function generateId($isBeforeInsert = true, $tableName = null, $idCloumnName = null)
    {
        // Identity type id is generated after insert is done.
        // If this method is called before insert, return null.
        if ($isBeforeInsert && $this->idGeneration == 'Identity')
            return null;

        if (!$isBeforeInsert && $this->idGeneration != 'Identity') {
            $this->errorMessage = MessageHelper::getMessage("DATA_UNABLE_GET_ID", $this->objectName);
            return false;
        }

        /* @var $genIdService genIdService */
        $genIdService = Openbizx::getService(GENID_SERVICE);
        if ($this->m_db) {
            $db = $this->m_db;
        } else {
            $db = $this->getDBConnection("READ");
        }
        $dbInfo = Openbizx::$app->getConfiguration()->getDatabaseInfo($this->databaseAliasName);
        $dbType = $dbInfo["Driver"];
        $table = $tableName ? $tableName : $this->mainTableName;
        $column = $idCloumnName ? $idCloumnName : $this->getField("Id")->column;

        try {
            $newId = $genIdService->getNewID($this->idGeneration, $db, $dbType, $table, $column);
        } catch (Exception $e) {
            $this->errorMessage = $e->getMessage();
            return false;
        }
        return $newId;
    }

    /**
     * Insert record using given input record array
     *
     * @param array $recArr - associated array whose keys are field names of this BizDataObj
     * @return boolean - if return false, the caller can call getErrorMessage to get the error.
     * */
    public function insertRecord($recArr)
    {
        $this->events()->trigger(__FUNCTION__ . '.pre', $this, array('record', $recArr));
        if ($this->_isNeedGenerateId($recArr))
            $recArr["Id"] = $this->generateId();    // for certain cases, id is generated before insert

        $this->bizRecord->setInputRecord($recArr);

        if (!$this->validateInput())
            return false;

        $db = $this->getDBConnection("WRITE");

        try {
            $sql = $this->getSQLHelper()->buildInsertSQL($this, $joinValues);
            if ($sql) {
                Openbizx::$app->getLog()->log(LOG_DEBUG, "DATAOBJ", "Insert Sql = $sql");
                $db->query($sql, $bindValues);
            }
            //$mainId = $db->lastInsertId();
            if ($this->_isNeedGenerateId($recArr)) {
                $this->m_db = $db; //compatiable for CLI mode and also speed up of it running
                $mainId = $this->generateId(false);
                $recArr["Id"] = $mainId;
            }
            Openbizx::$app->getLog()->log(LOG_DEBUG, "DATAOBJ", "New record Id is " . $recArr["Id"]);
        } catch (Exception $e) {
            Openbizx::$app->getLog()->log(LOG_ERR, "DATAOBJ", "Query Error : " . $e->getMessage());
            $this->errorMessage = $this->getMessage("DATA_ERROR_QUERY") . ": " . $sql . ". " . $e->getMessage();
            throw new Openbizx\Data\Exception($this->errorMessage);
            return null;
        }

        $this->bizRecord->setInputRecord($recArr);

        if ($this->_postUpdateLobFields($recArr) === false) {
            $this->errorMessage = $db->ErrorMsg();
            return false;
        }

        $this->cleanCache();

        $this->recordId = $recArr["Id"];
        $this->currentRecord = null;

        $this->_postInsertRecord($recArr);
        $this->events()->trigger(__FUNCTION__ . '.post', $this, array('record', $recArr));
        return $recArr["Id"];
    }

    /**
     * Action after insert record is done
     *
     * @param array $recArr
     */
    private function _postInsertRecord($recArr)
    {
        // do trigger
        $this->_runDOTrigger("INSERT");
    }

    /**
     * Delete current record or delete the given input record
     *
     * @param array $recArr - associated array whose keys are field names of this BizDataObj
     * @return boolean - if return false, the caller can call GetErrorMessage to get the error.
     * */
    public function deleteRecord($recArr)
    {
        $this->events()->trigger(__FUNCTION__ . '.pre', $this, array('record', $recArr));
        if (!$this->canDeleteRecord()) {
            $this->errorMessage = MessageHelper::getMessage("DATA_NO_PERMISSION_DELETE", $this->objectName);
            throw new Openbizx\Data\Exception($this->errorMessage);
            return false;
        }

        if ($recArr) {
            $delrec = $recArr;
        } else {
            $delrec = $this->getActiveRecord();
        }

        $this->bizRecord->setInputRecord($delrec);

        $sql = $this->getSQLHelper()->buildDeleteSQL($this);
        if ($sql) {
            $db = $this->getDBConnection("WRITE");
            $db->beginTransaction();
            try {
                $this->cascadeDelete(); // cascade delete
                Openbizx::$app->getLog()->log(LOG_DEBUG, "DATAOBJ", "Delete Sql = $sql");
                $db->query($sql);
                $db->commit();
                $this->bizRecord->saveOldRecord($delrec); // save old record only if delete success
            } catch (Exception $e) {
                $db->rollBack();
                if ($e instanceof Openbizx\Data\Exception)
                    throw $e;
                else {
                    Openbizx::$app->getLog()->log(LOG_ERR, "DATAOBJ", "Query error : " . $e->getMessage());
                    $this->errorMessage = $this->getMessage("DATA_ERROR_QUERY") . ": " . $sql . ". " . $e->getMessage();
                    throw new Openbizx\Data\Exception($this->errorMessage);
                }
                return false;
            }
        }

        //clean cached data
        $this->cleanCache();

        $this->_postDeleteRecord($this->bizRecord->getKeyValue());
        $this->events()->trigger(__FUNCTION__ . '.pre', $this, array('record', $recArr));
        return true;
    }

    public function deleteRecords($condition = null)
    {
        if (!$this->canDeleteRecordCondition()) {
            throw new Openbizx\Data\Exception(MessageHelper::getMessage("DATA_NO_PERMISSION_DELETE", $this->objectName));
            return false;
        }

        $sql = $this->getSQLHelper()->buildDeleteSQLwithCondition($this, $condition);
        $db = $this->getDBConnection("WRITE");

        try {
            if ($sql) {  // delete joint table first then delete main table's data'
                Openbizx::$app->getLog()->log(LOG_DEBUG, "DATAOBJ", "Delete Sql = $sql");
                $db->query($sql);
            }
        } catch (Exception $e) {
            Openbizx::$app->getLog()->log(LOG_ERR, "DATAOBJ", "Query error : " . $e->getMessage());
            $db->rollBack(); //if one failed then rollback all
            $this->errorMessage = $this->getMessage("DATA_ERROR_QUERY") . ": " . $sql . ". " . $e->getMessage();
            throw new Openbizx\Data\Exception($this->errorMessage);
            return false;
        }

        //clean cached data
        $this->cleanCache();
        return true;
    }

    /**
     * Action after delete record is done
     *
     * @return void
     */
    private function _postDeleteRecord()
    {
        // do trigger
        $this->_runDOTrigger("DELETE");
    }

    // $action: Delete, Update
    protected function processCascadeAction($objRef, $cascadeType)
    {
        if (($cascadeType == 'Delete' && $objRef->onDelete) || ($cascadeType == 'Update' && $objRef->onUpdate)) {
            if ($objRef->relationship == "1-M" || $objRef->relationship == "1-1") {
                $table = $objRef->table;
                $column = $objRef->column;
                $column2 = $objRef->column2;
            } else if ($objRef->relationship == "M-M" || $objRef->relationship == "Self-Self") {
                $table = $objRef->xTable;
                $column = $objRef->xColumn1;
            }
            $refField = $this->getField($objRef->fieldRef);
            $fieldVal = $this->getFieldValue($objRef->fieldRef);

            $fieldVal2 = $this->getFieldValue($objRef->fieldRef2);
            if (!$fieldVal)
                return;
            if ($column2) {
                if (!$fieldVal2)
                    return;
            }

            $db = $this->getDBConnection("WRITE");
            // get the cascade action sql
            if ($cascadeType == 'Delete') {
                if ($objRef->onDelete == "Cascade") {
                    $sql = "DELETE FROM " . $table . " WHERE " . $column . "='" . $fieldVal . "'";
                    if ($column2 && $fieldVal2) {
                        $sql .= " AND " . $column2 . "='" . $fieldVal2 . "'";
                    }
                } else if ($objRef->onDelete == "SetNull") {
                    $sql = "UPDATE " . $table . " SET $column=null WHERE " . $column . "='" . $fieldVal . "'";
                    if ($column2 && $fieldVal2) {
                        $sql .= " AND " . $column2 . "='" . $fieldVal2 . "'";
                    }
                } else if ($objRef->onDelete == "Restrict") {
                    // check if objRef has records
                    $refObj = $this->getRefObject($objRef->objectName);
                    $sql = "`$column`='" . $refField->value . "'";
                    if ($column2 && $fieldVal2) {
                        $sql .= " AND " . $column2 . "='" . $fieldVal2 . "'";
                    }
                    if (count($refObj->directFetch($sql, 1)) == 1) {
                        throw new Openbizx\Data\Exception($this->getMessage("DATA_UNABLE_DEL_REC_CASCADE", array($objRef->objectName)));
                    }
                    return;
                }
            } else if ($cascadeType == 'Update') {
                // check if the column value is actually changed
                if ($refField->oldValue == $refField->value)
                    return;

                if ($objRef->onUpdate == "Cascade") {
                    $sql = "UPDATE " . $table . " SET $column='" . $refField->value . "' WHERE " . $column . "='" . $refField->oldValue . "'";
                    if ($column2 && $fieldVal2) {
                        $sql .= " AND " . $column2 . "='" . $fieldVal2 . "'";
                    }
                } else if ($objRef->onUpdate == "SetNull") {
                    $sql = "UPDATE " . $table . " SET $column=null WHERE " . $column . "='" . $refField->oldValue . "'";
                    if ($column2 && $fieldVal2) {
                        $sql .= " AND " . $column2 . "='" . $fieldVal2 . "'";
                    }
                } else if ($objRef->onUpdate == "Restrict") {
                    // check if objRef has records
                    $refObj = Openbizx::getObject($objRef->objectName);
                    $sql = "[" . $objRef->fieldRef . "]='" . $refField->oldValue . "'";
                    if ($column2 && $fieldVal2) {
                        $sql .= " AND " . $column2 . "='" . $fieldVal2 . "'";
                    }
                    if (count($refObj->directFetch($sql, 1)) == 1) {
                        throw new Openbizx\Data\Exception($this->getMessage("DATA_UNABLE_UPD_REC_CASCADE", array($objRef->objectName)));
                    }
                    return;
                }
            }
            try {
                Openbizx::$app->getLog()->log(LOG_DEBUG, "DATAOBJ", "Cascade $cascadeType Sql = $sql");
                $db->query($sql);
            } catch (Exception $e) {
                Openbizx::$app->getLog()->log(LOG_Err, "DATAOBJ", "Cascade $cascadeType Error: " . $e->getMessage());
                $this->errorMessage = $this->getMessage("DATA_ERROR_QUERY") . ": " . $sql . ". " . $e->getMessage();
                throw new Openbizx\Data\Exception($this->errorMessage);
            }
        }
    }

    /**
     * Run cascade delete
     * @return void
     */
    protected function cascadeDelete()
    {
        foreach ($this->objReferences as $objRef) {
            $this->processCascadeAction($objRef, "Delete");
        }
    }

    /**
     * Run cascade update
     * @return void
     */
    protected function cascadeUpdate()
    {
        foreach ($this->objReferences as $objRef) {
            $this->processCascadeAction($objRef, "Update");
        }
    }

    /**
     * Get auditable fields
     *
     * @return array list of {@link BizField} objects who are auditable
     */
    public function getOnAuditFields()
    {
        $fieldList = array();
        foreach ($this->bizRecord as $field) {
            if ($field->onAudit)
                $fieldList[] = $field;
        }
        return $fieldList;
    }

    /**
     * Run DataObject trigger
     *
     * @param string $triggerType type of the trigger
     */
    private function _runDOTrigger($triggerType)
    {
        // locate the trigger metadata file BOName_Trigger.xml
        $triggerServiceName = $this->objectName . "_Trigger";
        $xmlFile = ObjectFactoryHelper::getXmlFileWithPath($triggerServiceName);
        if (!$xmlFile) {
            return;
        }

        $triggerService = Openbizx::getObject($triggerServiceName);
        if ($triggerService == null) {
            return;
        }
        // invoke trigger service ExecuteTrigger($triggerType, $currentRecord)

        $triggerService->execute($this, $triggerType);
    }

    /**
     * Get all fields that belong to the same join of the input field
     *
     * @param BizDataObj $joinDataObj the join data object
     * @return array joined fields array
     */
    public function getJoinFields($joinDataObj)
    {
        // get the maintable of the joindataobj
        $joinTable = $joinDataObj->mainTableName;
        $returnRecord = array();

        // find the proper join according to the maintable
        foreach ($this->tableJoins as $tableJoin) {
            if ($tableJoin->table == $joinTable) {
                // populate the column-fieldvalue to columnRef-fieldvalue
                // get the field mapping to the column, then get the field value
                $joinFieldName = $joinDataObj->bizRecord->getFieldByColumn($tableJoin->column); // joined-main table

                if (!$joinFieldName) {
                    continue;
                }

                $refFieldName = $this->bizRecord->getFieldByColumn($tableJoin->columnRef); // join table
                $returnRecord[$refFieldName] = $joinFieldName;

                // populate joinRecord's field to current record
                foreach ($this->bizRecord as $field) {
                    if ($field->join == $tableJoin->objectName) {
                        // use join column to match joinRecord field's column
                        $jFieldName = $joinDataObj->bizRecord->getFieldByColumn($field->column); // joined-main table
                        $returnRecord[$field->objectName] = $jFieldName;
                    }
                }
                break;
            }
        }
        return $returnRecord;
    }

    /**
     * Pick the joined object's current record to the current record
     *
     * @param BizDataObj $joinDataObj
     * @param string $joinName name of join (optional)
     * @return array return a modified record with joined record data
     */
    public function joinRecord($joinDataObj, $joinName = "")
    {
        // get the maintable of the joindataobj
        $joinTable = $joinDataObj->mainTableName;
        $joinRecord = null;
        $returnRecord = array();

        // find the proper join according to join name and the maintable
        foreach ($this->tableJoins as $tableJoin) {
            if (($joinName == $tableJoin->objectName || $joinName == "") && $tableJoin->table == $joinTable) {
                // populate the column-fieldvalue to columnRef-fieldvalue
                // get the field mapping to the column, then get the field value
                $joinFieldName = $joinDataObj->bizRecord->getFieldByColumn($tableJoin->column); // joined-main table
                if (!$joinFieldName)
                    continue;
                if (!$joinRecord)
                    $joinRecord = $joinDataObj->getActiveRecord();
                $refFieldName = $this->bizRecord->getFieldByColumn($tableJoin->columnRef); // join table
                $returnRecord[$refFieldName] = $joinRecord[$joinFieldName];
                // populate joinRecord's field to current record
                foreach ($this->bizRecord as $fld) {
                    if ($fld->join == $tableJoin->objectName) {
                        // use join column to match joinRecord field's column
                        $jfldname = $joinDataObj->bizRecord->getFieldByColumn($fld->column); // joined-main table
                        $returnRecord[$fld->objectName] = $joinRecord[$jfldname];
                    }
                }
                break;
            }
        }
        // return a modified record with joined record data
        return $returnRecord;
    }

    /**
     * Add a new record to current record set
     *
     * @param array $recArr
     * @param boolean $isParentObjUpdated
     * @return boolean
     */
    public function addRecord($recArr, &$isParentObjUpdated)
    {
        $oldBaseSearchRule = $this->baseSearchRule;
        $this->baseSearchRule = "";
        $result = BizDataObj_Assoc::addRecord($this, $recArr, $isParentObjUpdated);
        //$this->baseSearchRule=$oldBaseSearchRule;
        return $result;
    }

    /**
     * Remove a record from current record set of current association relationship
     *
     * @param array $recArr
     * @param boolean &$isParentObjUpdated
     * @return boolean
     */
    public function removeRecord($recArr, &$isParentObjUpdated)
    {
        return BizDataObj_Assoc::removeRecord($this, $recArr, $isParentObjUpdated);
    }

    /**
     * Clean chache
     *
     * @global BizSystem $g_BizSystem
     * @return void
     */
    public function cleanCache()
    {
        if ($this->cacheLifeTime > 0) {
            $cacheSvc = Openbizx::getService(CACHE_SERVICE, 1);
            $cacheSvc->init($this->objectName, $this->cacheLifeTime);
            $cacheSvc->cleanAll();
        }
    }

    /**
     * Is need to generate Id?
     *
     * @param array $recArr array of record
     * @return boolean
     */
    private function _isNeedGenerateId($recArr)
    {
        if ($this->idGeneration != 'None' && (!$recArr["Id"] || $recArr["Id"] == "")) {
            return true;
        }
        if ($this->idGeneration == 'Identity') {
            return true;
        }
    }

}


<?php

namespace Environaut\Runner;

use Environaut\Cache\IReadOnlyCache;
use Environaut\Checks\ICheck;
use Environaut\Command\Command;
use Environaut\Config\IConfig;
use Environaut\Config\Parameters;
use Environaut\Report\IReport;
use Environaut\Report\Results\IResult;
use Environaut\Runner\IRunner;

/**
 * Reads checks from the config, executes them in that order and compiles the results into a report.
 */
class Runner implements IRunner
{
    /**
     * Default namespaced class name to use for checks if none is specified in the check definition of the config.
     */
    const DEFAULT_CHECK_IMPLEMENTOR = 'Environaut\Checks\Configurator';

    /**
     * @var IConfig current config
     */
    protected $config;

    /**
     * @var Command environaut command
     */
    protected $command;

    /**
     * @var IReport current report
     */
    protected $report;

    /**
     * @var Parameters
     */
    protected $parameters;

    /**
     * @var IReadOnlyCache cache that checks may use for cached settings (storage and retrieval)
     */
    protected $readonly_cache;

    public function __construct()
    {
        $this->parameters = new Parameters();
    }

    /**
     * Execute the checks that are defined in the config
     * and generate a report to consume by others.
     */
    public function run()
    {
        $successful = true;

        $this->initReport();

        $checks = array();
        foreach ($this->config->getCheckDefinitions() as $check_definition) {
            $checks[] = $this->getCheckInstance($check_definition);
        }

        $progress = $this->command->getHelperSet()->get('progress');
        $progress->setFormat(' %current%/%max% [%bar%] %percent%% Elapsed: %elapsed% ');

        $progress->start($this->command->getOutput(), count($checks));

        // run all checks defined in the configuration
        foreach ($checks as $check) {
            // process the check
            $succeeded = (bool) $check->run();

            // collect the result
            $result = $check->getResult();

            if (!$result instanceof IResult) {
                throw new \LogicException(
                    'The result of check "' . $check->getName() . '" (group "' . $check->getGroup() . '", class "' .
                    get_class($check) . '") must implement IResult.'
                );
            }

            // mark the check's result as success or failure
            if (!$succeeded) {
                $result->setStatus(IResult::FAIL);
            } else {
                $result->setStatus(IResult::SUCCESS);
            }

            // add the check's result to the report
            $this->report->addResult($result);

            $successful &= $succeeded;

            $progress->advance();
        }

        $progress->finish();

        return $successful;
    }

    /**
     * Returns a new check instance based on the given parameters (from config).
     *
     * @param array $parameters check definition parameters
     *
     * @return ICheck instance
     */
    protected function getCheckInstance(array $parameters = array())
    {
        $params = new Parameters($parameters);

        $check_implementor = $params->get(IConfig::PARAM_CLASS, self::DEFAULT_CHECK_IMPLEMENTOR);

        $check = new $check_implementor();

        if (!$check instanceof ICheck) {
            throw new \InvalidArgumentException(
                'The given check class "' . $check_implementor . '" does not implement ICheck.'
            );
        }

        $check->setCommand($this->command);
        $check->setCache($this->readonly_cache);

        $check->setName($params->get(IConfig::PARAM_NAME));
        $check->setGroup($params->get(IConfig::PARAM_GROUP));
        $check->setParameters($params);

        return $check;
    }

    /**
     * Initializes the internal report instance being used to collect the results of the checks.
     *
     * @return IReport report instance
     */
    protected function initReport()
    {
        $report_implementor = $this->config->getReportImplementor();
        $report = new $report_implementor();

        if (!$report instanceof IReport) {
            throw new \InvalidArgumentException(
                'The given report class "' . $report_implementor . '" does not implement IReport.'
            );
        }

        $this->report = $report;
        $this->report->setParameters(new Parameters($this->config->get('report', array())));

        return $this->report;
    }

    /**
     * Returns the report that contains the results of the checks.
     *
     * @return IReport report created by the runner
     */
    public function getReport()
    {
        return $this->report;
    }

    /**
     * Sets the given runtime parameters on the runner.
     *
     * @param Parameters $parameters runtime parameters understood by the runner
     */
    public function setParameters(Parameters $parameters)
    {
        $this->parameters = $parameters;
    }

    /**
     * Sets the given config on the runner.
     *
     * @param IConfig $config config data
     */
    public function setConfig(IConfig $config)
    {
        $this->config = $config;
    }

    /**
     * Sets the readonly cache used by checks to determine if they've been run before and
     * if they can reuse prior settings to let users just confirm settings etc.
     *
     * @param IReadOnlyCache $cache instance that contains all cached settings for checks
     */
    public function setCache(IReadOnlyCache $cache)
    {
        $this->readonly_cache = $cache;
    }

    /**
     * Sets the command on the runner to have
     * access to the input and output.
     *
     * @param Command $command
     */
    public function setCommand(Command $command)
    {
        $this->command = $command;
    }
}


<?php

namespace Limber\Kernel;

use Limber\Exceptions\MethodNotAllowedHttpException;
use Limber\Exceptions\NotFoundHttpException;
use Limber\Middleware\MiddlewareManager;
use Limber\Router\Route;
use Limber\Router\Router;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class HttpKernel
{
    /**
     * Router instance.
     *
     * @var Router
     */
    protected $router;

    /**
     * Global middleware to execute on each HTTP request.
     *
     * @var array<string>
     */
    protected $middleware = [];

    /**
     * HttpKernel constructor
     *
     * @param Router $router
     */
    public function __construct(Router $router)
    {
        $this->router = $router;
    }

    /**
     * Resolve to a Route instance or throw exception
     *
     * @param Request $request
     * @throws NotFoundHttpException
     * @throws MethodNotAllowedHttpException
     * @return Route
     */
    private function resolveRoute(Request $request): Route
    {
        if( ($route = $this->router->resolve($request)) === null ){

            // 405 Method Not Allowed
            if( ($methods = $this->router->getMethodsForUri($request)) ){
                throw new MethodNotAllowedHttpException;
            }

            // 404 Not Found
            throw new NotFoundHttpException("Route not found");
        }

        return $route;
    }

    /**
     * Kernel invoker
     *
     * @param Request $request
     * @return Response
     */
    public function run(Request $request): Response
    {
        // Resolve the route
        $route = $this->resolveRoute($request);

        // Merge the path-based parameters into the request attributes
        $request->attributes->add($route->getPathParams($request->getPathInfo()));

        // Dispatch the request
        return $this->dispatch($request, $route);
    }

    /**
     * Dispatch a request
     *
     * @param Request $request
     * @return Response
     */
    public function dispatch(Request $request, Route $route): Response
    {
        // Build MiddlewareManager
        $middlewareManager = new MiddlewareManager(array_merge($this->middleware, $route->getMiddleware()));

        // Run the middleware stack
        return $middlewareManager->run($request, function(Request $request) use ($route): Response {

            // Callable/closure style route
            if( is_callable($route->getAction()) ){
                $action = $route->getAction();
            }

            // Class@Method style route
            elseif( is_string($route->getAction()) ) {
                $action = class_method($route->getAction());
            }
            else {
                throw new \Exception("Cannot dispatch route because target cannot be resolved.");
            }

            // Auto-resolve controller parameters
            $params = $this->resolveActionParameters($request, $action);

            return \call_user_func_array($action, $params);

        });
    }

    /**
     * Resolve the action parameters for dependency injection.
     *
     * @param Request $request
     * @param callable $target
     * @return array
     */
    private function resolveActionParameters(Request $request, callable $target): array
    {
        // Get the target's parameters
        if( is_array($target) ) {
            $functionParameters = (new \ReflectionClass(get_class($target[0])))->getMethod($target[1])->getParameters();
        }

        else{
            $functionParameters = (new \ReflectionFunction($target))->getParameters();
        }

        $params = [];

        /** @var \ReflectionParameter $parameter */
        foreach( $functionParameters as $parameter ){

            /**
             *
             * @NOTE We cast the ReflectionType to string because the ::getName() method does not appear in
             * PHP 7 until 7.1
             *
             */
            // Check container first for an instance of this parameter type
            if( $parameter->getType() &&
                (string) $parameter->getType() === Request::class ){
                $params[$parameter->getPosition()] = $request;
            }

            // Check request attributes for this parameter name
            elseif( $request->attributes->has($parameter->getName()) ){
                $params[$parameter->getPosition()] = $request->attributes->get($parameter->getName());
            }

            else {
                $params[$parameter->getPosition()] = null;
            }
        }

        return $params;
    }
}


<?php

namespace Environaut\Cache;

use Environaut\Cache\IReadOnlyCache;
use Environaut\Config\Parameters;
use Environaut\Report\Results\Settings\Setting;

class ReadOnlyCache implements IReadOnlyCache
{
    const DEFAULT_PATH = './';
    const DEFAULT_NAME = '.environaut';
    const DEFAULT_EXTENSION = '.cache';

    /**
     * @var string location of the cache file
     */
    protected $location = null;

    /**
     * @var Parameters runtime parameters
     */
    protected $parameters;

    /**
     * @var array of ISetting implementing settings
     */
    protected $settings = array();

    public function __construct()
    {
        $this->location = null;
        $this->parameters = new Parameters();
        $this->settings = array();
    }

    /**
     * Returns whether a cached value for a setting from the loaded cache exists, that matches the given criterias.
     *
     * @param string $name key of wanted setting
     * @param mixed $groups group name of setting, default is null and matches always
     * @param integer $flag setting type to match, default is null and matches always
     *
     * @return boolean true if value for that setting is in cache; false otherwise
     */
    public function has($name, $groups = null, $flag = null)
    {
        foreach ($this->settings as $setting) {
            if (($setting->getName() === $name) && $setting->matchesGroup($groups) && $setting->matchesFlag($flag)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Returns the first setting from the loaded cache that matches the given criterias.
     *
     * @param string $name key of wanted setting
     * @param mixed $groups group name of setting, default is null and matches always
     * @param integer $flag setting type to match, default is null and matches always
     *
     * @return ISetting|null matching setting
     */
    public function get($name, $groups = null, $flag = null)
    {
        $found = null;

        foreach ($this->settings as $setting) {
            if (($setting->getName() === $name) && $setting->matchesGroup($groups) && $setting->matchesFlag($flag)) {
                return $setting;
            }
        }

        return $found;
    }

    /**
     * Returns an array of settings matching the given criterias.
     *
     * @param mixed $groups name of a group or array of group names or null for all settings regardless of group
     * @param type $flag only return settings that match the given flag value
     *
     * @return array of setting instances matching the specification
     *
     * @throws \InvalidArgumentException if $groups is neither null nor a string or an array
     */
    public function getAll($groups = null, $flag = null)
    {
        $settings = array();

        if (null === $groups) {
            foreach ($this->settings as $setting) {
                $settings[] = $setting;
            }
        } elseif (is_string($groups) || is_array($groups)) {
            foreach ($this->settings as $setting) {
                if ($setting->matchesGroup($groups) && $setting->matchesFlag($flag)) {
                    $settings[] = $setting;
                }
            }
        } else {
            throw new \InvalidArgumentException(
                'Only a null value, a single string as group name or an array of group names are supported.'
            );
        }

        return $settings;
    }

    /**
     * Loads the settings from the configured or default location.
     *
     * @return boolean true, if reading from cache succeeded; false otherwise.
     *
     * @throws \InvalidArgumentException on invalid or broken cache file
     */
    public function load()
    {
        $location = $this->location;

        // no location given from commandline -> use config values or fallback to default location
        if (empty($location)) {
            $location = $this->parameters->get(
                'read_location',
                $this->parameters->get(
                    'location',
                    $this->getDefaultLocation()
                )
            );
        }

        $this->location = $location;

        if (!is_readable($location) || !is_file($location)) {
            return false;
        }

        $content = file_get_contents($location);

        if (false === $content) {
            return false;
        }

        $result = json_decode($content, true);

        if (null === $result) {
            throw new \InvalidArgumentException('Cache could not be decoded from file: ' . $location);
        }

        $items = array();
        foreach ($result as $setting) {
            $items[] = new Setting($setting['name'], $setting['value'], $setting['group'], $setting['flag']);
        }

        $this->settings = $items;

        return true;
    }

    /**
     * Sets the given location as the cache location to use.
     *
     * @param string $location cache file path
     *
     * @return ReadOnlyCache this instance for fluent API support
     *
     * @throws \InvalidArgumentException if location is not readable
     */
    public function setLocation($location)
    {
        if (!is_readable($location)) {
            throw new \InvalidArgumentException('Given cache location "' . $location . '" is not readable.');
        }

        $this->location = $location;

        return $this;
    }

    /**
     * Returns the location currently set on the cache.
     *
     * @return string cache file location currently configured
     */
    public function getLocation()
    {
        return $this->location;
    }

    /**
     * Runtime parameters to configure the cache operations.
     *
     * @param Parameters $parameters runtime parameters
     *
     * @return ReadOnlyCache this instance for fluent API support
     */
    public function setParameters(Parameters $parameters)
    {
        $this->parameters = $parameters;

        return $this;
    }

    /**
     * Returns the default location used for the cache file. Defaults to "./.environaut.cache".
     *
     * @return string file path and name
     */
    protected function getDefaultLocation()
    {
        return $this->getCurrentWorkingDirectory() . DIRECTORY_SEPARATOR .
            self::DEFAULT_PATH . self::DEFAULT_NAME . self::DEFAULT_EXTENSION;
    }

    /**
     * @return string current working directory
     */
    protected function getCurrentWorkingDirectory()
    {
        $dir = getcwd();

        if (false === $dir) {
            $dir = __DIR__; // fallback to folder of current class in case of strange errors
        }

        return $dir;
    }
}


<?php

namespace Interpro\Entrance\Extract;

use Interpro\Entrance\Contracts\Extract\Selection as SelectionInterface;
use Interpro\Extractor\Contracts\Load\Loader;
use Interpro\Extractor\Contracts\Selection\SelectionUnit;

class Selection implements SelectionInterface
{
    private $loader;
    private $unit;

    public function __construct(
        Loader $loader,
        SelectionUnit $unit
    )
    {
        $this->loader = $loader;
        $this->unit = $unit;
    }

    /**
     * @return \Interpro\Extractor\Collections\GroupCollection
     */
    public function get()
    {
        $type = $this->unit->getType();
        $name = $this->unit->getName();

        return $this->loader->loadGroupCollection($type, $name);
    }

    /**
     * @return int
     */
    public function count()
    {
        $type = $this->unit->getType();
        $name = $this->unit->getName();

        return $this->loader->countGroup($type, $name);
    }

    /**
     * @param string $field_path
     * @param string $value
     * @param string $or_union_name
     *
     * @return \Interpro\Entrance\Extract\Selection
     */
    public function moreThen($field_path, $value, $or_union_name = null)
    {
        $this->unit->moreThen($field_path, $value, $or_union_name);

        return $this;
    }

    /**
     * @param string $field_path
     * @param string $value
     * @param string $or_union_name
     *
     * @return \Interpro\Entrance\Extract\Selection
     */
    public function lessThan($field_path, $value, $or_union_name = null)
    {
        $this->unit->lessThan($field_path, $value, $or_union_name);

        return $this;
    }

    /**
     * @param string $field_path
     * @param string $min_x
     * @param string $max_x
     * @param string $or_union_name
     *
     * @return \Interpro\Entrance\Extract\Selection
     */
    public function inRange($field_path, $min_x, $max_x, $or_union_name = null)
    {
        $this->unit->inRange($field_path, $min_x, $max_x, $or_union_name);

        return $this;
    }

    /**
     * @param string $field_path
     * @param string $min_x
     * @param string $max_x
     * @param string $or_union_name
     *
     * @return \Interpro\Entrance\Extract\Selection
     */
    public function notInRange($field_path, $min_x, $max_x, $or_union_name = null)
    {
        $this->unit->notInRange($field_path, $min_x, $max_x, $or_union_name);

        return $this;
    }

    /**
     * @param string $field_path
     * @param string $value
     * @param string $or_union_name
     *
     * @return \Interpro\Entrance\Extract\Selection
     */
    public function eq($field_path, $value, $or_union_name = null)
    {
        $this->unit->eq($field_path, $value, $or_union_name);

        return $this;
    }

    /**
     * @param string $field_path
     * @param string $value
     * @param string $or_union_name
     *
     * @return \Interpro\Entrance\Extract\Selection
     */
    public function notEq($field_path, $value, $or_union_name = null)
    {
        $this->unit->notEq($field_path, $value, $or_union_name);

        return $this;
    }

    /**
     * @param string $field_path
     * @param string $value
     * @param string $or_union_name
     *
     * @return \Interpro\Entrance\Extract\Selection
     */
    public function like($field_path, $value, $or_union_name = null)
    {
        $this->unit->like($field_path, $value, $or_union_name);

        return $this;
    }

    /**
     * @param string $field_path
     * @param string $value
     * @param string $or_union_name
     *
     * @return \Interpro\Entrance\Extract\Selection
     */
    public function notLike($field_path, $value, $or_union_name = null)
    {
        $this->unit->notLike($field_path, $value, $or_union_name);

        return $this;
    }

    /**
     * @return \Interpro\Entrance\Extract\Selection
     */
    public function sortBy($field_name, $order = 'ASC')
    {
        $this->unit->sortBy($field_name, $order);

        return $this;
    }

    /**
     * @param int $value
     *
     * @return \Interpro\Entrance\Extract\Selection
     */
    public function skip($value)
    {
        $this->unit->skip($value);

        return $this;
    }

    /**
     * @param int $value
     *
     * @return \Interpro\Entrance\Extract\Selection
     */
    public function take($value)
    {
        $this->unit->take($value);

        return $this;
    }
}


<?php
/**
 * PleasingPrefixFilter.php
 */

namespace XQ\Pleasing\Filter;

use Assetic\Asset\AssetInterface;
use Assetic\Filter\FilterInterface;

/**
 * Pleasing and Assetic filter to prefix commonly used properties for usage in approximately the last four major browser
 * versions.
 *
 * This filter is simplistic in nature, and does not do fancy things like removing unneeded prefixes, looking up which
 * prefixes are needed, etc.  It is intended for situations in which you do not have the ability to use autoprefixer.
 *
 * @author  Aaron M Jones <am@jonesiscoding.com>
 * @version Pleasing Filters v1.0.18 (https://github.com/jonesiscoding/pleasing-filters)
 * @license MIT (https://github.com/jonesiscoding/pleasing-filters/blob/master/LICENSE)
 *
 * Class PleasingPrefixFilter
 * @package XQ\Pleasing\Filter
 */
class PleasingPrefixFilter implements FilterInterface
{
  const FIT_FILL = array(
      'fill-available' => array( '-webkit-fill-available', '-moz-available', 'fill-available' ),
      'fit-content'    => array( '-webkit-fit-content', '-moz-fit-content', 'fit-content' ),
      'max-content'    => array( '-webkit-max-content', '-moz-max-content', 'intrinsic', 'max-content' ),
      'min-content'    => array( '-webkit-min-content', '-moz-min-content', 'min-intrinsic', 'min-content' ),
  );

  /** @var array CSS Properties where the value is prefixed. */
  private $prefixValue = array(
      'display'    => array(
          'flex'        => array( '-webkit-flex', '-ms-flexbox', 'flex' ),
          'grid'        => array( '-ms-grid', 'grid' ),
          'inline-grid' => array( '-ms-inline-grid', 'inline-grid' ),
          'inline-flex' => array( '-webkit-inline-flex', '-ms-inline-flexbox', 'inline-flex' )
      ),
      'height'     => self::FIT_FILL,
      'max-height' => self::FIT_FILL,
      'min-height' => self::FIT_FILL,
      'max-width'  => self::FIT_FILL,
      'min-width'  => self::FIT_FILL,
      'width'      => self::FIT_FILL,
  );

  /** @var array CSS Properties where the property is prefixed. */
  private $prefixProperty = array(
      'flex-direction'        => array( '-webkit-flex-direction', '-ms-flex-direction', 'flex-direction' ),
      'flex-grow'             => array( '-webkit-flex-grow', '-ms-flex-positive', 'flex-grow' ),
      'flex-shrink'           => array( '-webkit-flex-shrink', '-ms-flex-negative', 'flex-shrink' ),
      'flex-basis'            => array( '-webkit-flex-basis', '-ms-flex-preferred-size', 'flex-basis' ),
      'flex-wrap'             => array( '-webkit-flex-wrap', '-ms-flex-wrap', 'flex-wrap' ),
      'flex-flow'             => array( '-webkit-flex-flow', '-ms-flex-flow', 'flex-flow' ),
      'order'                 => array( '-webkit-order', '-ms-flex-order', 'order' ),
      'transition'            => array( '-webkit-transition', '-o-transition', 'transition' ),
      'box-sizing'            => array( '-webkit-box-sizing', 'box-sizing' ),
      'column-count'          => array( '-webkit-column-count', 'column-count' ),
      'column-gap'            => array( '-webkit-column-gap', 'column-gap' ),
      'column-width'          => array( '-webkit-column-width', 'column-width' ),
      'column-rule'           => array( '-webkit-column-rule', 'column-rule' ),
      'user-select'           => array( '-webkit-user-select', '-moz-user-select', '-ms-user-select', 'user-select' ),
      'transform'             => array( '-webkit-transform', '-ms-transform', 'transform' ),
      'transform-origin'      => array( '-webkit-transform-origin', '-ms-transform-origin', 'transform-origin' ),
      'appearance'            => array( '-webkit-appearance', '-moz-appearance', 'appearance' ),
      'filter'                => array( '-webkit-filter', 'filter' ),
      'grid-template-columns' => array( '-ms-grid-columns', 'grid-template-columns' ),
      'grid-template-rows'    => array( '-ms-grid-rows', 'grid-template-rows' ),
      'grid-row-start'        => array( '-ms-grid-row', 'grid-row-start' ),
      'grid-column-start'     => array( '-ms-grid-column', 'grid-column-start' ),
      'grid-column'           => array( '-ms-grid-column', 'grid-column' ),
      'grid-row'              => array( '-ms-grid-row', 'grid-row' ),
      'justify-self'          => array( '-ms-grid-row-align', 'justify-self' ),
  );

  /** @var array CSS properties where a custom method is used to properly prefix. */
  private $prefixMethod = array(
      'flex'            => 'prefixFlex',
      'justify-content' => 'prefixJustifyContent',
      'align-items'     => 'prefixAlignItems',
      'align-content'   => 'prefixAlignContent',
      'align-self'      => 'prefixAlignSelf'
  );

  // region //////////////////////////////////////////////// Filter Interface Methods

  /**
   * {@inheritdoc}
   */
  public function filterDump( AssetInterface $asset )
  {
  }

  /**
   * {@inheritdoc}
   */
  public function filterLoad( AssetInterface $asset )
  {
    $assetPath = $asset->getSourcePath();
    $ext       = ( $assetPath ) ? pathinfo( $assetPath, PATHINFO_EXTENSION ) : false;

    $content = $asset->getContent();

    switch( $ext )
    {
      case "less":
      case "scss":
      case "css":
        $output = $this->prefixCss( $content );
        break;
      default:
        // Extension not recognized, or could not be read.  Leave content alone
        $output = $content;
        break;
    }

    $asset->setContent( $output );
  }

  // endregion ///////////////////////////////////////////// End Filter Interface Methods

  // region //////////////////////////////////////////////// Main Method

  /**
   * Finds individual CSS rules and evaluates them for needed prefixes, then replaces the rules with the prefixed rule
   * as needed.
   *
   * @param string $content   The CSS, without prefixes.
   *
   * @return string           The CSS with prefixes.
   */
  protected function prefixCss( $content )
  {
    $replaced = array();
    if( $rules = $this->getRules( $content ) )
    {
      foreach( $rules as $rule )
      {
        $prefixed = array();
        if( strpos( $content, $rule->getRaw() ) !== false && !in_array( $rule->getRaw(), $replaced ) )
        {

          if( array_key_exists( $rule->getProperty(), $this->prefixValue ) )
          {
            if( array_key_exists( $rule->getValue(), $this->prefixValue[ $rule->getProperty() ] ) )
            {
              $prefixed = $this->getPrefixRules( $rule->getProperty(), $this->prefixValue[ $rule->getProperty() ][ $rule->getValue() ], $rule->getBang() );
            }
          }
          elseif( array_key_exists( $rule->getProperty(), $this->prefixProperty ) )
          {
            $prefixed = $this->getPrefixRules( $this->prefixProperty[ $rule->getProperty() ], $rule->getValue(), $rule->getBang() );
          }
          elseif( array_key_exists( $rule->getProperty(), $this->prefixMethod ) )
          {
            $method = $this->prefixMethod[ $rule->getProperty() ];
            $prefixed  = $this->$method( $rule->getValue(), $rule->getBang() );
          }

          if( !empty( $prefixed ) )
          {
            $newRules = array();
            foreach( $prefixed as $pRule )
            {
              /** @var CssRule $pRule */
              $pRule->setTemplate( $rule->getTemplate() );
              $newRules[] = $pRule->getOutput();
            }

            $replaced[] = $rule->getRaw();
            $replacement = str_replace( $rule->getOutput(), implode( "\n", $newRules ), $rule->getRaw() );
            $content = str_replace($rule->getRaw(),$replacement,$content);

          }
        }
      }
    }

    return $content;
  }

  /**
   * @param $content
   *
   * @return CssRule[]
   */
  protected function getRules( $content )
  {
    $rules = array();
    if( preg_match_all( '#{((?:[^{}]++|(?R))*+)}#', $content, $groups, PREG_SET_ORDER ) )
    {
      foreach( $groups as $group )
      {
        if( strpos( $group[ 1 ], '{' ) === false )
        {
          $set = preg_split( '#(\r|\n)#', $group[ 1 ] );

          foreach( $set as $s )
          {
            if( !empty($s) && $rule = CssRule::fromString( $s ) )
            {
              $rules[] = $rule;
            }
          }
        }
        else
        {
          $rules = array_merge( $rules, $this->getRules( $group[ 1 ] ) );
        }
      }
    }

    return (!empty($rules)) ? $rules : null;
  }

  // endregion ///////////////////////////////////////////// End Main Method

  // region //////////////////////////////////////////////// Prefix Methods

  /**
   * Properly prefixes the 'align-items' property.
   *
   * @param string  $value  The value of the property.
   * @param null    $extra  !important or null
   *
   * @return array          The prefixed rules to replace the 'align-items' rule.
   */
  protected function prefixAlignItems( $value, $extra = null )
  {
    $prop[] = '-ms-flex-align';

    switch( $value )
    {
      case 'flex-start':
        $val[] = 'start';
        break;
      case 'flex-end':
        $val[] = 'end';
        break;
      default:
        $val[]  = $value;
        $prop[] = '-ms-grid-row-align';
        $val[]  = 'center';
        break;
    }

    $prop[] = '-webkit-align-items';
    $prop[] = 'align-items';
    $val[]  = $value;
    $val[]  = $value;

    return $this->getPrefixRules( $prop, $val, $extra );
  }

  /**
   * Properly prefixes the 'align-content' property.
   *
   * @param string  $value  The value of the property.
   * @param null    $extra  !important or null
   *
   * @return array          The prefixed rules to replace the 'align-content' rule.
   */
  protected function prefixAlignContent( $value, $extra = null )
  {
    $prop = array(
        '-webkit-align-content',
        '-ms-flex-line-pack',
        'align-content'
    );

    $val[] = $value;
    switch( $value )
    {
      case 'flex-start':
        $val[] = 'start';
        break;
      case 'flex-end':
        $val[] = 'end';
        break;
      case 'space-between':
        $val[] = 'justify';
        break;
      case 'space-around':
        $val[] = 'distribute';
        break;
      default:
        $val[] = $value;
        break;
    }

    $val[] = $value;

    return $this->getPrefixRules( $prop, $val, $extra );
  }

  /**
   * Properly prefixes the 'align-self' property.
   *
   * @param string  $value  The value of the property.
   * @param null    $extra  !important or null
   *
   * @return array          The prefixed rules to replace the 'align-self' rule.
   */
  protected function prefixAlignSelf( $value, $extra = null )
  {
    $prop = array(
        '-webkit-align-self',
        '-ms-flex-item-align',
        'align-self'
    );

    $val[] = $value;
    switch( $value )
    {
      case 'flex-start':
        $val[] = 'start';
        break;
      case 'flex-end':
        $val[] = 'end';
        break;
      default:
        $val[] = $value;
        break;
    }

    $val[] = $value;

    return $this->getPrefixRules( $prop, $val, $extra );
  }

  /**
   * Properly prefixes the 'flex' property & value.
   *
   * @param string  $value  The value of the property.
   * @param null    $extra  !important or null
   *
   * @return array          The prefixed rules to replace the 'flex' rule.
   */
  protected function prefixFlex( $value, $extra = null )
  {
    $parts = explode( " ", $value );
    if( count( $parts ) == 3 )
    {
      // Make sure there's a % after the basis to avoid IE10/11 Bugs.
      // 0px does not work because a minifier would remove it.
      //
      // https://github.com/philipwalton/flexbugs#4-flex-shorthand-declarations-with-unitless-flex-basis-values-are-ignored
      if( $parts[ 2 ] === 0 || $parts[ 2 ] === '0px' )
      {
        $parts[ 2 ] = '0%';
      }
    }

    $prop = array( '-webkit-flex', '-ms-flex', 'flex' );
    $val  = implode( ' ', $parts );

    return $this->getPrefixRules( $prop, $val, $extra );
  }

  /**
   * Properly prefixes the 'justify-content' property.
   *
   * @param string  $value  The value of the property.
   * @param null    $extra  !important or null
   *
   * @return array          The prefixed rules to replace the 'justify-content' rule.
   */
  protected function prefixJustifyContent( $value, $extra = null )
  {
    $prop = array(
        '-webkit-justify-content',
        '-ms-flex-pack',
        'justify-content'
    );

    $val[] = $value;
    switch( $value )
    {
      case 'flex-start':
        $val[] = 'start';
        break;
      case 'flex-end':
        $val[] = 'end';
        break;
      case 'space-between':
        $val[] = 'justify';
        break;
      case 'space-around':
        $val[] = 'distribute';
        break;
      default:
        $val[] = $value;
    }
    $val[] = $value;

    return $this->getPrefixRules( $prop, $val, $extra );
  }

  // region //////////////////////////////////////////////// Private Helper Methods

  /**
   * Interpets the given parameters into a set of CSS rules to insert in replacement of the rule being evaluated.
   *
   * The number of properties and values given will be matched up to the other.  For instance, if one property
   * is given, it will be duplicated to match the count of the number of values given and vice versa.
   *
   * @param array|string         $prop    The property or properties to use with the rules.
   * @param array|string|float   $val     The value or values to use with the rules.
   * @param string               $extra   Any extra additions to the rules, such as !important
   *
   * @return array                        The CSS rules to insert
   */
  private function getPrefixRules( $prop, $val, $extra = null )
  {
    $extra = ( empty( $extra ) ) ? null : ' ' . $extra;
    if( !is_array( $prop ) && is_array( $val ) )
    {
      $properties = array_fill( 0, count( $val ), $prop );
      $values     = $val;
    }
    elseif( !is_array( $val ) && is_array( $prop ) )
    {
      $values     = array_fill( 0, count( $prop ), $val );
      $properties = $prop;
    }
    else
    {
      $properties = $prop;
      $values     = $val;
    }

    $property = null;
    $value    = null;
    do
    {
      $property = ( !empty( $properties ) ) ? array_shift( $properties ) : $property;
      $value    = ( !empty( $values ) ) ? array_shift( $values ) : $property;

      $rules[] = new CssRule( $property, $value, $extra );
    }
    while( !empty( $properties ) && !empty( $values ) );

    return $rules;
  }

  // endregion ///////////////////////////////////////////// End Private Helper Methods
}


<?php

/**
 * Instaphp
 *
 * Copyright (c) 2011 randy sesser <randy@instaphp.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @author randy sesser <randy@instaphp.com>
 * @copyright 2011, randy sesser
 * @license http://www.opensource.org/licenses/mit-license The MIT License
 * @package Instaphp
 * @filesource
 */

namespace Instaphp\Instagram;

use Instaphp\Request;
use Instaphp\Response;

/**
 * Media
 * The Media class handles all media requests to the API
 * @package Instaphp
 * @version 1.0
 * @author randy sesser <randy@instaphp.com>
 */
class Media extends InstagramBase
{
    public function __construct($token = null, $config = array())
    {
        parent::__construct($token, $config);
        $this->api_path = '/media';
    }

    /**
     * Gets information about a particular media
     * @access public
     * @param int $media_id A media ID
     * @param string $token An access token
     * @return Response
     */
    public function Info($media_id)
    {
        return $this->Get($this->buildUrl($media_id));
    }

    /**
     * Searches the API
     * @access public
     * @param string $token An access token
     * @param Array $params An associative array of key/value pairs to pass to the API
     * @return Response
     */
    public function Search(Array $params = array())
    {

        if (isset($params['lat'])) {
            if (!isset($params['lng']) || empty($params['lng']))
                trigger_error('Longitude and Latitude are mutually inclusive in ' . __METHOD__, E_USER_ERROR);
        }
        if (isset($params['lng'])) {
            if (!isset($params['lat']) || empty($params['lat']))
                trigger_error('Longitude and Latitude are mutually inclusive in ' . __METHOD__, E_USER_ERROR);
        }

		if (!empty($params))
			$this->AddParams($params);

        return $this->Get($this->buildUrl('search'));
    }

	public function OEmbed($url)
	{
		$uri = $this->config['endpoint'] . '/' . $this->config['version'];
		return $this->Get($uri.'/oembed', array('url' => $url));
	}

    /**
     * Gets the recent popular media.
     * Note: This method does not appear to require authentication
     * @access public
     * @return Response
     */
    public function Popular()
    {
        return $this->Get($this->BuildUrl('popular'));
    }

    /**
     * Gets comments associated with a particular media
     * @access public
     * @param int $media_id A media ID
     * @param string $token An access token
     * @return Response
     */
    public function Comments($media_id)
    {
        return $this->Get($this->buildUrl($media_id . '/comments'));
    }

    /**
     * Adds a comment to a particular media
     * @access public
     * @param int $media_id A media ID
     * @param string $comment The text of the comment
     * @param string $token An access token
     * @return Response
     */
    public function Comment($media_id, $comment)
    {
        $this->AddParam('text', $comment);
        return $this->Post($this->buildUrl($media_id . '/comments'));
    }

    /**
     * Deletes a comment previously left on a particular media
     * @access public
     * @param int $media_id A media ID
     * @param int $comment_id The comment ID to delete
     * @param string $token An access token
     * @return Response
     */
    public function DeleteComment($media_id, $comment_id)
    {
        return $this->Delete($this->buildUrl($media_id . '/comments/' . $comment_id));
    }

    /**
     * Gets likes for a particular media
     * @access public
     * @param int $media_id A media ID
     * @param string $token An access token
     * @return Response
     */
    public function Likes($media_id)
    {
        return $this->Get($this->buildUrl($media_id . '/likes'));
    }

    /**
     * Likes a particular media
     * @access public
     * @param int $media_id A media ID
     * @param string $token An access token
     * @return Response
     */
    public function Like($media_id)
    {
        return $this->Post($this->buildUrl($media_id . '/likes'));
    }

    /**
     * Unlikes a particular media
     * @access public
     * @param int $media_id A media ID
     * @param string $token An access token
     * @return Response
     */
    public function Unlike($media_id)
    {
        return $this->Delete($this->buildUrl($media_id . '/likes'));
    }

}


<?php

/**
 * Instaphp
 *
 * Copyright (c) 2011 randy sesser <randy@instaphp.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @author randy sesser <randy@instaphp.com>
 * @copyright 2011, randy sesser
 * @license http://www.opensource.org/licenses/mit-license The MIT License
 * @package Instaphp
 * @filesource
 */

namespace Instaphp\Instagram;

use Instaphp\Request;
use Instaphp\Response;

/**
 * Instaphp Base Instagram class.
 * @package Instaphp
 * @version 1.0
 * @author randy <randy@instaphp.com>
 */
class InstagramBase
{

    /**
     * The Instaphp Config object
     * @var Config
     * @access protected
     */
    protected $config = null;
    /**
     * The base API path appended to the endpoint
     * @var string
     * @access protected
     */
    protected $api_path;
    /**
     * Parameters passed to the API
     * @var Array
     * @access protected
     */
    protected $default_params = array();
    /**
     * The access token used to authenticate API calls
     * @var string
     * @access protected
     */
    protected $access_token;
    /**
     * Our request object
     * @var Request
     * @access protected
     */
    protected $request;

	/**
	 * THE parameters array passed to the API call
	 *
	 * @var array
	 * @access public
	 */
	public $parameters = array();

    /**
     * Constructor.
     * If you inherit from this class, you must call the parent constructor
     * @access public
     */
    public function __construct($token = null, $config = array())
    {
        $this->config = $config;
        $this->default_params['client_id'] = $config['client_id'];

        if (!empty($token))
            $this->default_params['access_token'] = $token;

        $this->request = new Request($config);
    }

    /**
     * A convenience method for making Get requests via the request
     * @access protected
     * @param string $url A url in which to make a request
     * @param Array $params An associative array of key/value pairs to pass to the API
     * @return Response
     */
    protected function Get($url = null, $params = array())
    {
        if (empty($url))
            trigger_error('A URL is required in ' . __METHOD__, E_USER_ERROR);

		if (!empty($params))
			$this->AddParams($params);

        return $this->request->Get($url, array_merge($this->default_params, $this->parameters))->response;
    }

    /**
     * A convenience method for making POST request via the request object
     * @access protected
     * @param string $url A url in which to make a POST request
     * @param Array $params An associative array of key/value pairs to POST to the API
     * @return Response
     */
    protected function Post($url = null, $params = array())
    {
        if (empty($url))
            trigger_error('A URL is required in ' . __METHOD__, E_USER_ERROR);

		if (!empty($params))
			$this->AddParams($params);

        return $this->request->Post($url, array_merge($this->default_params, $this->parameters))->response;
    }

    /**
     * A convenience method for making DELETE requests via the request object
     * @access protected
     * @param string $url A url in which to make a DELETE request
     * @param Array $params An associative array of key/value pairs to pass to the API
     * @return Response
     */
    protected function Delete($url = null, $params = array())
    {
        if (empty($url))
            trigger_error('A URL is required in ' . __METHOD__, E_USER_ERROR);

		if (!empty($params))
			$this->AddParams($params);

        return $this->request->Delete($url, array_merge($this->default_params, $this->parameters))->response;
    }

    /**
     * A convenience method that builds a base URL to the Instagram API based on
     * values in the config.xml file and the $api_path property.
     * @access protected
     * @param string $path The path to append to the base URL to create the endpoint
     * @param string $action The 'action' to append to the endpoint (not always used, but available)
     * @return string The Instagram API endpoint
     */
    protected function BuildUrl($path = null, $action = null)
    {
        $uri = $this->config['endpoint'] . '/' . $this->config['version'];

        if (!empty($path) && substr($path, 0, 1) !== '/')
            $path = '/' . $path;

        $path = $this->api_path . $path;

        $uri .= $path;

        if (null !== $action) {
            if (substr($action, 0, 1) !== '/')
                $action = '/' . $action;

            if (substr($action, strlen($action) - 1, 1) !== '/')
                $action .= '/';

            $uri .= $action;
        }

        return $uri;
    }

    /**
     * A convenience method for bulk adding querystring parameters
     * to the API requests. Note that existing params will be over-written.
     * @access public
     * @param Array $params Associative array of key/value pairs to add
     * @return void
     */
    public function AddParams(Array $params = array())
    {
		$this->parameters = $params;
    }

    /**
     * A convenience method for adding a single parameter to the querystring
     * passed to the API. Note this will overwrite existing parameters with
     * the same name.
     * @access public
     * @param string $name The parameter name
     * @param string $value The value to pass
     * @return void
     */
    public function AddParam($name, $value)
    {
        if (!empty($name))
            $this->parameters[$name] = $value;
    }

    /**
     * A convenience method for removing parameters from the querystring.
     * @access public
     * @param string $name The name of the parameter to remove
     * @return void
     */
    public function RemoveParam($name)
    {
        if (isset($this->parameters[$name]))
            unset($this->parameters[$name]);
    }

}


<?php

namespace Interpro\QuickStorage\Laravel;

use Interpro\QuickStorage\Concept\JSONQueryAgent as JSONQueryAgentInterface;
use Interpro\QuickStorage\Concept\Param\GroupParam;
use Interpro\QuickStorage\Concept\Sorting\GroupSortingSet;
use Interpro\QuickStorage\Concept\Specification\GroupSpecificationSet;
use Interpro\QuickStorage\Laravel\Sorting\GroupSorting;
use Interpro\QuickStorage\Laravel\Sorting\RandomGroupSorting;
use Interpro\QuickStorage\Laravel\Specification\GroupSpecificationEq;
use Interpro\QuickStorage\Concept\QSource as QSourceInterface;

class JSONQueryAgent implements JSONQueryAgentInterface {

    private $groupSortingSet;
    private $groupSpecificationSet;
    private $groupParam;
    private $qSource;

    /**
     * @param  \Interpro\QuickStorage\Concept\Sorting\GroupSortingSet $groupSortingSet
     * @param  \Interpro\QuickStorage\Concept\Specification\GroupSpecificationSet $groupSpecificationSet
     * @param  \Interpro\QuickStorage\Concept\Param\GroupParam $groupParam
     * @param  \Interpro\QuickStorage\Concept\QSource $qSource
     * @return void
     */
    public function __construct(
        GroupSortingSet $groupSortingSet,
        GroupSpecificationSet $groupSpecificationSet,
        GroupParam $groupParam,
        QSourceInterface $qSource
    ){
        $this->groupSortingSet       = $groupSortingSet;
        $this->groupSpecificationSet = $groupSpecificationSet;
        $this->groupParam            = $groupParam;
        $this->qSource               = $qSource;
    }

    protected function setSorts($sorts)
    {
        foreach($sorts as $group_name=>$sort_arr)
        {
            $this->groupSortingSet->reset($group_name);

            if(is_array($sort_arr))
            {
                foreach($sort_arr as $field_name=>$sort_way)
                {
                    if($field_name == 'random')
                    {
                        $sort_obj = new RandomGroupSorting($group_name);
                    }else{
                        $sort_obj = new GroupSorting($group_name, $field_name, $sort_way);
                    }

                    $this->groupSortingSet->add($group_name, $sort_obj);
                }
            }
        }
    }

    protected function setEqSpecs($specs)
    {
        foreach($specs as $group_name=>$spec_arr)
        {
            $this->groupSpecificationSet->reset($group_name);

            if(is_array($spec_arr))
            {
                foreach($spec_arr as $field_name=>$spec_val)
                {
                    $spec_obj = new GroupSpecificationEq($group_name, $field_name, $spec_val);

                    $this->groupSpecificationSet->add($group_name, $spec_obj);
                }
            }
        }
    }

    protected function setParams($params)
    {
        foreach($params as $group_name=>$param_arr)
        {
            if(is_array($param_arr))
            {
                foreach($param_arr as $param_name=>$param_val)
                {
                    $this->groupParam->set($group_name, $param_name, $param_val);
                }
            }
        }
    }

    /**
     * Получить элемент блока с полями
     *
     * @param string $name
     * @param array $sorts
     * @param array $specs
     * @param array $params
     * @return array
     */
    public function getBlock($name, $sorts, $specs, $params=[])
    {
        $this->setSorts($sorts);

        $this->setEqSpecs($specs);

        $this->setParams($params);

        $block_array = $this->qSource->blockQuery($name);

        return $block_array;
    }

    /**
     * Получить коллекцию элементов группы по имени
     *
     * @param string $block_name
     * @param string $name
     * @param array $sorts
     * @param array $specs
     * @param array $params
     * @return array
     */
    public function getGroupFlat($block_name, $name, $sorts, $specs, $params=[])
    {
        $this->setSorts($sorts);

        $this->setEqSpecs($specs);

        $this->setParams($params);

        $group_array = $this->qSource->groupQuery($block_name, $name);

        return $group_array;
    }

}


<?php

 /**
 * (c) Bureau Pieper <piet@bureaupieper.nl>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Bureaupieper\StoreeClient\Client\Result;

/**
 * Class ContentResult
 * @package Bureaupieper\StoreeClient\Client\Result
 *
 * @method getMedia
 * @method getTitle
 * @method getContent
 * @method getId
 * @method getSort
 * @method getSlug
 * @method getSubtitle
 */
class ContentResult extends AbstractResult
{
    /**
     * To memmorize which placeholder is selected from the possible pool of multiple images
     *
     * @var int
     */
    private $placeholder_pick;

    /**
     * Returns the short content if provided or a substring of the normal version
     *
     * @return string
     */
    function getContentShort()
    {
        return $this['content_short'] ?: substr(strip_tags($this['content']), 0, 200);
    }

    /**
     * Content can be split by the tag [split] to open more options in the rendering of the layout, such
     * as creating a leader text from the first section.
     *
     * @param bool $forceArrayReturn    Always return array, whether the content can be split or not
     * @param int $maxSize              Remaining pieces will be glued together
     * @return array|null
     */
    function getContentSeparated($forceArrayReturn = false, $maxSize = null)
    {
        if (isset($this['meta']['content']['split'])) {
            $c = $this['meta']['content']['split'];
            if ($maxSize && $maxSize < count($c)) {
                array_splice($c, $maxSize-1, count($c)-1, implode('', array_slice($c, $maxSize-1)));
            }
            return $c;
        }
        if ($forceArrayReturn) {
            return [$this['content']];
        }
    }

    /**
     * Return the URL set in the dashboard if its set
     *
     * @return string|null
     */
    function getUrl()
    {
        return $this['meta']['content']['endpoint'];
    }

    /**
     * Get a medium by ID
     *
     * @param $id
     * @return null|array
     */
    function getMedium($id)
    {
        foreach($this['media'] as $medium) {
            if ($medium['id'] == $id) {
                return $medium;
            }
        }
    }

    /**
     * @return array
     */
    function getImages()
    {
        return $this->getFilteredMedia(['image']);
    }

    /**
     * Filter media by types
     *
     * @param array $filters    image|video|document|audio|other(binary attachments)
     */
    function getFilteredMedia(array $filters, $allowPlaceholder = true)
    {
        $col = [];
        foreach($this['media'] as $medium) {
            if (!isset($hasImage) && $medium['type'] == 'image') {
                $hasImage = true;
            }
            if (in_array($medium['type'], $filters)) {
                $col[] = $medium;
            }
        }

        // Add a placeholder if the image type was requested, and no images were found.
        if (in_array('image', $filters)
            && !isset($hasImage)
            && $allowPlaceholder
            && $this->getPlaceholder()) {
            $col[] = $this->getPlaceholder();
        }

        return $col;
    }

    /**
     * Did the user favourite an image?
     *
     * @return bool
     */
    function hasPreferredImage() {
        return (bool) $this['meta']['media']['preferred_image'];
    }

    /**
     * If there is a preferred image this one will be returned. If not, the first one of the
     * collection will be returned.
     *
     * If an $orientation is passed, @getPreferredImageByOrientation will be called as a fallback, this will allow
     * alot less boilerplate code in sitations where you might want the user' favourite image as the highest priority,
     * but the best fitting alternative to a certain orientation, if not.
     *
     * F.e.: A large header image:
     *
     * getPreferredImage('1080p', 'landscape')          Get the user-preferred image, and return the url to the source
     *                                                  of the '1080' format. Or give me the image that best fits the
     *                                                  'landscape' aspect. And if there is no image found at all, give me
     *                                                  a placeholder if possible.
     *
     * NB: Falls back to placeholders
     *
     * @param null $aspect                              Return the src string instead of the medium array
     * @param string|null $orientation                  portrait|landscape|null
     *
     * @return null|string|array
     */
    function getPreferredImage($aspect = null, $orientation = null)
    {
        // If theres no images, check for placeholders
        if (!$this->getFilteredMedia(['image'], false)) {
            if ($ph = $this->getPlaceholder()) {
                if ($aspect) {
                    return $ph['meta']['src'][$aspect];
                }
                return $ph;
            }
            return null;
        }

        if ($this->hasPreferredImage()) {
            $medium = $this->getMedium($this['meta']['media']['preferred_image']);
        }
        elseif ($orientation) {
            $medium = $this->getPreferredImageByOrientation($orientation);
        }
        else {
            $medium = $this['media'][0];
        }

        if ($aspect) {
            return $medium['meta']['src'][$aspect];
        }
        return $medium;
    }

    /**
     * These images defined server-side based on aspect ratio and dimensions.
     *
     * NB: Falls back to a possible placeholder.
     *
     * @param string $orientation       portrait|landscape
     * @param null $aspect
     *
     * @return array|string|null
     */
    function getPreferredImageByOrientation($orientation, $aspect = null)
    {
        // If theres no images, check for placeholders
        if (!$this->getFilteredMedia(['image'], false)) {
            if ($ph = $this->getPlaceholder()) {
                if ($aspect) {
                    return $ph['meta']['src'][$aspect];
                }
                return $ph;
            }
            return null;
        }

        $medium = $this->getMedium($this['meta']['media']['preferred_orientation'][$orientation]);
        if ($aspect) {
            return $medium['meta']['src'][$aspect];
        }
        return $medium;
    }

    /**
     * Returns an array of unique pages published to, because there can be multiple hotspots on the same page.
     *
     * @return array
     */
    function getPagesPublishedTo()
    {
        $pages = [];
        foreach($this['meta']['issue']['hotspots'] as $hotspot) {
            $pages[$hotspot['page']['slug']] = $hotspot['page'];
        }
        return $pages;
    }

    /**
     * Multiple placeholders can be set for a specific content-type, keep in mind that one will be
     * set for this session. Server-side relating a specific random placeholder as a preferred one is a WIP.
     */
    function getPlaceholder($index = null)
    {
        if (!isset($this['meta']['media']['placeholder'])) {
            return null;
        }
        if (!$this->placeholder_pick) {
            $this->placeholder_pick = rand(0, count($this['meta']['media']['placeholder']) - 1);
        }
        return $this['meta']['media']['placeholder'][$index ?: $this->placeholder_pick];
    }
}


<?PHP
/**
 * Openbizx Framework
 *
 * LICENSE
 *
 * This source file is subject to the BSD license that is bundled
 * with this package in the file LICENSE.txt.
 *
 * @package   openbiz.bin.easy.element
 * @copyright Copyright (c) 2005-2011, Rocky Swen
 * @license   http://www.opensource.org/licenses/bsd-license.php
 * @link      http://www.phpopenbiz.org/
 * @version   $Id: InputDate.php 2553 2010-11-21 08:36:48Z mr_a_ton $
 */

namespace Openbizx\Easy\Element;

use Openbizx\Openbizx;
use Openbizx\Easy\Element\InputText;

/**
 * InputDate class is element for input date with date picker
 *
 * @package openbiz.bin.easy.element
 * @author Rocky Swen
 * @copyright Copyright (c) 2005-2009
 * @access public
 */
class InputDateRangePicker extends InputText {

	public function getSearchRule(){
		$value = Openbizx::$app->getClientProxy()->getFormInputs($this->objectName);
		$field = $this->fieldName;

		$dates = explode("-", $value);
		$date_start = str_replace("/","-",trim($dates[0]))." 00:00:00";

		if(count($dates)==2){
			$date_end = str_replace("/","-",trim($dates[1]))." 23:59:59";
		}else{
			$date_end = str_replace("/","-",trim($dates[0]))." 23:59:59";
		}
		$searchRule = "([$field] >'$date_start' AND [$field]<'$date_end')";
		return $searchRule;
	}
    /**
     * Render / draw the element according to the mode
     *
     * @return string HTML text
     */
    public function render() {
    	$this->cssClass=null;
    	$this->cssErrorClass = null;
    	$this->cssHoverClass = null;

   		if($this->value!=null){
    		$value = $this->value;
    	}else{
    		$value = $this->getText();
    	}

    	if($value==""){
    		$value = $this->getDefaultValue();
    	}
        $events = $this->getEvents();

        $event_onchange = $events['onchange'];

        $sHTML = "

        <INPUT NAME=\"" . $this->objectName . "\" ID=\"" . $this->objectName ."\" VALUE=\"" . $value . "\" class=\"ui-rangepicker-input ui-widget-content\" style=\"border:none\"  />

        ";

        $sHTML .= "

        ";
        return $sHTML;
    }

}

?>


<?php
/**
 * CssRule.php
 */

namespace XQ\Pleasing\Filter;

/**
 * An entity representing a single CSS rule.
 *
 * Class CssRule
 *
 * @author  Aaron M Jones <am@jonesiscoding.com>
 * @version Pleasing Filters v1.0.18 (https://github.com/jonesiscoding/pleasing-filters)
 * @license MIT (https://github.com/jonesiscoding/pleasing-filters/blob/master/LICENSE)
 *
 * @package XQ\Pleasing\Filter
 */
class CssRule
{
  /** @var  string */
  protected $bang;
  /** @var  int */
  protected $indent;
  /** @var  string */
  protected $property;
  /** @var string */
  protected $raw;
  /** @var  string */
  protected $template;
  /** @var  string */
  protected $value;

  /**
   * @param string $property
   * @param string $value
   * @param string $bang
   */
  public function __construct( $property = null, $value = null, $bang = null)
  {
    $this->property = $property;
    $this->value    = $value;
    $this->bang     = $bang;
  }

  /**
   * Create a CssRule object from an existing CSS string.
   *
   * @param string $string
   *
   * @return null|CssRule
   */
  public static function fromString( $string )
  {
    if( preg_match( '#(\s+)?([^:]+):([^!;]+)([^;]+)?#', trim( $string, "\n\r" ), $matches ) )
    {
      $rule = new self();
      $rule
          ->setRaw($string)
          ->setProperty( ( !empty( $matches[ 2 ] ) ) ? trim( $matches[ 2 ] ) : null )
          ->setValue( ( !empty( $matches[ 3 ] ) ) ? trim( $matches[ 3 ] ) : null )
          ->setBang( ( !empty( $matches[ 4 ] ) ) ? trim( $matches[ 4 ] ) : null )
          ->setIndent( ( isset( $matches[ 1 ] ) ) ? strlen( $matches[ 1 ] ) : 0 )
      ;

      // Replace Property in Template
      $pattern  = "#(" . preg_quote( $rule->getProperty(), "#" ) . "([\s:]+))#";

      $template = preg_replace( $pattern, "%s$2", $matches[ 0 ] . ';' );

      // Replace Value in Template
      $pattern = "#(:([\s]+))" . preg_quote( $rule->getValue(), "#" ) . "#";
      $template = preg_replace(  $pattern, "$1%s", $template );

      // Replace Bang in Template
      $pattern  = "#([^!]+)" . preg_quote($rule->getBang(), "#") . ";#";
      $template = preg_replace( $pattern, "$1%s;", $template );

      return $rule->setTemplate( $template );
    }

    return null;
  }

  /**
   * Any !important, !default, !global addition to the CSS Rule, complete with !
   *
   * @return string
   */
  public function getBang()
  {
    return $this->bang;
  }

  /**
   * The number of spaces that the CSS rule should be indented.
   *
   * @return int
   */
  public function getIndent()
  {
    return $this->indent;
  }

  /**
   * The properly formatted CSS rule.
   * @return string
   */
  public function getOutput()
  {
    return sprintf( $this->getTemplate(), $this->getProperty(), $this->getValue(), $this->getBang() );
  }

  /**
   * The property uhm.. property.
   * @return string
   */
  public function getProperty()
  {
    return $this->property;
  }

  /**
   * The raw CSS string, prior to parsing, if set.
   *
   * @return string
   */
  public function getRaw()
  {
    return $this->raw;
  }

  /**
   * An sprintf template for recreating the CSS rule.  Arguments are property, value, bang.
   *
   * @return string
   */
  public function getTemplate()
  {
    return $this->template;
  }

  /**
   * The value of the CSS rule.
   *
   * @return string
   */
  public function getValue()
  {
    return $this->value;
  }

  /**
   * @param string $bang
   *
   * @return CssRule
   */
  public function setBang( $bang )
  {
    $this->bang = $bang;

    return $this;
  }

  /**
   * @param int $indent
   *
   * @return CssRule
   */
  public function setIndent( $indent )
  {
    $this->indent = $indent;

    return $this;
  }

  /**
   * @param string $property
   *
   * @return CssRule
   */
  public function setProperty( $property )
  {
    $this->property = $property;

    return $this;
  }

  /**
   * @param string $raw
   *
   * @return CssRule
   */
  public function setRaw( $raw )
  {
    $this->raw = $raw;

    return $this;
  }

  /**
   * @param string $template
   *
   * @return CssRule
   */
  public function setTemplate( $template )
  {
    $this->template = $template;

    return $this;
  }

  /**
   * @param string $value
   *
   * @return CssRule
   */
  public function setValue( $value )
  {
    $this->value = $value;

    return $this;
  }
}


<?php
/**
 * User  : Nikita Makarov
 * Date  : 1/5/16
 * E-Mail: mesaverde228@gmail.com
 *
 * @file
 * Description
 */

namespace Akuma\Bundle\UserBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;

class FosUserCompilerPass  implements CompilerPassInterface{

    /**
     * You can modify the container here before it is dumped to PHP code.
     *
     * @param ContainerBuilder $container
     */
    public function process(ContainerBuilder $container)
    {
        /** @var Definition $definition */
        $definition = $container->getDefinition('fos_user.user_manager.default');

        if('FOS\UserBundle\Doctrine\UserManager' === $definition->getClass()){
            $definition->setClass('Akuma\Bundle\UserBundle\Doctrine\UserManager');
        }

    }
}