<?php
namespace Nkey\Caribu\Mvc\View;

use \Nkey\Caribu\Mvc\Controller\Response;
use \Nkey\Caribu\Mvc\Controller\Request;
use \Nkey\Caribu\Mvc\View\View;

/**
 * Abstract view class
 *
 * This class provides some basic functions which are needed by every
 * concrete view class. It initializes the view by reading the
 * annotations from elements and provide them as settings.
 *
 * It also has the ability to check whether the view is responsible
 * for a particular request.
 *
 * All basic functions are final and cannot be overriden.
 *
 * @author Maik Greubel <greubel@nkey.de>
 *
 *         This file is part of Caribu MVC package
 */
abstract class AbstractView implements View
{

    /**
     * The name of view
     *
     * @var string
     */
    private $viewName;

    /**
     * List of allowed controllers
     *
     * @var array
     */
    private $controllers = array();

    /**
     * List of allowed actions
     *
     * @var array
     */
    private $actions = array();

    /**
     * List of view controls
     *
     * @var array
     */
    private $controls = array();

    /**
     * List of additional css files
     *
     * @var array
     */
    private $cssFiles = array();

    /**
     * List of additional javascript files
     *
     * @var array
     */
    private $jsFiles = array();

    /**
     * (non-PHPdoc)
     *
     * @see \Nkey\Caribu\Mvc\View\View::getOrder()
     */
    abstract public function getOrder();

    /**
     * (non-PHPdoc)
     *
     * @see \Nkey\Caribu\Mvc\View\View::render()
     */
    abstract public function render(Response &$response, Request $request, $parameters = array());

    /**
     * Retrieve the settings from view
     *
     * @return \Nkey\Caribu\Mvc\View\View
     */
    final public function getViewSettings()
    {
        $rf = new \ReflectionClass($this);

        $this->viewName = str_replace('View', '', $rf->getShortName());

        $matches = array();
        if (preg_match("#@applyTo\((.*)\)#", $rf->getDocComment(), $matches)) {
            $params = array();
            parse_str(str_replace(',', '&', $matches[1]), $params);

            if (is_array($params)) {
                foreach ($params as $param => $value) {
                    if ($param == 'controller') {
                        $this->controllers = explode('|', $value);
                    }

                    if ($param == 'action') {
                        $this->actions = explode('|', $value);
                    }
                }
            }
        }

        return $this;
    }

    /**
     * (non-PHPdoc)
     *
     * @see \Nkey\Caribu\Mvc\View\View::matchController()
     */
    final public function matchController($controller)
    {
        return (in_array($controller, $this->controllers) ||
				in_array('any', $this->controllers) ||
				count($this->controllers) == 0);
    }

    /**
     * (non-PHPdoc)
     *
     * @see \Nkey\Caribu\Mvc\View\View::matchAction()
     */
    final public function matchAction($action)
    {
        return (in_array($action, $this->actions) ||
        		in_array('any', $this->actions) ||
        		count($this->actions) == 0);
    }

    /**
     * (non-PHPdoc)
     *
     * @see \Nkey\Caribu\Mvc\View\View::matchBoth()
     */
    final public function matchBoth($controller, $action)
    {
        return $this->matchController($controller) && $this->matchAction($action);
    }

    /**
     * Get name of view
     *
     * @return string The name of view
     */
    final public function getViewSimpleName()
    {
        return $this->viewName;
    }

    /**
     * (non-PHPdoc)
     *
     * @see \Nkey\Caribu\Mvc\View\View::registerControl()
     */
    final public function registerControl($controlClass, $controlIdentifier)
    {
        $this->controls[$controlIdentifier] = $controlClass;
    }

    /**
     * (non-PHPdoc)
     *
     * @see \Nkey\Caribu\Mvc\View\View::createControl()
     */
    final public function createControl($controlIdentifier)
    {
        $rf = new \ReflectionClass($this->controls[$controlIdentifier]);
        return $rf->newInstance();
    }

    /**
     * (non-PHPdoc)
     *
     * @see \Nkey\Caribu\Mvc\View\View::hasControl()
     */
    final public function hasControl($controlIdentifier)
    {
        return isset($this->controls[$controlIdentifier]);
    }

    /**
     * (non-PHPdoc)
     *
     * @see \Nkey\Caribu\Mvc\View\View::setCssFiles()
     */
    final public function setCssFiles(array $files)
    {
        $this->cssFiles = $files;
        return $this;
    }

    /**
     * (non-PHPdoc)
     *
     * @see \Nkey\Caribu\Mvc\View\View::setJsFiles()
     */
    final public function setJsFiles(array $files)
    {
        $this->jsFiles = $files;
        return $this;
    }

    /**
     * Retrieve all js files
     *
     * @return array
     */
    final protected function getJsFiles()
    {
        return $this->jsFiles;
    }

    /**
     * Retrieve all css files
     *
     * @return array
     */
    final protected function getCssFiles()
    {
        return $this->cssFiles;
    }
}


<?php

namespace Yab\Cerebrum;

use Carbon\Carbon;
use Illuminate\Support\Facades\Cache;

trait Memory
{
    /**
     * Memory duration.
     *
     * @var int
     */
    protected $memoryDuration = 15;

    /**
     * Methods that can be forgetten
     * when the forget method is called.
     *
     * @var array
     */
    protected $forgetful = [];

    /**
     * Forget the cached value.
     *
     * @param array $args
     *
     * @return mixed
     */
    public function forget($args = [])
    {
        if (!empty($args)) {
            if (is_array($args)) {
                $args = implode('_', $args);
            }
            if (empty($this->forgetful)) {
                $this->forgetful = get_class_methods($this);
            }

            foreach ($this->forgetful as $method) {
                $cacheKey = str_replace('\\', '_', get_class($this).'_'.$method.'_');
                $this->forgetByKey($cacheKey);
                $cacheKey = str_replace('\\', '_', get_class($this).'_'.$method.'_'.$args);
                $this->forgetByKey($cacheKey);
            }
        } else {
            $key = $this->getRememberKey();
            $this->forgetByKey($key);
        }

        return $this;
    }

    /**
     * Remember the value.
     *
     * @param mixed $value
     * @param int   $memoryDuration
     *
     * @return mixed
     */
    public function remember($value, $memoryDuration = null)
    {
        if (is_null($memoryDuration)) {
            $memoryDuration = $this->memoryDuration;
        }

        $key = $this->getRememberKey();

        if (Cache::has($key)) {
            $value = Cache::get($key);
        } else {
            $expiresAt = Carbon::now()->addMinutes($memoryDuration);

            if (is_callable($value)) {
                $value = $value();
            }

            Cache::put($key, $value, $expiresAt);
        }

        return $value;
    }

    /**
     * Forget something by key.
     *
     * @param string $key
     *
     * @return bool
     */
    protected function forgetByKey($key)
    {
        $result = false;

        if (Cache::has($key)) {
            $result = Cache::forget($key);
        }

        return $result;
    }

    /**
     * get the cache key.
     *
     * @return string
     */
    protected function getRememberKey()
    {
        $backtrace = debug_backtrace(4)[2];
        $args = implode('_', $backtrace['args']);
        $key = str_replace('\\', '_', get_class($this).'_'.$backtrace['function'].'_'.$args);

        return $key;
    }
}


<?php

/**
 * TechDivision\Import\Configuration\Jms\ConfigurationFactory
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Open Software License (OSL 3.0)
 * that is available through the world-wide-web at this URL:
 * http://opensource.org/licenses/osl-3.0.php
 *
 * PHP version 5
 *
 * @author    Tim Wagner <t.wagner@techdivision.com>
 * @copyright 2016 TechDivision GmbH <info@techdivision.com>
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
 * @link      https://github.com/techdivision/import-configuration-jms
 * @link      http://www.techdivision.com
 */

namespace TechDivision\Import\Configuration\Jms;

use JMS\Serializer\SerializerBuilder;
use TechDivision\Import\ConfigurationFactoryInterface;
use TechDivision\Import\Configuration\Jms\Configuration\Params;

/**
 * The configuration factory implementation.
 *
 * @author    Tim Wagner <t.wagner@techdivision.com>
 * @copyright 2016 TechDivision GmbH <info@techdivision.com>
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
 * @link      https://github.com/techdivision/import-configuration-jms
 * @link      http://www.techdivision.com
 */
class ConfigurationFactory implements ConfigurationFactoryInterface
{

    /**
     * Factory implementation to create a new initialized configuration instance.
     *
     * @param string $filename   The configuration filename
     * @param string $format     The format of the configuration file, either one of json, yaml or xml
     * @param string $params     A serialized string with additional params that'll be passed to the configuration
     * @param string $paramsFile A filename that contains serialized data with additional params that'll be passed to the configuration
     *
     * @return \TechDivision\Import\Configuration\Jms\Configuration The configuration instance
     * @throws \Exception Is thrown, if the specified configuration file doesn't exist
     */
    public function factory($filename, $format = 'json', $params = null, $paramsFile = null)
    {

        // try to load the JSON data
        if ($data = file_get_contents($filename)) {
            // initialize the JMS serializer, load and return the configuration
            return $this->factoryFromString($data, $format, $params, $paramsFile);
        }

        // throw an exception if the data can not be loaded from the passed file
        throw new \Exception(sprintf('Can\'t load configuration file %s', $filename));
    }

    /**
     * Factory implementation to create a new initialized configuration instance.
     *
     * @param string $data       The configuration data
     * @param string $format     The format of the configuration data, either one of json, yaml or xml
     * @param string $params     A serialized string with additional params that'll be passed to the configuration
     * @param string $paramsFile A filename that contains serialized data with additional params that'll be passed to the configuration
     *
     * @return \TechDivision\Import\Configuration\Jms\Configuration The configuration instance
     */
    public function factoryFromString($data, $format = 'json', $params = null, $paramsFile = null)
    {

        // initialize the JMS serializer, load and return the configuration
        $data = $this->toArray($data, Configuration::class, $format);

        // merge the params, if specified with the --params option
        if ($params) {
            $this->mergeParams(
                $data,
                $this->toArray(
                    $params,
                    Params::class,
                    $format
                )
            );
        }

        // merge the param loaded from the file, if specified with the --params-file option
        if ($paramsFile && is_file($paramsFile)) {
            $this->mergeParams(
                $data,
                $this->toArray(
                    file_get_contents($paramsFile),
                    Params::class,
                    pathinfo($paramsFile, PATHINFO_EXTENSION)
                )
            );
        }

        // finally, create and return the configuration from the merge data
        return SerializerBuilder::create()->build()->fromArray($data, Configuration::class);
    }

    /**
     * Creates and returns an array/object tree from the passed array.
     *
     * @param array  $data The data to create the object tree from
     * @param string $type The object type to create
     *
     * @return mixed The array/object tree from the passed array
     */
    protected function fromArray(array $data, $type)
    {
        return SerializerBuilder::create()->build()->fromArray($data, $type);
    }

    /**
     * Deserializes the data, converts it into an array and returns it.
     *
     * @param string $data   The data to convert
     * @param string $type   The object type for the deserialization
     * @param string $format The data format, either one of JSON, XML or YAML
     *
     * @return array The data as array
     */
    protected function toArray($data, $type, $format)
    {

        // load the serializer builde
        $serializer = SerializerBuilder::create()->build();

        // deserialize the data, convert it into an array and return it
        return $serializer->toArray($serializer->deserialize($data, $type, $format));
    }

    /**
     * Merge the additional params in the passed configuration data.
     *
     * @param array $data   The array with configuration data
     * @param array $params The array with additional params to merge
     *
     * @return void
     */
    protected function mergeParams(&$data, $params)
    {

        // merge the passed params into the configuration data
        foreach ($params as $paramName => $paramValue) {
            if (is_array($paramValue)) {
                foreach ($paramValue as $key => $value) {
                    foreach ($value as $name => $x) {
                        $data[$paramName][$key][$name] = $x;
                    }
                }
            } else {
                $data[$paramName] = $paramValue;
            }
        }
    }
}


<?php

/**
 * TechDivision\Import\Configuration\Jms\Configuration\Subject
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Open Software License (OSL 3.0)
 * that is available through the world-wide-web at this URL:
 * http://opensource.org/licenses/osl-3.0.php
 *
 * PHP version 5
 *
 * @author    Tim Wagner <t.wagner@techdivision.com>
 * @copyright 2016 TechDivision GmbH <info@techdivision.com>
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
 * @link      https://github.com/techdivision/import-configuration-jms
 * @link      http://www.techdivision.com
 */

namespace TechDivision\Import\Configuration\Jms\Configuration;

use JMS\Serializer\Annotation\Type;
use JMS\Serializer\Annotation\SerializedName;
use JMS\Serializer\Annotation\PostDeserialize;
use TechDivision\Import\ConfigurationInterface;
use TechDivision\Import\Configuration\SubjectConfigurationInterface;
use TechDivision\Import\Configuration\Jms\Configuration\Subject\FileResolver;
use TechDivision\Import\Configuration\Jms\Configuration\Subject\ImportAdapter;
use TechDivision\Import\Configuration\Jms\Configuration\Subject\ExportAdapter;
use TechDivision\Import\Configuration\Jms\Configuration\Subject\DateConverter;
use TechDivision\Import\Configuration\Jms\Configuration\Subject\NumberConverter;
use TechDivision\Import\Configuration\Jms\Configuration\Subject\FilesystemAdapter;

/**
 * The subject configuration implementation.
 *
 * @author    Tim Wagner <t.wagner@techdivision.com>
 * @copyright 2016 TechDivision GmbH <info@techdivision.com>
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
 * @link      https://github.com/techdivision/import-configuration-jms
 * @link      http://www.techdivision.com
 */
class Subject implements SubjectConfigurationInterface
{

    /**
     * The trait that provides parameter handling functionality.
     *
     * @var \TechDivision\Import\Configuration\Jms\Configuration\ParamsTrait
     */
    use ParamsTrait;

    /**
     * The subject's unique DI identifier.
     *
     * @var string
     * @Type("string")
     * @SerializedName("id")
     */
    protected $id;

    /**
     * The array with the subject's observers.
     *
     * @var array
     * @Type("array")
     */
    protected $observers = array();

    /**
     * The array with the subject's callbacks.
     *
     * @var array
     * @Type("array<string, array>")
     */
    protected $callbacks = array();

    /**
     * The array with the subject's frontend input callbacks.
     *
     * @var array
     * @Type("array<string, array>")
     * @SerializedName("frontend-input-callbacks")
     */
    protected $frontendInputCallbacks = array();

    /**
     * A reference to the parent configuration instance.
     *
     * @var \TechDivision\Import\ConfigurationInterface
     */
    protected $configuration;

    /**
     * The flag to signal that the subjects needs a OK file to be processed or not.
     *
     * @var boolean
     * @Type("boolean")
     * @SerializedName("ok-file-needed")
     */
    protected $okFileNeeded = false;

    /**
     *The flag to signal that the subject has to create a .imported flagfile or not.
     *
     * @var boolean
     * @Type("boolean")
     * @SerializedName("create-imported-file")
     */
    protected $createImportedFile = true;

    /**
     * The import adapter configuration instance.
     *
     * @var \TechDivision\Import\Configuration\Subject\ImportAdapterConfigurationInterface
     * @Type("TechDivision\Import\Configuration\Jms\Configuration\Subject\ImportAdapter")
     * @SerializedName("import-adapter")
     */
    protected $importAdapter;

    /**
     * The export adapter configuration instance.
     *
     * @var \TechDivision\Import\Configuration\Subject\ExportAdapterConfigurationInterface
     * @Type("TechDivision\Import\Configuration\Jms\Configuration\Subject\ExportAdapter")
     * @SerializedName("export-adapter")
     */
    protected $exportAdapter;

    /**
     * The filesystem adapter configuration instance.
     *
     * @var \TechDivision\Import\Configuration\Subject\FilesystemAdapterConfigurationInterface
     * @Type("TechDivision\Import\Configuration\Jms\Configuration\Subject\FilesystemAdapter")
     * @SerializedName("filesystem-adapter")
     */
    protected $filesystemAdapter;

    /**
     * The file resolver configuration instance.
     *
     * @var \TechDivision\Import\Configuration\Subject\FileResolverConfigurationInterface
     * @Type("TechDivision\Import\Configuration\Jms\Configuration\Subject\FileResolver")
     * @SerializedName("file-resolver")
     */
    protected $fileResolver;

    /**
     * The number converter configuration instance.
     *
     * @var \TechDivision\Import\Configuration\Subject\NumberConverterConfigurationInterface
     * @Type("TechDivision\Import\Configuration\Jms\Configuration\Subject\NumberConverter")
     * @SerializedName("number-converter")
     */
    protected $numberConverter;

    /**
     * The date converter configuration instance.
     *
     * @var \TechDivision\Import\Configuration\Subject\DateConverterConfigurationInterface
     * @Type("TechDivision\Import\Configuration\Jms\Configuration\Subject\DateConverter")
     * @SerializedName("date-converter")
     */
    protected $dateConverter;

    /**
     * The source directory that has to be watched for new files.
     *
     * @var string
     * @Type("string")
     * @SerializedName("source-dir")
     */
    protected $sourceDir;

    /**
     * The target directory with the files that has been imported.
     *
     * @var string
     * @Type("string")
     * @SerializedName("target-dir")
     */
    protected $targetDir;

    /**
     * Lifecycle callback that will be invoked after deserialization.
     *
     * @return void
     * @PostDeserialize
     */
    public function postDeserialize()
    {

        // set a default import adatper if none has been configured
        if ($this->importAdapter === null) {
            $this->importAdapter = new ImportAdapter();
        }

        // set a default export adatper if none has been configured
        if ($this->exportAdapter === null) {
            $this->exportAdapter = new ExportAdapter();
        }

        // set a default filesystem adatper if none has been configured
        if ($this->filesystemAdapter === null) {
            $this->filesystemAdapter = new FilesystemAdapter();
        }

        // set a default file resolver if none has been configured
        if ($this->fileResolver === null) {
            $this->fileResolver = new FileResolver();
        }

        // set a default number converter if none has been configured
        if ($this->numberConverter === null) {
            $this->numberConverter = new NumberConverter();
        }

        // set a default date converter if none has been configured
        if ($this->dateConverter === null) {
            $this->dateConverter = new DateConverter();
        }
    }

    /**
     * Return's the multiple field delimiter character to use, default value is comma (,).
     *
     * @return string The multiple field delimiter character
     */
    public function getMultipleFieldDelimiter()
    {
        return $this->getConfiguration()->getMultipleFieldDelimiter();
    }

    /**
     * Return's the multiple value delimiter character to use, default value is comma (|).
     *
     * @return string The multiple value delimiter character
     */
    public function getMultipleValueDelimiter()
    {
        return $this->getConfiguration()->getMultipleValueDelimiter();
    }

    /**
     * Return's the delimiter character to use, default value is comma (,).
     *
     * @return string The delimiter character
     */
    public function getDelimiter()
    {
        return $this->getConfiguration()->getDelimiter();
    }

    /**
     * The enclosure character to use, default value is double quotation (").
     *
     * @return string The enclosure character
     */
    public function getEnclosure()
    {
        return $this->getConfiguration()->getEnclosure();
    }

    /**
     * The escape character to use, default value is backslash (\).
     *
     * @return string The escape character
     */
    public function getEscape()
    {
        return $this->getConfiguration()->getEscape();
    }

    /**
     * The file encoding of the CSV source file, default value is UTF-8.
     *
     * @return string The charset used by the CSV source file
     */
    public function getFromCharset()
    {
        return $this->getConfiguration()->getFromCharset();
    }

    /**
     * The file encoding of the CSV targetfile, default value is UTF-8.
     *
     * @return string The charset used by the CSV target file
     */
    public function getToCharset()
    {
        return $this->getConfiguration()->getToCharset();
    }

    /**
     * The file mode of the CSV target file, either one of write or append, default is write.
     *
     * @return string The file mode of the CSV target file
     */
    public function getFileMode()
    {
        return $this->getConfiguration()->getFileMode();
    }

    /**
     * Queries whether or not strict mode is enabled or not, default is TRUE.
     *
     * @return boolean TRUE if strict mode is enabled, else FALSE
     */
    public function isStrictMode()
    {
        return $this->getConfiguration()->isStrictMode();
    }

    /**
     * Return's the subject's source date format to use.
     *
     * @return string The source date format
     */
    public function getSourceDateFormat()
    {
        return $this->getDateConverter()->getSourceDateFormat();
    }

    /**
     * Return's the source directory that has to be watched for new files.
     *
     * @return string The source directory
     */
    public function getSourceDir()
    {
        return $this->sourceDir ? $this->sourceDir : $this->getConfiguration()->getSourceDir();
    }

    /**
     * Return's the target directory with the files that has been imported.
     *
     * @return string The target directory
     */
    public function getTargetDir()
    {
        return $this->targetDir ? $this->targetDir : $this->getConfiguration()->getTargetDir();
    }

    /**
     * Queries whether or not debug mode is enabled or not, default is TRUE.
     *
     * @return boolean TRUE if debug mode is enabled, else FALSE
     */
    public function isDebugMode()
    {
        return $this->getConfiguration()->isDebugMode();
    }

    /**
     * Return's the subject's unique DI identifier.
     *
     * @return string The subject's unique DI identifier
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set's the reference to the configuration instance.
     *
     * @param \TechDivision\Import\ConfigurationInterface $configuration The configuration instance
     *
     * @return void
     */
    public function setConfiguration(ConfigurationInterface $configuration)
    {
        $this->configuration = $configuration;
    }

    /**
     * Return's the reference to the configuration instance.
     *
     * @return \TechDivision\Import\ConfigurationInterface The configuration instance
     */
    public function getConfiguration()
    {
        return $this->configuration;
    }

    /**
     * Return's the prefix for the import files.
     *
     * @return string The prefix
     */
    public function getPrefix()
    {
        return $this->getFileResolver()->getPrefix();
    }

    /**
     * Return's the array with the subject's observers.
     *
     * @return array The subject's observers
     */
    public function getObservers()
    {
        return $this->observers;
    }

    /**
     * Return's the array with the subject's callbacks.
     *
     * @return array The subject's callbacks
     */
    public function getCallbacks()
    {
        return $this->callbacks;
    }

    /**
     * Return's the array with the subject's frontend input callbacks.
     *
     * @return array The subject's frontend input callbacks
     */
    public function getFrontendInputCallbacks()
    {
        return $this->frontendInputCallbacks;
    }

    /**
     * Set's the flag to signal that the an OK file is needed for the subject
     * to be processed.
     *
     * @param boolean $okFileNeeded TRUE if the subject needs an OK file, else FALSE
     *
     * @return void
     */
    public function setOkFileNeeded($okFileNeeded)
    {
        $this->okFileNeeded = $okFileNeeded;
    }

    /**
     * Queries whether or not that the subject needs an OK file to be processed.
     *
     * @return boolean TRUE if the subject needs an OK file, else FALSE
     */
    public function isOkFileNeeded()
    {
        return $this->okFileNeeded;
    }

    /**
     * Queries whether or not the subject should create a .imported flagfile
     *
     * @return boolean TRUE if subject has to create the .imported flagfile, else FALSE
     */
    public function isCreatingImportedFile()
    {
        return $this->createImportedFile;
    }

    /**
     * Return's the import adapter configuration instance.
     *
     * @return \TechDivision\Import\Configuration\Subject\ImportAdapterConfigurationInterface The import adapter configuration instance
     */
    public function getImportAdapter()
    {
        return $this->importAdapter;
    }

    /**
     * Return's the export adapter configuration instance.
     *
     * @return \TechDivision\Import\Configuration\Subject\ExportAdapterConfigurationInterface The export adapter configuration instance
     */
    public function getExportAdapter()
    {
        return $this->exportAdapter;
    }

    /**
     * Return's the filesystem adapter configuration instance.
     *
     * @return \TechDivision\Import\Configuration\Subject\FilesystemAdapterConfigurationInterface The filesystem adapter configuration instance
     */
    public function getFilesystemAdapter()
    {
        return $this->filesystemAdapter;
    }

    /**
     * Return's the file resolver configuration instance.
     *
     * @return \TechDivision\Import\Configuration\Subject\FileResolverConfigurationInterface The file resolver configuration instance
     */
    public function getFileResolver()
    {
        return $this->fileResolver;
    }

    /**
     * Return's the number converter configuration instance.
     *
     * @return \TechDivision\Import\Configuration\Subject\NumberConverterConfigurationInterface The number converter configuration instance
     */
    public function getNumberConverter()
    {
        return $this->numberConverter;
    }

    /**
     * Return's the date converter configuration instance.
     *
     * @return \TechDivision\Import\Configuration\Subject\DateConverterConfigurationInterface The date converter configuration instance
     */
    public function getDateConverter()
    {
        return $this->dateConverter;
    }

    /**
     * The array with the subject's custom header mappings.
     *
     * @return array The custom header mappings
     */
    public function getHeaderMappings()
    {
        return $this->getConfiguration()->getHeaderMappings();
    }

    /**
     * The array with the subject's custom image types.
     *
     * @return array The custom image types
     */
    public function getImageTypes()
    {
        return $this->getConfiguration()->getImageTypes();
    }
}


<?php

namespace Openbuildings\Swiftmailer;

use Swift_Events_SendListener;
use Swift_Events_SendEvent;

/**
 * @author     Yasen Yanev <yasen@openbuildings.com>
 * @copyright  (c) 2014 Clippings Ltd.
 * @license    http://spdx.org/licenses/BSD-3-Clause
 */
class GoogleCampaignPlugin implements Swift_Events_SendListener
{
    const CAMPAIGN_QUERY_PARAM = 'google_campaign';

    /**
     * Embed campaigns into the newsletter and return the updated html
     *
     * @param  string $html                 the email content
     * @param  array  $campaign             the general campaign for the newsletter
     * @param  array  $additionalCampaigns  additional campaigns to be replaced
     * @return string $html                 html with updated hrefs
     */
    public static function embedCampaigns(
        $html,
        $campaign = [],
        $additionalCampaigns = []
    ) {
        $pattern = '/<a(\s[^>]*)href="([^"]*)"([^>]*)>/si';

        $html = preg_replace_callback($pattern, function($matches) use ($campaign, $additionalCampaigns) {
            $href = GoogleCampaignPlugin::replaceLink($matches[2], $campaign, $additionalCampaigns);
            return "<a{$matches[1]}href=\"{$href}\"{$matches[3]}>";
        }, $html);

        return $html;
    }

    /**
     * Append campaign parameters to the href attribute of $element object
     * or replace `google_campaign` parameter with the correct campaign params
     *
     * @param  string  $href                  the href which needs to be replaced
     * @param  array   $campaign              the general campaign parameters
     * @param  array   $additionalCampaigns  additional campaigns for the newsletter
     * @return DomNode the $element with replaced href attribute
     */
    public static function replaceLink($href, $campaign = array(), $additionalCampaigns = array())
    {
        $href = html_entity_decode($href);
        $params = array();
        $parts = explode('?', $href);
        $uri = $parts[0];

        if (isset($parts[1])) {
            parse_str($parts[1], $params);
        }

        if ( ! count(array_intersect_key($campaign, $params)) and ! array_key_exists(GoogleCampaignPlugin::CAMPAIGN_QUERY_PARAM, $params)) {
            $params = array_merge($params, $campaign);
        } elseif (
            array_key_exists(GoogleCampaignPlugin::CAMPAIGN_QUERY_PARAM, $params)
            and $campaign_name = $params[GoogleCampaignPlugin::CAMPAIGN_QUERY_PARAM]
            and isset($additionalCampaigns[$campaign_name])
        ) {
            unset($params[GoogleCampaignPlugin::CAMPAIGN_QUERY_PARAM]);
            $params = array_merge($params, $additionalCampaigns[$campaign_name]);
        }

        if (count($params)) {
            $uri .= '?'.urldecode(http_build_query($params));
        }

        return $uri;
    }

    private $campaign;
    private $additionalCampaigns;

    public function __construct(array $campaign, $additionalCampaigns = [])
    {
        $this->campaign = $campaign;
        $this->additionalCampaigns = $additionalCampaigns;
    }

    public function getCampaign()
    {
        return $this->campaign;
    }

    public function setCampaign(array $campaign)
    {
        $this->campaign = $campaign;
    }

    public function getAdditionalCampaigns()
    {
        return $this->additionalCampaigns;
    }

    public function setAdditionalCampaigns(array $campaigns)
    {
        $this->additionalCampaigns = $campaigns;
    }

    /**
     *
     * @param Swift_Events_SendEvent $event
     */
    public function beforeSendPerformed(Swift_Events_SendEvent $event)
    {
        $message = $event->getMessage();

        if ($message->getContentType() === 'text/html') {
            $html = GoogleCampaignPlugin::embedCampaigns(
                $message->getBody(),
                $this->getCampaign(),
                $this->getAdditionalCampaigns()
            );

            $message->setBody($html);
        }

        foreach ($message->getChildren() as $part) {
            if (strpos($part->getContentType(), 'text/html') !== false) {
                $html = GoogleCampaignPlugin::embedCampaigns(
                    $part->getBody(),
                    $this->getCampaign(),
                    $this->getAdditionalCampaigns()
                );

                $part->setBody($html);
            }
        }
    }

    /**
     * Do nothing
     * @codeCoverageIgnore
     * @param Swift_Events_SendEvent $event
     */
    public function sendPerformed(Swift_Events_SendEvent $event)
    {
        // Do Nothing
    }
}


<?php

/**
 * This file is part of the PHP Generics package.
 *
 * @package Generics
 */
namespace Generics\Socket;

/**
 * This class provides a basic client socket implementation
 *
 * @author Maik Greubel <greubel@nkey.de>
 */
class ClientSocket extends Socket
{

    /**
     * Whether the socket is connected
     *
     * @var boolean
     */
    private $conntected;

    /**
     * Create a new client socket
     *
     * @param Endpoint $endpoint
     *            The endpoint to use
     * @param resource $clientHandle
     *            optional existing client handle
     */
    public function __construct(Endpoint $endpoint, $clientHandle = null)
    {
        $this->endpoint = $endpoint;
        $this->handle = $clientHandle;
        $this->conntected = false;

        if (! is_resource($clientHandle)) {
            parent::__construct($endpoint);
        }
    }

    /**
     * Connect to remote endpoint
     *
     * @throws SocketException
     */
    public function connect()
    {
        if (!is_resource($this->handle)) {
            throw new SocketException("Socket is not available");
        }
        if (! @socket_connect($this->handle, $this->endpoint->getAddress(), $this->endpoint->getPort())) {
            $code = socket_last_error($this->handle);
            throw new SocketException(socket_strerror($code), array(), $code);
        }
        $this->conntected = true;
    }

    /**
     * Disconnects the socket
     *
     * @throws SocketException
     */
    public function disconnect()
    {
        if (! $this->conntected) {
            throw new SocketException("Socket is not connected");
        }

        $this->close();
    }

    /**
     * Whether the client is connected
     *
     * @return bool
     */
    public function isConnected():bool
    {
        return $this->conntected;
    }

    /**
     *
     * @see \Generics\Socket\ClientSocket::disconnect()
     */
    public function close()
    {
        parent::close();
        $this->conntected = false;
    }

    /**
     *
     * {@inheritdoc}
     * @see \Generics\Socket\Socket::isWriteable()
     */
    public function isWriteable():bool
    {
        if (! $this->isConnected()) {
            return false;
        }

        return parent::isWriteable();
    }
}


<?php

namespace Unite\UnisysApi\Http\Middleware;

use Cache;
use Closure;

class CacheResponse
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next, $tag = null)
    {
        if(!env('CACHE_RESPONSE', false)) {
            return $next($request);
        }

        $key = md5($request->fullUrl());

        $tags = ['response', $tag];

        if (Cache::tags($tags)->has($key)) {
            return Cache::tags($tags)->get($key);
        }

        $response = $next($request);

        Cache::tags($tags)->put($key, $response, 60 * 24);

        return $response;
    }
}


<?php

namespace hypeJunction\Prototyper;

class ActionController {

	private $config;
	private $prototype;
	private $entityFactory;

	/**
	 * Constructor
	 *
	 * @param Config $config
	 */
	public function __construct(Config $config, Prototype $prototype, EntityFactory $entityFactory) {
		$this->config = $config;
		$this->prototype = $prototype;
		$this->entityFactory = $entityFactory;
	}

	/**
	 * Returns a form element object
	 *
	 * @param mixed  $entity ElggEntity or an array of entity attributes
	 * @param string $action Action name (used as a plugin hook type)
	 * @param array  $params Additional context params to pass to the hook
	 * @return Elements\ActionController
	 */
	public function with($entity = array(), $action = 'all', array $params = array()) {

		$entity = $this->entityFactory->build($entity);
		$fields = $this->prototype->fields($entity, $action, $params);
		return new Elements\ActionController($entity, $action, $fields);
	}
}


<?php

namespace Unite\UnisysApi\Policies;

use Illuminate\Auth\Access\HandlesAuthorization;
use Unite\UnisysApi\Models\Permission;
use Unite\UnisysApi\Models\User;

class UserPolicy
{
    use HandlesAuthorization;

    public function before(User $user, $ability)
    {
        if ($user->isAdmin()) {
            return true;
        }
    }

    /**
     * Determine whether the user can view the user.
     *
     * @param  \Unite\UnisysApi\Models\User  $user
     * @param  \Unite\UnisysApi\Models\User  $givenUser
     * @return mixed
     */
    public function view(User $user, User $givenUser)
    {
        if ($user->hasPermissionTo(Permission::USER_READ_ALL)) {
            return true;
        }

        return $user->id === $givenUser->id;
    }

    /**
     * Determine whether the user can update the user.
     *
     * @param  \Unite\UnisysApi\Models\User  $user
     * @param  \Unite\UnisysApi\Models\User  $givenUser
     * @return mixed
     */
    public function update(User $user, User $givenUser)
    {
        if ($user->hasPermissionTo(Permission::USER_UPDATE_ALL)) {
            return true;
        }

        return $user->id === $givenUser->id;
    }
}


<?php

declare(strict_types=1);

/*
 * This file is part of Eloquent Presenter.
 *
 * (c) Brian Faust <hello@brianfaust.de>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace BrianFaust\Presenter;

trait Presentable
{
    /**
     * View presenter instance.
     *
     * @var mixed
     */
    protected $presenterInstance;

    /**
     * Prepare a new or cached presenter instance.
     *
     * @throws PresenterException
     *
     * @return mixed
     */
    public function present()
    {
        $presenterClass = $this->getPresenterClass();

        if (!class_exists($presenterClass)) {
            throw new Exceptions\PresenterException('The specified presenter does not exist.');
        }

        if (!$this->presenterInstance) {
            $this->presenterInstance = new $presenterClass($this);
        }

        return $this->presenterInstance;
    }

    /**
     * Get the view presenter for the model.
     *
     * @return string
     */
    protected function getPresenterClass(): string
    {
        return 'App\\Presenters\\'.class_basename($this);
    }
}


<?php
/**
 * @link      http://github.com/zetta-code/zend-bootstrap for the canonical source repository
 * @copyright Copyright (c) 2018 Zetta Code
 */

namespace Zetta\ZendBootstrap\View\Helper;

use Zend\Mvc\Plugin\FlashMessenger\FlashMessenger as PluginFlashMessenger;
use Zend\Mvc\Plugin\FlashMessenger\View\Helper\FlashMessenger as FlashMessengerHelper;
use Zend\Stdlib\ArrayUtils;
use Zend\View\Helper\AbstractHelper;

class FlashMessenger extends AbstractHelper
{
    /**
     * @var FlashMessengerHelper
     */
    protected $flashMessengerHelper;

    /**
     * Default class for the div tag
     *
     * @var string
     */
    protected $divClass = 'alerts';

    /**
     * Default attributes for the open format tag
     *
     * @var array
     */
    protected $classes = [
        PluginFlashMessenger::NAMESPACE_DEFAULT => ['alert', 'alert-secondary', 'alert-dismissible', 'fade', 'show', 'animated', 'shake'],
        PluginFlashMessenger::NAMESPACE_SUCCESS => ['alert', 'alert-success', 'alert-dismissible', 'fade', 'show', 'animated', 'shake'],
        PluginFlashMessenger::NAMESPACE_INFO => ['alert', 'alert-info', 'alert-dismissible', 'fade', 'show', 'animated', 'shake'],
        PluginFlashMessenger::NAMESPACE_WARNING => ['alert', 'alert-warning', 'alert-dismissible', 'fade', 'show', 'animated', 'shake'],
        PluginFlashMessenger::NAMESPACE_ERROR => ['alert', 'alert-danger', 'alert-dismissible', 'fade', 'show', 'animated', 'shake'],
    ];

    /**
     * @return FlashMessenger
     */
    public function __invoke()
    {
        return $this;
    }

    /**
     * @inheritdoc
     */
    public function __toString()
    {
        return $this->render();
    }

    /**
     * Render All Messages
     *
     * @param  array $classes
     * @param  null|bool $autoEscape
     * @return string
     */
    public function render(array $classes = [], $autoEscape = null)
    {
        $divOpen = '
divClass . '">';
        $divClose = '
';
        $hasMessages = false;

        foreach ($this->classes as $namespace => $namespaceClasses) {
            $namespaceClasses = ArrayUtils::merge($namespaceClasses, $classes);
            if ($this->getFlashMessengerHelper()->getPluginFlashMessenger()->hasCurrentMessages($namespace)) {
                $hasMessages = true;
                $divOpen .= $this->getFlashMessengerHelper()->renderCurrent($namespace, $namespaceClasses, $autoEscape);
                $this->getFlashMessengerHelper()->getPluginFlashMessenger()->clearCurrentMessagesFromNamespace($namespace);
            } elseif ($this->getFlashMessengerHelper()->getPluginFlashMessenger()->hasMessages($namespace)) {
                $hasMessages = true;
                $divOpen .= $this->getFlashMessengerHelper()->render($namespace, $namespaceClasses, $autoEscape);
            }
        }

        return $hasMessages ? $divOpen . $divClose : '';
    }

    /**
     * Get the FlashMessenger flashMessengerHelper
     * @return FlashMessengerHelper
     */
    public function getFlashMessengerHelper()
    {
        if ($this->flashMessengerHelper) {
            return $this->flashMessengerHelper;
        }

        if (method_exists($this->view, 'plugin')) {
            $this->flashMessengerHelper = $this->view->plugin(FlashMessengerHelper::class);
        }

        if (!$this->flashMessengerHelper instanceof FlashMessengerHelper) {
            $this->flashMessengerHelper = new FlashMessengerHelper();
        }

        return $this->flashMessengerHelper;
    }

    /**
     * Set the FlashMessenger flashMessengerHelper
     * @param FlashMessengerHelper $flashMessengerHelper
     * @return FlashMessenger
     */
    public function setFlashMessengerHelper($flashMessengerHelper)
    {
        $this->flashMessengerHelper = $flashMessengerHelper;
        return $this;
    }

    /**
     * Get the FlashMessenger divClass
     * @return string
     */
    public function getDivClass()
    {
        return $this->divClass;
    }

    /**
     * Set the FlashMessenger divClass
     * @param string $divClass
     * @return FlashMessenger
     */
    public function setDivClass($divClass)
    {
        $this->divClass = $divClass;
        return $this;
    }

    /**
     * Get the FlashMessenger classes
     * @return array
     */
    public function getClasses()
    {
        return $this->classes;
    }

    /**
     * Set the FlashMessenger classes
     * @param array $classes
     * @return FlashMessenger
     */
    public function setClasses($classes)
    {
        $this->classes = $classes;
        return $this;
    }
}


<?php

namespace hypeJunction\Prototyper\Elements;

class AnnotationField extends Field {

	const CLASSNAME = __CLASS__;

	/**
	 * {@inheritdoc}
	 */
	public function getValues(\ElggEntity $entity) {
		$values = array();
		$sticky = $this->getStickyValue();

		if ($sticky) {
			$keys = array_keys($sticky['value']);
			foreach ($keys as $i) {
				$ann = new \stdClass();
				$ann->id = $sticky['id'][$i];
				$ann->name = $sticky['name'][$i];
				$ann->value = $sticky['value'][$i];
				$ann->access_id = $sticky['access_id'][$i];
				$ann->owner_guid = $sticky['owner_guid'][$i];

				$values[$i] = $ann;
			}
		} else if ($entity->guid) {
			$values = elgg_get_annotations(array(
				'guids' => (int) $entity->guid,
				'metadata_names' => $this->getShortname(),
				'limit' => 0,
			));
		}

		if (empty($values)) {
			$ann = new \stdClass();
			$ann->value = $this->getDefaultValue();
			$values = array($ann);
		}

		return array_values($values);
	}

	/**
	 * {@inheritdoc}
	 */
	public function validate(\ElggEntity $entity) {

		$validation = new ValidationStatus();

		$annotation = get_input($this->getShortname(), array());
		$keys = array_keys(elgg_extract('value', $annotation, array()));

		if (empty($keys)) {
			if ($this->isRequired()) {
				$validation->setFail(elgg_echo('prototyper:validate:error:required', array($this->getLabel())));
			}
		} else {
			foreach ($keys as $i) {
				if ($annotation['name'][$i] == $this->getShortname()) {
					if (is_string($annotation['value'][$i])) {
						$value = strip_tags($annotation['value'][$i]);
					} else {
						$value = $annotation['value'][$i];
					}
					if (is_null($value) || $value == '') {
						if ($this->isRequired()) {
							$validation->setFail(elgg_echo('prototyper:validate:error:required', array($this->getLabel())));
						}
					} else {
						$validation = $this->applyValidationRules($value, $validation, $entity);
					}
				}
			}
		}
		return $validation;
	}

	/**
	 * {@inheritdoc}
	 */
	public function handle(\ElggEntity $entity) {

		$shortname = $this->getShortname();

		$current_annotations = elgg_get_annotations(array(
			'guids' => (int) $entity->guid,
			'annotation_names' => $shortname,
		));

		if (is_array($current_annotations) && count($current_annotations)) {
			foreach ($current_annotations as $ann) {
				$current_annotations_ids[] = $ann->id;
			}
		}

		if (!is_array($current_annotations_ids)) {
			$current_annotations_ids = array();
		}

		$future_annotations = get_input($this->getShortname(), array());

		$params = array(
			'field' => $this,
			'entity' => $entity,
			'annotation_name' => $shortname,
			'value' => $current_annotations,
			'future_value' => $future_annotations,
		);

		// Allow plugins to prevent annotation from being changed
		if (!elgg_trigger_plugin_hook('handle:annotation:before', 'prototyper', $params, true)) {
			return $entity;
		}

		$future_annotations_ids = elgg_extract('id', $future_annotations, array());

		$to_delete = array_diff($current_annotations_ids, $future_annotations_ids);
		foreach ($to_delete as $id) {
			elgg_delete_annotation_by_id($id);
		}

		$keys = array_keys(elgg_extract('name', $future_annotations, array()));

		$ids = array();
		foreach ($keys as $i) {

			$id = $future_annotations['id'][$i];
			$name = $future_annotations['name'][$i];
			$value = $future_annotations['value'][$i];
			if ($this->getValueType() == 'tags') {
				$value = string_to_tag_array($value);
			}
			$access_id = $future_annotations['access_id'][$i];
			$owner_guid = $future_annotations['owner_guid'][$i];

			if (!is_array($value)) {
				if ($id) {
					update_annotation($id, $name, $value, '', $owner_guid, $access_id);
				} else {
					$id = create_annotation($entity->guid, $name, $value, '', $owner_guid, $access_id);
				}
				$ids[] = $id;
			} else {
				if ($id) {
					elgg_delete_annotation_by_id($id);
				}
				foreach ($value as $val) {
					$ids[] = create_annotation($entity->guid, $name, $val, '', $owner_guid, $access_id);
				}
			}
		}

		$params = array(
			'field' => $this,
			'entity' => $entity,
			'annotation_name' => $shortname,
			'value' => (count($ids)) ? elgg_get_annotations(array('annotation_ids' => $ids)) : array(),
			'previous_value' => $current_annotations,
		);

		elgg_trigger_plugin_hook('handle:annotation:after', 'prototyper', $params, true);

		return $entity;
	}

	/**
	 * {@inheritdoc}
	 */
	public static function getDataType() {
		return 'annotation';
	}

}


<?php

namespace Monospice\SpicyIdentifiers\Tools;

use Monospice\SpicyIdentifiers\Tools\Interfaces;
use Monospice\SpicyIdentifiers\Tools\Parser;
use Monospice\SpicyIdentifiers\Tools\Formatter;

/**
 * Converts an identifier string from one format to another
 *
 * @author Cy Rossignol <cy.rossignol@yahoo.com>
 */
class Converter implements Interfaces\Converter
{

    // Inherit Doc from Interfaces\Converter
    public static function convert($identifier, $sourceFormat, $outputFormat)
    {
        $parts = Parser::parse($identifier, $sourceFormat);

        return Formatter::format($parts, $outputFormat);
    }
}


<?php
namespace yimaTheme;

use yimaTheme\Theme\Theme;
use Zend\EventManager\EventManagerAwareInterface;
use Zend\EventManager\EventManagerInterface;
use Zend\ServiceManager\ServiceManager;
use Zend\ServiceManager\ServiceManagerAwareInterface;
use Zend\View\Resolver as ViewResolver;

/**
 * Class Manager
 *
 * @package yimaTheme
 */
class Manager implements
    ManagerInterface,
    ServiceManagerAwareInterface,
    EventManagerAwareInterface
{
    /**
     * @var ServiceManager
     */
    protected $serviceManager;

    /*
     * @var EventManagerInterface
     */
    protected $events;

    protected $isInitialized;

    /**
     * @var Theme Prepared Theme Object
     */
    protected $themeObject = false;

    /**
     * Init Theme Manager To Work
     *
     * @return $this
     */
    public function init()
    {
        if ($this->isInitialized())
            return true;

        // attach default listeners
        /** @var $sharedEvents \Zend\EventManager\SharedEventManager */
        $sm = $this->getServiceManager();
        $defaultListeners = $sm->get('yimaTheme.Manager.ListenerAggregate');
        if ($defaultListeners instanceof self)
            // inject themeManager
            $defaultListeners->manager = $this;

        $sharedEvents = $this->getEventManager()->getSharedManager();
        $sharedEvents->attachAggregate($defaultListeners);

        $this->isInitialized = true;

        return $this;
    }

    /**
     * Determine theme is loaded or not?
     *
     * @return bool
     */
    public function isInitialized()
    {
        return $this->isInitialized;
    }

    /**
     * Get Prepared Theme Object
     *
     * @return Theme
     */
    public function getThemeObject()
    {
        return $this->themeObject;
    }

    // -- implementation methods --------------------------------------------------------------------------------------

    /**
     * Set service manager
     *
     * @param ServiceManager $serviceManager
     */
    public function setServiceManager(ServiceManager $serviceManager)
    {
        $this->serviceManager = $serviceManager;
    }

    /**
     * Get serviceManager
     *
     * @return ServiceManager
     *
     * @throws \Exception
     */
    public function getServiceManager()
    {
        if (! $this->serviceManager) {
            throw new \Exception('ServiceManager not injected and not exists.');
        }

        return $this->serviceManager;
    }

    /**
     * Inject an EventManager instance
     *
     * @param  EventManagerInterface $eventManager
     * @return void
     */
    public function setEventManager(EventManagerInterface $eventManager)
    {
        $this->events = $eventManager;
    }

    /**
     * Retrieve the event manager
     *
     * @return EventManagerInterface
     */
    public function getEventManager()
    {
        return $this->events;
    }
}


<?php
namespace yimaTheme\Theme;

use Poirot\Core\Entity;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\ServiceManager\ServiceManager;
use Zend\View\Model\ModelInterface;
use Zend\View\Model\ViewModel;

/**
 * Class Theme
 * @package yimaTheme\Theme
 */
class Theme extends ViewModel
    implements
    ThemeDefaultInterface,
    ServiceLocatorAwareInterface
{
    /**
     * Theme name
     *
     * @var string
     */
    protected $name;

    /**
     * dir path that store themes

     * @var string
     */
    protected $themesPath;

    protected $initialized = false;

    /**
     * not Final theme only initialized and adding pathStack
     * then fallBack to theme resolver till resolve Final
     *
     * @var boolean
     */
    protected $isFinal = true;

    /**
     * @var Parent Theme Object
     */
    protected $parent;

    /**
     * @var Entity Theme Configs Entity
     */
    protected $config;

    /**
     * @var ServiceManager
     */
    protected $serviceLocator;

    /**
     * Constructor
     *
     * @param null|string $name Name of theme
     * @param null|string $themesPath Path dir to themes folder
     */
    public function __construct($name = null, $themesPath = null)
    {
        if ($name !== null)
            $this->setName($name);

        if ($themesPath !== null)
            $this->setThemesPath($themesPath);
    }

    /**
     * Initialize theme object if attained
     *
     * @throws \Exception
     * @return mixed
     */
    public function init()
    {
        if ($this->isInitialized())
            return $this;

        if (!$this->getThemesPath() || !$this->getName())
            throw new \Exception('Theme Cant initialize because theme name or theme paths not present.');

        $themePathname = $this->getThemesPath().DS.$this->getName();
        if (!is_dir($themePathname))
            throw new \Exception(sprintf('Theme "%s" not found in "%s".', $this->getName(), $themePathname));

        $bootstrap    = $themePathname.DS.'theme.bootstrap.php';
        if (file_exists($bootstrap)) {
            ob_start();
            set_error_handler(
                function($errno, $errstr) {
                    throw new \ErrorException($errstr, $errno);
                },
                E_ALL
            );

            include $bootstrap; // Bootstrap Theme

            restore_error_handler();
            ob_get_clean();
        }

        $this->initialized = true;

        return $this;
    }

    /**
     * Is theme object attained theme and initialized?
     * : attained theme mean having theme name
     *
     * @return boolean
     */
    public function isInitialized()
    {
        return $this->initialized;
    }

    /**
     * not Final theme only initialized and adding pathStack
     * then fallBack to theme resolver till resolve Final
     *
     * @return boolean
     */
    public function isFinalTheme()
    {
        return $this->isFinal;
    }

    /**
     * Set Final Theme Flag
     *
     * @param bool $bool Final Theme Flag
     *
     * @return $this
     */
    public function setFinalTheme($bool = true)
    {
        $this->isFinal = (boolean) $bool;

        return $this;
    }

    /**
     * Add a child model
     *
     * @param  ModelInterface $child
     * @param  null|string    $captureTo Optional; if specified, the "capture to" value to set on the child
     * @param  null|bool      $append    Optional; if specified, append to child  with the same capture
     *
     * @return ViewModel
     */
    public function addChild(ModelInterface $child, $captureTo = null, $append = null)
    {
        parent::addChild($child, $captureTo, $append);

        if ($child instanceof ThemeDefaultInterface) {
            $child->parent = $this;
        }

        return $this;
    }

    /**
     * Get Parent Theme
     *
     * @return ThemeDefaultInterface
     */
    public function getParentTheme()
    {
        if ($this->isFinalTheme()) {
            // Final Theme can't have parent theme
            return false;
        }

        return $this->parent;
    }

    /**
     * Set name of theme
     *
     * @param string $name
     *
     * @return mixed
     */
    public function setName($name)
    {
        $this->name = (string) $name;

        return $this;
    }

    public function getName()
    {
        return $this->name;
    }

    /**
     * Set dir to folder that store themes
     *
     * @param string $path dir path
     *
     * @throws \Exception
     * @return mixed
     */
    public function setThemesPath($path)
    {
        if (!is_dir($path)) {
            throw new \Exception(
                sprintf('Path "%s" not found.', $path)
            );
        }

        $this->themesPath = rtrim($path, DS);

        return $this;
    }

    public function getThemesPath()
    {
        return $this->themesPath;
    }

    /**
     * Get Theme Config Object Entity
     *
     * @throws \Exception
     * @return Entity
     */
    public function config()
    {
        if (!$this->config) {
            $config = array();

            $configFile = $this->getThemesPath()
                .DIRECTORY_SEPARATOR.$this->getName()
                .DIRECTORY_SEPARATOR.'theme.config.php';
            if (file_exists($configFile)) {
                ob_start();
                set_error_handler(
                    function($errno, $errstr) {
                        throw new \ErrorException($errstr, $errno);
                    },
                    E_ALL
                );

                $config = include $configFile;

                restore_error_handler();
                ob_get_clean();

                if (!is_array($config))
                    throw new \Exception('Invalid "'.$this->getName().'" Theme Config File. It must return array.');
            }

            $this->config = new Entity($config);
        }

        return $this->config;
    }

    /**
     * Set service locator
     *
     * @param ServiceLocatorInterface $serviceLocator
     */
    public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
    {
        $this->serviceLocator = $serviceLocator;
    }

    /**
     * Get service locator
     *
     * @return ServiceLocatorInterface
     */
    public function getServiceLocator()
    {
        return $this->serviceLocator;
    }
}


<?php

namespace Zf2Forum\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\Stdlib\ResponseDescription as Response;

class DiscussController extends AbstractActionController
{
    protected $discussService;
    protected $tag;
    protected $thread;
    protected $moduleOptions;
    protected $userMapper;

    /**
     * gets User Mapper
     *
     * @return Zf2Forum\Mapper\UserMapper
     */
    protected function getUserMapper()
    {
        return $this->userMapper;
    }

    /**
     * gets module options from ServiceManager
     *
     * @return \Zf2Forum\Options\ModuleOptions
     */
    protected function getModuleOptions()
    {
        return $this->moduleOptions;
    }

    public function forumsAction()
    {
        $tags = $this->getDiscussService()->getCategories();

        return new ViewModel(
            array(
                'tags'          => $tags,
                'showTimeAgo'   => $this->getModuleOptions()->getShowTimeAgo(),
            )
        );

    }

    public function threadsAction()
    {
        $verifyTag = $this->verifyTag();
        if (-1 === $verifyTag) {
            $response = $this->getResponse();
            $response->setStatusCode(404);
            return $response;
        }

        $tag = $this->getTag();

        if (0 === $verifyTag) {
            return $this->redirect()->toRoute(
                'forum/category',
                array(
                    'categoryid'   => $tag->getId()
                )
            );
        }

        $threads = $this->getDiscussService()->getLatestThreads(25, 0, $tag->getid());
        $form = $this->getServiceLocator()->get('Zf2Forum_form');

        return new ViewModel(
            array(
                'tag'           => $tag,
                'threads'       => $threads,
                'showTimeAgo'   => $this->getModuleOptions()->getShowTimeAgo(),
                'form'          => $form
            )
        );
    }

    protected function messagesAction()
    {
        $verifyThread = $this->verifyThread();

        if (-1 == $verifyThread) {
            /**
             * @todo make a nice template for over here
             */
            die();
        } else {
            $thread = $this->getThread();
            $category = $this->getTag();
/*
            // Store visit if unique.
            $visit = $this->getServiceLocator()->get('Zf2Forum_visit');
            $visit->setThread($thread);
            $this->getDiscussService()->storeVisitIfUnique($visit);

            // Get messages.
            $replys = $this->getDiscussService()->getMessagesByThread($thread);
*/
            $messages = array($thread);

            // Create new form instance.
            $form = $this->getServiceLocator()->get('Zf2Forum_replyform');

            // Return a view model.
            return new ViewModel(
                array(
                    'category'       => $category,
                    'thread'         => $thread,
                    'messages'       => $messages,
                    'showQuickReply' => $this->getModuleOptions()->getShowQuickReply(),
                    'showTimeAgo'    => $this->getModuleOptions()->getShowTimeAgo(),
                    'form'           => $form
                )
            );
        }
    }

    public function replyAction()
    {
        // Create new form and hydrator instances.
        $form = $this->getServiceLocator()->get('Zf2Forum_replyform');
        $formHydrator = $this->getServiceLocator()->get('Zf2Forum_post_form_hydrator');

        $tag = $this->getTag();
        $thread = $this->getThread();

        // Check if the request is a POST.
        $request = $this->getRequest();
        if ($request->isPost()) {
            // POST, so check if valid.
            $data = (array) $request->getPost();

            // create a new message and sets its thread.
            $message = $this->getServiceLocator()->get('Zf2Forum_message');
            $message->setThread($thread);

            $form->setHydrator($formHydrator);
            $form->bind($message);
            $form->setData($data);
            if ($form->isValid()) {
                // Persist message.
                $this->getDiscussService()->createMessage($message);

                // Redirect to list of messages
                return $this->redirect()->toRoute(
                    'Zf2Forum/thread',
                    array(
                        'tagslug'    => $tag->getSlug(),
                            'tagid'      => $tag->getTagId(),
                            'threadslug' => $thread->getSlug(),
                            'threadid'   => $thread->getThreadId(),
                        'action'     => 'messages'
                    )
                );
            }
        }

        // If not a POST request, then just render the form.
        return new ViewModel(
            array(
                'form'   => $form,
                'tag'    => $tag,
                'thread' => $thread
            )
        );

    }

    public function newthreadAction()
    {
      // Create new form instance.
        $form = $this->getServiceLocator()->get('Zf2Forum_form');
        $formHydrator = $this->getServiceLocator()->get('Zf2Forum_post_form_hydrator');

        $category = $this->getTag();

        // Check if the request is a POST.
        $request = $this->getRequest();
        if ($request->isPost()) {
          // if post, check if valid
            $data = (array) $request->getPost();

            // create a new thread and sets its tag.
            $topic = $this->getServiceLocator()->get('Zf2Forum_thread');

            $form->setHydrator($formHydrator);
            $form->bind($topic);
            $form->setData($data);
            if ($form->isValid()) {
                // Persist message and thread.
                $thread = $this->getDiscussService()->createThread($category, $topic);

                // Redirect to list of messages
                return $this->redirect()->toRoute(
                    'forum/topic',
                    array(
                        'topicid'   => $thread->getId(),
                        'action'    => 'messages'
                    )
                );
            }
        }

        // If not a POST request, then just render the form.
        return new ViewModel(
            array(
                'form'      => $form,
                'category'  => $category
            )
        );
    }

    public function verifyTag()
    {
        $tag = $this->getTag();

        if (!$tag) {
            return -1;
        } else if ($tag->getId() !== $this->getEvent()->getRouteMatch()->getParam('categoryid')) {
            // fix slug name if it's wrong, redirect to the proper one
            return 0;
        }
        return 1;
    }

    public function verifyThread()
    {
        $thread = $this->getThread();

        if (!$thread) {
            $response = $this->getResponse();
            $response->setStatusCode(404);
            return -1;
        } else if ($thread->getId() !== $this->getEvent()->getRouteMatch()->getParam('topicid')) {
            // fix slug name if it's wrong, redirect to the proper one
            return 0;
        }
        return 1;
    }

    /**
     * Retrieve the category by the set url
     *
     * @access public
     * @author Stijn
     * @version 1.0.0
     * @return boolean / CategoryInterface
     */
    public function getTag()
    {
        if (null !== $this->tag) {
            return $this->tag;
        }

        $categoryId = $this->getEvent()->getRouteMatch()->getParam('categoryid');
        if (is_numeric($categoryId)) {
            return $this->tag = $this->getDiscussService()->getCategoryById($categoryId);
        }

        // Find category by topic
        $topicId = $this->getEvent()->getRouteMatch()->getParam('topicid');
        if (is_numeric($topicId)) {
            // Fetch the topic
            $topic = $this->getDiscussService()->getTopicById($topicId);

            // Fetch the category
            return $this->tag = $this->getDiscussService()->getCategoryById($topic->getforumCategoryId());
        }

        return false;
    }

    protected function getThread()
    {
        if (null !== $this->thread) {
            return $this->thread;
        }
        $topicId = $this->getEvent()->getRouteMatch()->getParam('topicid');
        return $this->thread = $this->getDiscussService()->getTopicById($topicId);
    }

    public function getDiscussService()
    {
        return $this->discussService;
    }

    public function setDiscussService($discussService)
    {
        $this->discussService = $discussService;
        return $this;
    }
}


<?php namespace Twitter;

use Twitter\Config\Credentials;
use Twitter\Config\AppCredentials;
use Twitter\Config\UserCredentials;
use Twitter\Config\Exceptions\TwitterCredentialsException;

use Twitter\Connections\AppConnection;
use Twitter\Connections\UserConnection;

class Client {

    /**
     * Twitter Credentials.
     *
     * @var AppCredentials|UserCredentials
     */
    private $credentials;

    /**
     * The current connection in use.
     *
     * @var AppConnection|UserConnection
     */
    private $connection;

    /**
     * Constructs a new Twitter Client object.
     *
     * $credentials should be an instance of AppCredentials if you want to make calls on Application's behalf.
     * $credentials should be an instance of UserCredentials if you want to make calls on users's behalf.
     *
     * @param Credentials $credentials Twitter credentials
     *
     * @throws TwitterCredentialsException If not a subclass of Credentials
     */
    public function __construct(Credentials $credentials)
    {
        //check if $credentials is a subclass of Credentials
        if(is_subclass_of($credentials, 'Twitter\Config\Credentials'))
        {
            $this->credentials = $credentials;
        }
        else
        {
            //if not a subclass of Credentials, throw exception!
            throw new TwitterCredentialsException('Parameter $credentials should be a subclass of Twitter\Config\Credentials.');
        }
    }

    /**
     * Checks the type of $credentials (if App or User) and returns a new connection instance accordingly.
     *
     * @return AppConnection|UserConnection Type of connection to Twitter.
     */
    public function connect()
    {
        if($this->credentials instanceof AppCredentials)
        {
            //set application specific connection
            $this->connection = new AppConnection($this->credentials);

            return $this->connection;
        }
        else
        {
            //set User specific connection
            $this->connection = new UserConnection($this->credentials);

            return $this->connection;
        }
    }

    /**
     * Gets the Twitter Credentials.
     *
     * @return AppCredentials|UserCredentials
     */
    public function getCredentials()
    {
        return $this->credentials;
    }

    /**
     * Sets the Twitter Credentials.
     *
     * @param AppCredentials|UserCredentials $credentials the credentials
     *
     * @return self
     */
    public function setCredentials($credentials)
    {
        $this->credentials = $credentials;

        return $this;
    }

    /**
     * Gets the The current connection in use.
     *
     * @return AppConnection|UserConnection
     */
    public function getConnection()
    {
        return $this->connection;
    }

    /**
     * Sets the The current connection in use.
     *
     * @param AppConnection|UserConnection $connection the connection
     *
     * @return self
     */
    public function setConnection($connection)
    {
        $this->connection = $connection;

        return $this;
    }
}


<?php namespace Twitter\Connections;

use Twitter\Config\Config;
use Twitter\Config\UserCredentials;
use Twitter\Connections\Exceptions\MediaUploadLimitException;

use GuzzleHttp\Post\PostFile;
use GuzzleHttp\Subscriber\Oauth\Oauth1;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ServerException;

/**
 * getRedirectUrlForAuth() and getAccessToken() are used for user authentication workflow (Oauth 1.0).
 *
 * Steps:
 *
 * - Get a request Token from Twitter and construct an Authentication URL for the user.
 * - Once the user is redirected back to the app, use 'oauth_token' and 'oauth_verifier' to get access tokens from Twitter.
 */
class UserConnection extends Connection {

    /**
     * A user connection to Twitter.
     *
     * @param UserCredentials $credentials Twitter API credentials
     */
    public function __construct(UserCredentials $credentials)
    {
        parent::__construct($credentials);
    }

    /**
     * Constructs an options array that is sent with the request.
     *
     * Uses Oauth tokens since this is a UserConnection.
     *
     * @param array $params URL query parameters
     * @param GuzzleHttp\Client $client a client to attach Oauth1 plugin to (can be null).
     *
     * @return array options for the request
     */
    protected function constructRequestOptions($params, $client = null)
    {
        //empty options array
        $options = array();

        //this is a User connection, use Oauth1 tokens.
        $oauth = new Oauth1(array(
            'consumer_key'    => $this->credentials->getConsumerKey(),
            'consumer_secret' => $this->credentials->getConsumerSecret(),
            'token'           => $this->credentials->getAccessToken(),
            'token_secret'    => $this->credentials->getAccessTokenSecret()
        ));

        //attach oauth to Guzzle client
        if(is_null($client))
        {
            //use the instance client
            $this->guzzleClient->getEmitter()->attach($oauth);
        }
        else
        {
            //to the parameter specified in the client
            $client->getEmitter()->attach($oauth);
        }

        //if query parameters not supplied, continue.
        if(!is_null($params))
        {
            //Add query parameters to options.
            $options['query'] = $params;
        }

        //Set the "auth" request option to "oauth" to sign using oauth.
        $options['auth'] = 'oauth';

        //return constructed options
        return $options;
    }

    /**
     * Get a request token and configures a Twitter authorization URL that the
     * user will be redirected to for authentication.
     *
     * Then returns the prepared Twitter authorization URL.
     *
     * @return string authentication URL
     */
    public function getRedirectUrlForAuth()
    {
        //Oauth1 plugin to get access tokens!
        $oauth = new Oauth1(array(
            'consumer_key'    => $this->credentials->getConsumerKey(),
            'consumer_secret' => $this->credentials->getConsumerSecret(),
            'callback'        => $this->credentials->getCallbackUrl()
        ));

        $this->guzzleClient->getEmitter()->attach($oauth);

        //obtain request token for the authorization popup.
        $requestTokenResponse = $this->guzzleClient->post(
            Config::get('oauth_request_token'),
            array(
                'auth' => 'oauth'
            )
        );

        //Parse the response from Twitter
        $oauthToken = array();
        parse_str($requestTokenResponse->getBody(), $oauthToken);

        //build the query parameters
        $params = http_build_query(array(
            'oauth_token' => $oauthToken['oauth_token']
        ));

        //return the redirect URL the user should be redirected to.
        return (Config::get('base_url') . Config::get('oauth_authenticate') . '?' . $params);
    }

    /**
     * Get Access tokens from the user in exchange of oauth_token and oauth_verifier and return
     * them.
     *
     * @param  string $oauthToken
     * @param  string $oauthVerifier
     * @return array contains 'oauth_token', 'oauth_token_secret', 'user_id' and 'screen_name'.
     */
    public function getAccessToken($oauthToken, $oauthVerifier)
    {
        //Oauth1 plugin to get access tokens!
        $oauth = new Oauth1(array(
            'consumer_key'    => $this->credentials->getConsumerKey(),
            'consumer_secret' => $this->credentials->getConsumerSecret(),
            'token'           => $oauthToken,
            'verifier'        => $oauthVerifier
        ));

        //attach oauth to request
        $this->guzzleClient->getEmitter()->attach($oauth);

        //POST to 'oauth/access_token' - get access tokens
        $accessTokenResponse = $this->guzzleClient->post(
            Config::get('oauth_access_token'),
            array(
                'auth' => 'oauth'
            )
        );

        //handle response
        $response = array();
        parse_str($accessTokenResponse->getBody(), $response);

        //set access tokens
        $this->credentials
            ->setAccessToken($response['oauth_token'])
            ->setAccessTokenSecret($response['oauth_token_secret']);

        return $response; //contains 'oauth_token', 'oauth_token_secret', 'user_id' and 'screen_name'
    }

    /**
     * Base64 encode the Media located at $mediaPath.
     *
     * @param  string $mediaPath media where it's located
     * @return string
     */
    private function base64EncodeMedia($mediaPath)
    {
        //get media type (extension)
        $type = pathinfo($mediaPath, PATHINFO_EXTENSION);

        //get media data
        $data = file_get_contents($mediaPath);

        //encode the filedata with base64 - and then concatenate to make the encoded string.
        $encodedData = 'data:image/' . $type . ';base64,' . base64_encode($data);

        //return the encoded data
        return $encodedData;
    }

    /**
     * Upload media to Twitter and return a comma separated string containing their
     * media ID's to send with a status.
     *
     * @param  array $filepaths should be a maximum of 4
     * @param  GuzzleHttp\Client $client Optional. To inject your own instance of Guzzle. The base_url of the injected client should be set to Config::get('base_upload_url').
     *
     * @return string|false If a ServerException occurs, return false.
     */
    public function uploadMedia($filepaths, $client = null)
    {

        //maximum number of media files that a user can upload
        $maxMediaIds = Config::get('max_media_ids');

        //if number of media files supplied is larger than $maxMediaIds, throw exception.
        if(count($filepaths) > $maxMediaIds)
        {
            throw new MediaUploadLimitException("You cannot upload more than ${maxMediaIds} media files in a tweet!");
        }

        //array list of media id's uploaded
        $mediaIds = array();

        //create a new Guzzle client, if the user hasn't injected anything!
        if(is_null($client))
        {
            $client = $this->createGuzzleClient(Config::get('base_upload_url'));
        }

        //prepend Twitter's API version to the endpoint
        $endpoint = $this->prependVersionToEndpoint("media/upload.json", Config::get('api_version'));

        //iterate over each filepath
        foreach ($filepaths as $filepath)
        {

            //contruct an options array to configure the request
            $options = $this->constructRequestOptions(array(), $client);

            //add body options to the POST request
            $options['body'] = array (
                'media' => new PostFile('media', fopen($filepath, 'r'))
            );

            //make the POST request to the endpoint with the constructed options.
            $response = $client->post($endpoint, $options);

            //add media_id to array
            array_push($mediaIds, $response->json()['media_id_string']);

        }

        //return all media ID's as a string (comma seperated)
        return (implode(",", $mediaIds));

    }

}


<?php namespace Twitter\Connections;

use Twitter\Config\Config;
use Twitter\Config\AppCredentials;

class AppConnection extends Connection {

    /**
     * An application connection to Twitter.
     *
     * @param AppCredentials $credentials Twitter API credentials
     */
    public function __construct(AppCredentials $credentials)
    {
        parent::__construct($credentials);
    }

    /**
     * Creates and returns an encoded bearer token credentials to be used for making calls to Twitter.
     *
     * Currently:
     *     - URL encode consumer key and consumer secret
     *     - Create bearer token credentials
     *     - Base64 encode the resulting value and return.
     *
     * @link https://dev.twitter.com/docs/auth/application-only-auth Bearer Token Description
     *
     * @return string base64 encoded bearer token.
     */
    private function createBearerCredentials()
    {
        //URL encode the consumer key and consumer secret
        $consumerKey = rawurlencode($this->credentials->getConsumerKey());
        $consumerSecret = rawurlencode($this->credentials->getConsumerSecret());

        //create bearer token credentials by concatenating the consumer key and consumer secret, seperated by a colon.
        $bearerTokenCredentials = $consumerKey . ':' . $consumerSecret;

        //base64 encode the bearer token credentials
        return base64_encode($bearerTokenCredentials);
    }

    /**
     * Calls Twitter and gets a bearer token. This bearer token is valid until it gets invalidated.
     *
     * @link https://dev.twitter.com/docs/auth/application-only-auth Bearer Token Description
     *
     * @return $this AppConnection
     */
    public function createBearerToken()
    {
        //get bearer token credentials - to be used for getting the bearer token from Twitter.
        $bearerCredentials = $this->createBearerCredentials();

        //Required Headers
        $headers = array(
            'Authorization' => 'Basic ' . $bearerCredentials,
            'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8'
        );

        //Required Body
        $body = 'grant_type=client_credentials';

        //Send a Post request to `oauth2/token` and convert the resulting JSON to assoc-array.
        $data = $this->guzzleClient->post(
                Config::get('oauth2_token'),
                array(
                    'headers' => $headers,
                    'body' => $body
                )
            )->json();

        //Set the bearer token in the AppCredentials object
        $this->credentials->setBearerToken($data['access_token']);

        //Return the current object
        return $this;
    }

    /**
     * Constructs an options array that is sent with the request.
     *
     * Uses Bearer Token since this is an AppConnection.
     *
     * @return array options for the request
     */
    protected function constructRequestOptions($params)
    {
        //empty array
        $options = array();

        //add Bearer Token to the header
        $headers = array(
            'Authorization' => 'Bearer ' . $this->credentials->getBearerToken()
        );

        //if query parameters not supplied, continue.
        if(!is_null($params))
        {
            //Add query parameters to options.
            $options['query'] = $params;
        }

        //Add headers to the request.
        $options['headers'] = $headers;

        //return constructed options
        return $options;
    }

}


<?php namespace Twitter\Connections;

use Twitter\Config\Config;
use Twitter\Config\Credentials;
use Twitter\Config\AppCredentials;
use Twitter\Config\UserCredentials;

use GuzzleHttp\Client;
use GuzzleHttp\Subscriber\Oauth\Oauth1;
use GuzzleHttp\Message\RequestInterface;

abstract class Connection {

    /**
     * Twitter Credentials - Connection type.
     *
     * @var AppCredentials|UserCredentials
     */
    protected $credentials;

    /**
     * Guzzle Client to be used during the connection.
     *
     * @var GuzzleHttp\Client
     */
    protected $guzzleClient;

    /**
     * A connection. Contains common methods between AppConnection & UserConnection!
     *
     * @param Credentials $credentials Twitter Credentials
     */
    public function __construct(Credentials $credentials)
    {
        $this->credentials = $credentials;
        $this->guzzleClient = $this->createGuzzleClient(Config::get('base_url'));
    }

    /**
     * Creates a new Guzzle client with Twitter API's base URL and API Version.
     *
     * @param string $baseUrl Base Twitter API URL
     *
     * @return GuzzleHttp\Client A new Guzzle Client
     */
    protected function createGuzzleClient($baseUrl)
    {
        //create and return the Guzzle client
        return new Client(array(
            'base_url' => $baseUrl
        ));
    }

    /**
     * Set Headers for a Request specified by $headers.
     *
     * @param RequestInterface $request a Guzzle Request
     * @param array            $headers headers to set (should be an assoc array).
     */
    private function setGuzzleHeaders(RequestInterface $request, array $headers)
    {
        //iterate over the headers array and set each item
        foreach ($headers as $key => $value) {
            //Sets Header
            $request->setHeader($key, $value);
        }

        //return the request
        return $request;
    }

    /**
     * Prepend Twitter's API Version to an endpoint.
     *
     * @param  string $endpoint Twitter endpoint.
     * @param  string $version  Twitter API version.
     *
     * @return string           Twitter endpoint with the API version prepended.
     */
    protected function prependVersionToEndpoint($endpoint, $version)
    {
        return ($version . '/' . $endpoint);
    }

    /**
     * Constructs an options array that is sent with the request.
     *
     * @return array options for the request
     */
    abstract protected function constructRequestOptions($params);

    /**
     * Make a GET request to the endpoint. Also appends query params to the URL.
     *
     * @param  string $endpoint The endpoint to send a GET request to.
     * @param  array $params   associative array for the query parameters.
     *
     * @link   http://guzzle.readthedocs.org/en/latest/quickstart.html#using-responses ResponseInterface details.
     *
     * @return GuzzleHttp\Message\ResponseInterface API Response. Contains a lot of information.
     */
    public function get($endpoint, $params = null)
    {
        //prepend Twitter's API version to the endpoint
        $endpoint = $this->prependVersionToEndpoint($endpoint, Config::get('api_version'));

        //contruct an options array to configure the request
        $options = $this->constructRequestOptions($params);

        //make the GET request to the endpoint with the constructed options.
        $response = $this->guzzleClient->get($endpoint, $options);

        //return response
        return $response;
    }

    /**
     * Make a POST request to the endpoint. Also appends query params to the URL.
     *
     * @param  string $endpoint The endpoint to send a POST request to.
     * @param  array $params   associative array for the query parameters.
     *
     * @link   http://guzzle.readthedocs.org/en/latest/quickstart.html#using-responses ResponseInterface details.
     *
     * @return GuzzleHttp\Message\ResponseInterface API Response. Contains a lot of information.
     */
    public function post($endpoint, $params)
    {
        //prepend Twitter's API version to the endpoint
        $endpoint = $this->prependVersionToEndpoint($endpoint, Config::get('api_version'));

        //contruct an options array to configure the request
        $options = $this->constructRequestOptions($params);

        //make the GET request to the endpoint with the constructed options.
        $response = $this->guzzleClient->post($endpoint, $options);

        //return response
        return $response;
    }

    /**
     * Gets the Twitter Credentials - Connection type.
     *
     * @return AppCredentials|UserCredentials
     */
    public function getCredentials()
    {
        return $this->credentials;
    }

    /**
     * Sets the Twitter Credentials - Connection type.
     *
     * @param AppCredentials|UserCredentials $credentials the credentials
     *
     * @return self
     */
    protected function setCredentials($credentials)
    {
        $this->credentials = $credentials;

        return $this;
    }

    /**
     * Gets the Guzzle Client to be used during the connection.
     *
     * @return GuzzleHttp\Client
     */
    public function getGuzzleClient()
    {
        return $this->guzzleClient;
    }

    /**
     * Sets the Guzzle Client to be used during the connection.
     *
     * @param GuzzleHttp\Client $guzzleClient the guzzle client
     *
     * @return self
     */
    public function setGuzzleClient(GuzzleHttp\Client $guzzleClient)
    {
        $this->guzzleClient = $guzzleClient;

        return $this;
    }
}


<?php namespace Twitter\Config;

use Twitter\Config\Exceptions\InvalidConfigItemException;

class Config {

    /**
     * Get an item from the 'Config.json' file.
     *
     * @param  string $item the config item to get
     * @return string       the config URL
     *
     * @throws InvalidConfigItemException If the requested config item doesn't exist.
     */
    public static function get($item)
    {
        //convert the item requested to upper, just in case.
        $item = strtoupper($item);

        //get all config items as an associative array from the JSON file
        $config = json_decode(file_get_contents(dirname(__FILE__) . "/Config.json"), true);

        //if the requested config item doesn't exist, throw Twitter\Config\Exceptions\InvalidConfigItemException
        if( !isset($config[$item]) )
        {
            throw new InvalidConfigItemException("Invalid Endpoint Requested!");
        }

        //return the requested item
        return $config[$item];
    }

}