<?php
/**
 * Router.php
 * @author    Daniel Mason <daniel@ayeayeapi.com>
 * @copyright (c) 2015 - 2016 Daniel Mason <daniel@ayeayeapi.com>
 * @license   MIT
 * @see       https://github.com/AyeAyeApi/Api
 */

namespace AyeAye\Api;

use AyeAye\Api\Injector\ControllerReflectorInjector;
use AyeAye\Api\Injector\StatusInjector;

/**
 * Class Router
 * Finds the correct endpoint to process a request
 * @package AyeAye/Api
 * @see     https://github.com/AyeAyeApi/Api
 */
class Router
{
    use ControllerReflectorInjector;
    use StatusInjector;

    /**
     * Look at a request and work out what to do next.
     *
     * Looks at the request chain, takes the first part off, if there is a
     * matching controller, it will load the controller and recurse. If there
     * is a matching endpoint it will call the endpoint passing in the
     * request data.
     *
     * @param Request $request
     * @param Controller $controller
     * @param array $requestChain
     * @return mixed
     * @throws Exception
     */
    public function processRequest(Request $request, Controller $controller, array $requestChain = null)
    {

        $reflectionController = $this->getControllerReflector()->reflectController($controller);

        // If the request chain is null as apposed to empty, we can get it from the request
        if (is_null($requestChain)) {
            $requestChain = $request->getRequestChain();
        }

        // Get the next element of the front of the chain
        $nextLink = array_shift($requestChain);
        if ($nextLink) {
            // If the next element represents a controller, recurse with the new controller and remaining chain
            if ($reflectionController->hasChildController($nextLink)) {
                return $this->processRequest(
                    $request,
                    $reflectionController->getChildController($nextLink),
                    $requestChain
                );
            }

            // If the next element represents an endpoint, call it, passing in the request data
            if ($reflectionController->hasEndpoint($request->getMethod(), $nextLink)) {
                $data = $reflectionController->getEndpointResult($request->getMethod(), $nextLink, $request);
                $this->setStatus($reflectionController->getStatus());
                return $data;
            }

            // If we had another element but it doesn't represent anything, throw an exception.
            $message = "Could not find controller or endpoint matching '$nextLink'";
            throw new Exception($message, 404);
        }

        // If there were no more links in the chain, call the index endpoint if there is one.
        // Index endpoints will prevent automated automatic documentation, which may be undesirable. See below.
        if ($reflectionController->hasEndpoint($request->getMethod(), 'index')) {
            $data = $reflectionController->getEndpointResult($request->getMethod(), 'index', $request);
            $this->setStatus($reflectionController->getStatus());
            return $data;
        }

        // Generate documentation for the current controller and return it.
        return $reflectionController->getDocumentation();
    }
}


<?php
namespace CottaCush\Yii2\HttpResponse;

use yii\helpers\ArrayHelper;
use yii\helpers\Json;

/**
 * Class JSendResponse
 * @package app\libs
 * @author Adegoke Obasa <goke@cottacush.com>
 */
class JSendResponse extends BaseResponse
{
    const RESPONSE_STATUS_PARAM = 'status';
    const RESPONSE_DATA_PARAM = 'data';
    const RESPONSE_CODE_PARAM = 'code';
    const RESPONSE_MESSAGE_PARAM = 'message';
    const RESPONSE_STATUS_SUCCESS = 'success';
    const RESPONSE_STATUS_OK = 'OK';
    const CODE_NO_CODE = '000';
    const ERROR_MESSAGE_AN_UNEXPECTED_ERROR_OCCURRED = 'An unexpected error occurred';

    protected $rawResponse;
    protected $responseParsed = false;

    public function __construct($response, $responseParsed = true)
    {
        parent::__construct($response, $responseParsed);
        if (!$this->responseParsed) {
            $this->parsedResponse = Json::decode($response);
        }
    }

    /**
     * Gets the data from the response
     * @author Adegoke Obasa <goke@cottacush.com>
     * @param null $defaultValue
     * @return mixed
     */
    public function getData($defaultValue = null)
    {
        return ArrayHelper::getValue($this->parsedResponse, self::RESPONSE_DATA_PARAM, $defaultValue);
    }

    /**
     * Gets the error message from the response
     * @author Adegoke Obasa <goke@cottacush.com>
     * @return mixed
     */
    public function getErrorMessage()
    {
        return ArrayHelper::getValue(
            $this->parsedResponse,
            self::RESPONSE_MESSAGE_PARAM,
            self::ERROR_MESSAGE_AN_UNEXPECTED_ERROR_OCCURRED
        );
    }

    /**
     * Gets the response code from the response
     * @author Adegoke Obasa <goke@cottacush.com>
     * @return mixed
     */
    public function getCode()
    {
        return ArrayHelper::getValue($this->parsedResponse, self::RESPONSE_CODE_PARAM, self::CODE_NO_CODE);
    }

    /**
     * Gets the value of key if key exists, default value otherwise
     * @author Adegoke Obasa <goke@cottacush.com>
     * @param $key
     * @param null $default
     * @return mixed
     */
    public function get($key, $default = null)
    {
        return ArrayHelper::getValue(
            $this->parsedResponse,
            sprintf('%s.%s', self::RESPONSE_DATA_PARAM, $key),
            $default
        );
    }

    /**
     * Returns the Status parameter
     * @author Adegoke Obasa <goke@cottacush.com>
     * @return mixed
     */
    public function getStatusParam()
    {
        return self::RESPONSE_STATUS_PARAM;
    }

    /**
     * Returns the value for a success status
     * @author Adegoke Obasa <goke@cottacush.com>
     * @return mixed
     */
    public function getSuccessValue()
    {
        return self::RESPONSE_STATUS_SUCCESS;
    }

    /**
     * Gets the code parameter
     * @author Adegoke Obasa <goke@cottacush.com>
     * @return string
     */
    public function getCodeParam()
    {
        return self::RESPONSE_CODE_PARAM;
    }

    /**
     * Gets the message parameter
     * @author Adegoke Obasa <goke@cottacush.com>
     * @return string
     */
    public function getMessageParam()
    {
        return self::RESPONSE_MESSAGE_PARAM;
    }
}


<?php

namespace Vinelab\Auth\Social\Providers;

use Vinelab\Http\Response;
use Vinelab\Auth\Social\Provider;
use Vinelab\Http\Client as HttpClient;
use Vinelab\Auth\Contracts\StoreInterface;
use Vinelab\Auth\Contracts\ProfileInterface;
use Vinelab\Auth\Exceptions\InvalidProfileException;
use Vinelab\Auth\Exceptions\AuthenticationException;
use Vinelab\Auth\Exceptions\InvalidFacebookCodeException;
use Vinelab\Auth\Social\Providers\Facebook\Contracts\AccessTokenInterface;
use Illuminate\Routing\Redirector;
use Illuminate\Config\Repository as Config;

class Facebook extends Provider
{
    protected $name = 'facebook';

    protected $mandatory = [
        'api_key',
        'secret',
        'redirect_uri',
        'permissions',
        'api_url',
        'authentication_url',
        'token_url',
        'profile_uri',
    ];

    /**
     * The redirector instance.
     *
     * @var Illuminate\Routing\Redirector
     */
    protected $redirect;

    /**
     * The prefix to use when storing
     * keys in the store.
     *
     * @var string
     */
    protected $prefix = 'social:auth:state:';

    /**
     * Create a new Facebook instance.
     *
     * @param Illuminate\Config\Repository            $config
     * @param Illuminate\Routing\Redirector           $redirect
     * @param Vinelab\Http\Client                     $http
     * @param Vinelab\Auth\Contracts\StoreInterface   $store
     * @param Vinelab\Auth\Contracts\ProfileInterface $profile
     */
    public function __construct(Config $config,
                                Redirector $redirect,
                                HttpClient $http,
                                StoreInterface $store,
                                ProfileInterface $profile,
                                AccessTokenInterface $access_token)
    {
        parent::__construct($config);

        $this->config = $config;
        $this->redirect = $redirect;
        $this->http = $http;
        $this->store = $store;
        $this->profile = $profile;
        $this->access_token = $access_token;
    }

    /**
     * Redirects to the corresponding
     * authentication URL.
     */
    public function authenticate()
    {
        $state = $this->makeState();

        $this->store->put($state, $this->settings);

        return $this->redirect->to($this->authURL($state));
    }

    /**
     * Handles the authentication callback
     * returned from the provider.
     *
     * @param mixed $input
     *
     * @return Vinelab\Auth\Contracts\ProfileInterface
     */
    public function callback($input)
    {
        if (isset($input['error'])) {
            throw new AuthenticationException($input['error'].':'.$input['error_description']);
        }

        if (!isset($input['code']) || empty($input['code'])) {
            throw new AuthenticationException('invalid code');
        }

        if (!isset($input['state']) || empty($input['state'])) {
            throw new AuthenticationException('invalid state');
        }

        if (!$this->store->has($input['state'])) {
            throw new AuthenticationException('state expired');
        }

        $access_token = $this->requestAccessToken($input['code']);

        return $this->requestProfile($access_token);
    }

    public function authenticateWithToken($token, $secret = null)
    {
        return $this->requestProfile($this->access_token->makeFromToken($token));
    }

    /**
     * Returns the authentication
     * URL to which we should be
     * redirecting to.
     *
     *
     * @return string
     */
    public function authURL($state)
    {
        $url = $this->settings['authentication_url'];

        $params = [
            'client_id' => $this->settings('api_key'),
            'redirect_uri' => $this->settings('redirect_uri'),
            'scope' => $this->settings('permissions'),
            'state' => $state,
        ];

        return $url.'?'.http_build_query($params);
    }

    /**
     * Requests an access token from Facebook
     * according to the returned code.
     *
     * @param string $code The code returned from Facebook after authentication
     *
     * @return Vinelab\Contracts\AccessTokenInterface
     */
    public function requestAccessToken($code)
    {
        if (!$code || empty($code)) {
            throw new InvalidFacebookCodeException();
        }

        $request = [
            'url' => $this->settings['token_url'],

            'params' => [
                'client_id' => $this->settings['api_key'],
                'redirect_uri' => $this->settings['redirect_uri'],
                'client_secret' => $this->settings['secret'],
                'code' => $code,
                'format' => 'json',
            ],
        ];

        return $this->access_token->make($this->http->get($request));
    }

    /**
     * Sends a request for a Facebook profile
     * using the acquired access token.
     *
     * @param Vinelab\Contracts\AccessTokenInterface $access_token
     *
     * @return Vinelab\Auth\Social\Profile
     */
    public function requestProfile(AccessTokenInterface $access_token)
    {
        $request = [
            'url' => $this->settings['api_url'].$this->settings['profile_uri'],
            'params' => ['access_token' => $access_token->token()],
        ];

        return $this->parseProfileResponse($this->http->get($request), $access_token);
    }

    /**
     * Parses a response coming from Facebook
     * containing a profile.
     *
     * @param Vinelab\Http\Response                  $response
     * @param Vinelab\Contracts\AccessTokenInterface $access_token
     *
     * @return Vinelab\Auth\Social\Profile
     */
    public function parseProfileResponse(Response $response, AccessTokenInterface $access_token)
    {
        $profile = $response->json();

        if (gettype($profile) !== 'object') {
            throw new InvalidProfileException();
        }

        if (isset($profile->error)) {
            $error = $profile->error;

            throw new InvalidProfileException($error->type.': '.$error->message, $error->code);
        }

        $profile->access_token = $access_token->token();

        return $this->profile->instantiate($profile, $this->name);
    }

    /**
     * Generates an returns a random string
     * to be used as authentication state.
     * Also sets the value of the $secret.
     *
     * @return string
     */
    protected function makeState()
    {
        return $this->secret = md5(uniqid(microtime(), true));
    }
}


<?php

namespace mrstroz\wavecms;

use mrstroz\wavecms\components\helpers\FontAwesome;
use mrstroz\wavecms\forms\AddPermissionForm;
use mrstroz\wavecms\forms\AssignRoleForm;
use mrstroz\wavecms\forms\LoginForm;
use mrstroz\wavecms\forms\RequestPasswordResetForm;
use mrstroz\wavecms\forms\ResetPasswordForm;
use mrstroz\wavecms\models\AuthAssignment;
use mrstroz\wavecms\models\AuthItem;
use mrstroz\wavecms\models\AuthItemChild;
use mrstroz\wavecms\models\AuthRule;
use mrstroz\wavecms\models\Message;
use mrstroz\wavecms\models\query\MessageQuery;
use mrstroz\wavecms\models\query\SourceMessageQuery;
use mrstroz\wavecms\models\query\UserQuery;
use mrstroz\wavecms\models\search\SourceMessageSearch;
use mrstroz\wavecms\models\search\UserSearch;
use mrstroz\wavecms\models\SourceMessage;
use mrstroz\wavecms\models\User;
use Yii;
use yii\base\Application;
use yii\base\BootstrapInterface;
use yii\base\Exception;
use yii\base\InvalidConfigException;
use yii\console\Application as ConsoleApplication;
use yii\i18n\PhpMessageSource;
use yii\web\GroupUrlRule;

/**
 * Class Bootstrap
 * @package mrstroz\wavecms
 * Boostrap class for wavecms. Initialize languages, admin navigation, params
 */
class Bootstrap implements BootstrapInterface
{
    /**
     * Bootstrap for wavecms
     * @param \yii\base\Application $app
     * @throws InvalidConfigException
     * @throws Exception
     */
    public function bootstrap($app)
    {
        Yii::setAlias('@wavecms', '@vendor/mrstroz/yii2-wavecms');

        if ($app->id === 'app-backend' || $app->id === 'app-frontend') {

            /** Set extra aliases required in Wavecms with shared hostings*/
            Yii::setAlias('@frontWeb',
                str_replace('/admin', '', Yii::getAlias('@web'))
            );
            Yii::setAlias('@frontWebroot',
                str_replace('/public/admin', '/public', Yii::getAlias('@webroot'))
            );

        }

        /** Set backend language based on user lang (Must be done before define translations */
        if ($app->id === 'app-backend') {
            if (!Yii::$app->user->isGuest) {
                Yii::$app->language = Yii::$app->user->identity->lang;
            }
        }

        $this->initTranslations();

        /** @var Module $module */
        if ($app->hasModule('wavecms') && ($module = $app->getModule('wavecms')) instanceof Module) {

            if ($app instanceof ConsoleApplication) {
                $module->controllerNamespace = 'mrstroz\wavecms\commands';
            } else {
                $module->controllerNamespace = 'mrstroz\wavecms\controllers';

                if ($app->id === 'app-backend') {

                    /** @var string errorAction Set error action */
                    Yii::$app->errorHandler->errorAction = $module->errorAction;

                    /** Set required components */
                    $app->set('wavecms', [
                        'class' => 'mrstroz\wavecms\WavecmsComponent',
                        'languages' => $module->languages
                    ]);

                    $app->set('cacheFrontend', [
                        'class' => 'yii\caching\FileCache',
                        'cachePath' => Yii::getAlias('@frontend') . '/runtime/cache'
                    ]);

                    $app->set('settings', [
                        'class' => 'yii2mod\settings\components\Settings',
                    ]);

                    Yii::$app->assetManager->appendTimestamp = true;

                    Yii::$app->i18n->translations['yii2mod.settings'] = [
                        'class' => 'yii\i18n\PhpMessageSource',
                        'basePath' => '@yii2mod/settings/messages'
                    ];

                    $this->initContainer($module);
                    $this->initLanguages();
                    $this->initParams();
                    $this->initRoutes($app, $module);
                    $this->initNavigation();
                }
            }
        }
    }

    /**
     * Init translations
     */
    protected function initTranslations()
    {
        Yii::$app->i18n->translations['wavecms/*'] = [
            'class' => PhpMessageSource::class,
            'basePath' => '@wavecms/messages',
            'fileMap' => [
                'main' => 'main.php',
                'user' => 'user.php',
            ],
        ];
    }

    /**
     * Init wavecms languages
     * @param $module
     * @throws \yii\base\InvalidConfigException
     */
    protected function initLanguages()
    {
        if (!Yii::$app->user->isGuest) {
            Yii::$app->language = Yii::$app->user->identity->lang;
        }

        if (!isset(Yii::$app->wavecms))
            throw new InvalidConfigException(Yii::t('wavecms/main', 'Component "wavecms" not defined in config.php'));

        if (!count(Yii::$app->wavecms->languages))
            throw new InvalidConfigException(Yii::t('wavecms/main', 'Property "languages" is not defined in config file for component "wavecms"'));

        if (!Yii::$app->session->get('editedLanguage')) {
            Yii::$app->session->set('editedLanguage', Yii::$app->wavecms->languages[0]);
        }

        Yii::$app->wavecms->editedLanguage = Yii::$app->session->get('editedLanguage');
    }

    /**
     * Init required params
     */
    protected function initParams()
    {
        Yii::$app->view->params['h1'] = Yii::t('wavecms/main', '<i>Not set</i>');
        Yii::$app->view->params['buttons_top'] = [];
        Yii::$app->view->params['buttons_btm'] = [];
        Yii::$app->view->params['buttons_sublist'] = [];
    }

    /**
     * Init routes
     * @param Application $app
     * @param Module $module
     * @throws InvalidConfigException
     */
    protected function initRoutes(Application $app, $module)
    {
        $config = [
            'class' => GroupUrlRule::class,
            'rules' => $module->routes,
        ];

        $rule = Yii::createObject($config);
        $app->getUrlManager()->addRules([$rule], false);

        Yii::$app->user->loginUrl = $module->loginUrl;
    }

    /**
     * Init class map and dependency injection container
     * @param Module $module
     * @return void
     * @throws Exception
     */
    protected function initContainer($module)
    {
        $map = [];

        $defaultClassMap = [
            /* FORMS */
            'AddPermissionForm' => AddPermissionForm::class,
            'AssignRoleForm' => AssignRoleForm::class,
            'LoginForm' => LoginForm::class,
            'RequestPasswordResetForm' => RequestPasswordResetForm::class,
            'ResetPasswordForm' => ResetPasswordForm::class,

            /* MODELS */
            'AuthAssignment' => AuthAssignment::class,
            'AuthItem' => AuthItem::class,
            'AuthItemChild' => AuthItemChild::class,
            'AuthRule' => AuthRule::class,
            'Message' => Message::class,
            'SourceMessage' => SourceMessage::class,
            'User' => User::class,

            /* QUERIES */
            'MessageQuery' => MessageQuery::class,
            'SourceMessageQuery' => SourceMessageQuery::class,
            'UserQuery' => UserQuery::class,

            /* SEARCH */
            'SourceMessageSearch' => SourceMessageSearch::class,
            'UserSearch' => UserSearch::class,
        ];

        $routes = [
            'mrstroz\\wavecms\\forms' => [
                'AddPermissionForm',
                'AssignRoleForm',
                'LoginForm',
                'RequestPasswordResetForm',
                'ResetPasswordForm',
            ],
            'mrstroz\\wavecms\\models' => [
                'AuthAssignment',
                'AuthItem',
                'AuthItemChild',
                'AuthRule',
                'Message',
                'SourceMessage',
                'User',
            ],
            'mrstroz\\wavecms\\models\\query' => [
                'MessageQuery',
                'SourceMessageQuery',
                'UserQuery',
            ],
            'mrstroz\\wavecms\\models\\search' => [
                'SourceMessageSearch',
                'UserSearch',
            ]
        ];

        $mapping = array_merge($defaultClassMap, $module->classMap);

        foreach ($mapping as $name => $definition) {
            $map[$this->getContainerRoute($routes, $name) . "\\$name"] = $definition;
        }

        $di = Yii::$container;

        foreach ($map as $class => $definition) {
            /** Check if definition does not exist in container. */
            if (!$di->has($class)) {
                $di->set($class, $definition);
            }
        }

    }

    /**
     * Init left navigation
     */
    protected function initNavigation()
    {
        Yii::$app->params['nav']['wavecms_dashboard'] = [
            'label' => FontAwesome::icon('home') . Yii::t('wavecms/main', 'Dashboard'),
            'url' => ['/'],
            'position' => 500
        ];

        Yii::$app->params['nav']['wavecms_user'] = [
            'label' => FontAwesome::icon('users') . Yii::t('wavecms/user', 'Users'),
            'url' => 'javascript: ;',
            'options' => [
                'class' => 'drop-down'
            ],
            'permission' => 'wavecms-user',
            'position' => 9000,
            'items' => [
                [
                    'label' => FontAwesome::icon('user') . Yii::t('wavecms/user', 'List of users'),
                    'url' => ['/wavecms/user/index']
                ],
                [
                    'label' => FontAwesome::icon('key') . Yii::t('wavecms/user', 'Roles'),
                    'url' => ['/wavecms/role/index']
                ],
            ]
        ];

        Yii::$app->params['nav']['wavecms_settings'] = [
            'label' => FontAwesome::icon('cog') . Yii::t('wavecms/main', 'Settings'),
            'url' => 'javascript: ;',
            'options' => [
                'class' => 'drop-down'
            ],
            'permission' => 'wavecms-settings',
            'position' => 10000,
            'items' => [
                [
                    'label' => FontAwesome::icon('flag') . Yii::t('wavecms/main', 'Translations'),
                    'url' => ['/wavecms/translation/index']
                ],
                [
                    'label' => FontAwesome::icon('database') . Yii::t('wavecms/main', 'Cache'),
                    'url' => ['/wavecms/settings/cache']
                ]
            ]
        ];
    }

    /**
     * Get container route for class name
     * @param array $routes
     * @param $name
     * @throws Exception
     * @return int|string
     */
    private function getContainerRoute(array $routes, $name)
    {
        foreach ($routes as $route => $names) {
            if (in_array($name, $names, false)) {
                return $route;
            }
        }
        throw new Exception("Unknown configuration class name '{$name}'");
    }
}


<?php

namespace mrstroz\wavecms\components\actions;

use mrstroz\wavecms\components\web\Controller;
use Yii;
use yii\base\Action as BaseAction;
use yii\base\InvalidConfigException;
use yii\db\ActiveQuery;
use yii\db\ActiveRecord;
use yii\db\Query;
use yii\web\NotFoundHttpException;

/**
 * Action base class
 */
class Action extends BaseAction
{

    /**
     * @var Controller $controller
     */
    public $controller;

    /**
     * @var Query $query
     */
    public $query;

    /**
     * @var ActiveRecord $modelClass
     */
    public $modelClass;

    /**
     * @var string $tableName
     */
    public $tableName;

    /**
     * Init query and modelClass
     * @throws InvalidConfigException
     */
    public function init()
    {
        $this->query = $this->controller->query;
        if ($this->query) {
            $modelClass = Yii::createObject($this->query->modelClass);
            $this->modelClass = $modelClass;
            $this->tableName = $modelClass::tableName();
        }

        parent::init(); // TODO: Change the autogenerated stub
    }

    /**
     * Function to get one model by id. Using in crete/update/page action
     * @param $id
     * @return ActiveRecord
     * @throws \yii\web\NotFoundHttpException
     * @throws InvalidConfigException
     */
    protected function _fetchOne($id)
    {

        /** @var ActiveRecord $model */
        $model = $this->query->andWhere([$this->tableName. '.id' => $id])->one();

        if (!$model)
            throw new NotFoundHttpException(Yii::t('wavecms/main', 'Element not found'));

        if ($this->controller->scenario) {
            $model->scenario = $this->controller->scenario;
        }

        return $model;
    }

    /**
     * Check if $this->query is set
     * @throws \yii\base\InvalidConfigException
     */
    protected function _checkConfig()
    {
        if (!$this->controller->query)
            throw new InvalidConfigException(Yii::t('wavecms/main', 'The "query" property must be set.'));

        if (!$this->controller->query instanceof ActiveQuery)
            throw new InvalidConfigException(Yii::t('wavecms/main', 'The "query" property is not instance of ActiveQuery.'));
    }

    /**
     *
     * @return array
     */
    protected function _forwardParams()
    {
        $return = [];

        foreach ($this->controller->forwardParams as $param) {
            $return[$param] = Yii::$app->request->get($param);
        }

        return $return;
    }
}


<?php

namespace CottaCush\Yii2\Text;

use CottaCush\Yii2\Template\HandlebarsTemplatingEngine;
use Hashids\Hashids;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;

/**
 * Class Utils
 * @package app\libs
 * @author Olawale Lawal <wale@cottacush.com>
 * @codeCoverageIgnore
 */
class Utils
{
    const MIN_HASH_LENGTH = 12;

    /**
     * @author Olawale Lawal <wale@cottacush.com>
     * @param $text
     * @param int $untouchedLength
     * @param string $char
     * @return string
     */
    public static function asteriskise($text, $untouchedLength = 6, $char = '*')
    {
        $length = strlen($text);
        if ($length <= $untouchedLength) {
            return str_repeat($char, $length);
        }

        $asteriskLength = $length - $untouchedLength;
        $asterisk = str_repeat($char, $asteriskLength);

        $maxLength = $length - $asteriskLength;
        $start = $maxLength / 2;
        $end = $length - $maxLength;
        return substr_replace($text, $asterisk, $start, $end);
    }

    /**
     * Encodes an id into an hash
     * @author Adegoke Obasa <goke@cottacush.com>
     * @param $id
     * @param $salt
     * @param int $hashLength
     * @return string
     * @throws \Exception
     */
    public static function encodeId($id, $salt, $hashLength = self::MIN_HASH_LENGTH)
    {
        $hashIds = new Hashids($salt, $hashLength);
        return $hashIds->encode($id);
    }

    /**
     * Decodes a hash into an id
     * @author Adegoke Obasa <goke@cottacush.com>
     * @param $hash
     * @param $salt
     * @param int $hashLength
     * @return int
     * @throws \Exception
     */
    public static function decodeId($hash, $salt, $hashLength = self::MIN_HASH_LENGTH)
    {
        $hashIds = new Hashids($salt, $hashLength);
        return ArrayHelper::getValue($hashIds->decode($hash), '0');
    }

    /**
     * Returns the styled label for the status
     * @author Olajide Oye <jide@cottacush.com>
     * @author Olawale Lawal <wale@cottacush.com>
     * @param $status
     * @param string $extraClasses
     * @param string $baseClass
     * @param string $tag
     * @return string
     */
    public static function getStatusHtml($status, $extraClasses = '', $baseClass = 'label', $tag = 'span')
    {
        $status = strtolower($status);
        $statusHyphenated = implode('-', explode(' ', $status));
        $class = trim("{$baseClass} {$baseClass}-$statusHyphenated $extraClasses");
        return Html::tag($tag, $status, ['class' => $class]);
    }

    /**
     * Returns the international format of the given number
     * @author Adeyemi Olaoye <yemi@cottacush.com>
     * @param $countryCode
     * @param $number
     * @param $numberLength
     * @return string
     */
    public static function formatPhoneNumberToInternationalFormat($countryCode, $number, $numberLength)
    {
        $actualNumber = substr($number, -($numberLength), $numberLength);

        if (!$actualNumber) {
            return $number;
        }

        return '+' . $countryCode . $actualNumber;
    }

    /**
     * @author Olawale Lawal <wale@cottacush.com>
     * @param array $base
     * @param array $challenger
     * @return bool
     */
    public static function isArrayDifferent($base, $challenger)
    {
        return count($base) != count($challenger) || array_diff($challenger, $base);
    }

    /**
     * @author Olawale Lawal <wale@cottacush.com>
     * @param array $array
     * @return array
     */
    public static function flattenArray($array)
    {
        $result = array();

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

        foreach ($array as $key => $value) {
            if (is_array($value)) {
                $result = array_merge($result, self::flattenArray($value));
            } else {
                $result = array_merge($result, array($key => $value));
            }
        }

        return $result;
    }

    /**
     * @param $amount
     * @return string
     */
    public static function formatToNaira($amount)
    {
        if (is_null($amount) || !is_numeric($amount)) {
            return $amount;
        }

        return number_format($amount, 2) . 'NGN';
    }

    /**
     * @author Kehinde Ladipo <kehinde.ladipo@cottacush.com>
     * @param $template
     * @param array $params
     * @return string
     */
    public static function getActualMessage($template, array $params)
    {
        $engine = new HandlebarsTemplatingEngine();
        return $engine->renderTemplate($template, $params);
    }
}


<?php

namespace mrstroz\wavecms\components\web;

use dosamigos\editable\EditableAction;
use himiklab\sortablegrid\SortableGridAction;
use mrstroz\wavecms\components\actions\BulkDeleteAction;
use mrstroz\wavecms\components\actions\BulkPublishAction;
use mrstroz\wavecms\components\actions\BulkUnpublishAction;
use mrstroz\wavecms\components\actions\CreateAction;
use mrstroz\wavecms\components\actions\DeleteAction;
use mrstroz\wavecms\components\actions\DeleteSubListAction;
use mrstroz\wavecms\components\actions\IndexAction;
use mrstroz\wavecms\components\actions\PageAction;
use mrstroz\wavecms\components\actions\PublishAction;
use mrstroz\wavecms\components\actions\SettingsAction;
use mrstroz\wavecms\components\actions\SubListAction;
use mrstroz\wavecms\components\actions\UpdateAction;
use mrstroz\wavecms\components\actions\UpDownAction;
use Yii;
use yii\data\ActiveDataProvider;
use yii\db\ActiveQuery;
use yii\db\ActiveRecord;
use yii\filters\AccessControl;
use yii\filters\VerbFilter;

/**
 * Class Controller
 * @package mrstroz\wavecms\components\web
 * Main controller class used to manage data in Wavecms modules
 */
class Controller extends BaseController
{

    /**
     * @var string Type of controller (list,page,settings)
     */
    public $type = 'list';

    /**
     * @var ActiveQuery Query object
     */
    public $query;

    /**
     * @var string Class name of the model which will be used to validate the attributes in settings action
     */
    public $modelClass;

    /**
     * @var string Scenario for model
     */
    public $scenario;

    /**
     * @var ActiveDataProvider DataProvider for index grid
     */
    public $dataProvider;

    /**
     * @var ActiveRecord filter model for GridViews on index action
     */
    public $filterModel;

    /**
     * @var array Columns displayed in GridView on index action
     */
    public $columns = [];

    /**
     * @var string Index view
     */
    public $viewIndex = '@wavecms/views/crud/index';

    /**
     * @var string Sublist view
     */
    public $viewSubList = '@wavecms/views/crud/subList';

    /**
     * @var string Form view used for create, update, page, settings action
     */
    public $viewForm = 'form';

    /**
     * @var bool Set if GridView is sortable by drag & drop
     */
    public $sort = false;

    /** @var bool Automatically set to true when Model has publishColumn */
    public $publish = false;

    /**
     * @var string Model column used for publish
     */
    public $publishColumn = 'publish';

    /**
     * @var static Heading for index and create / update pages
     */
    public $heading;

    /**
     * @var array Url used for "Return" button and redirects to back to parent page
     */
    public $returnUrl;

    /**
     * @var array List of GET params that should be forwarded to each actions
     */
    public $forwardParams = [];

    /**
     * @var array List of active actions to set in left menu
     */
    public $activeActions = ['create', 'update', 'page'];

    /**
     * @var array Available bulk actions
     */
    public $bulkActions;

    /**
     * @var string Event after model create
     */
    const EVENT_AFTER_MODEL_CREATE = 'eventAfterModelCreate';
    const EVENT_BEFORE_MODEL_SAVE = 'eventBeforeModelSave';
    const EVENT_AFTER_MODEL_SAVE = 'eventAfterModelSave';
    const EVENT_CONTROLLER_INIT = 'eventControllerInit';
    const EVENT_BEFORE_RENDER = 'eventBeforeRender';

    public function init()
    {
        if ($this->query) {
            if ($this->bulkActions === null) {
                $this->bulkActions['bulk-delete'] = Yii::t('wavecms/main', 'Delete');

                /** @var ActiveRecord $modelClass */
                $modelClass = Yii::createObject($this->query->modelClass);

                if ($modelClass->hasAttribute($this->publishColumn)) {
                    $this->bulkActions['bulk-publish'] = Yii::t('wavecms/main', 'Publish');
                    $this->bulkActions['bulk-unpublish'] = Yii::t('wavecms/main', 'Unpublish');
                }
            }
        }

        parent::init(); // TODO: Change the autogenerated stub
    }

    /**
     * Actions
     * @return array
     */
    public function actions()
    {
        $actions = [];

        if ($this->type === 'list') {
            if (isset($this->query)) {
                $actions['sort'] = [
                    'class' => SortableGridAction::className(),
                    'modelName' => $this->query->modelClass
                ];
            }

            $actions['index'] = [
                'class' => IndexAction::className()
            ];

            $actions['sub-list'] = [
                'class' => SubListAction::className()
            ];

            $actions['create'] = [
                'class' => CreateAction::className()
            ];

            $actions['update'] = [
                'class' => UpdateAction::className()
            ];

            $actions['delete'] = [
                'class' => DeleteAction::className()
            ];

            $actions['delete-sub-list'] = [
                'class' => DeleteSubListAction::className()
            ];

            $actions['publish'] = [
                'class' => PublishAction::className()
            ];

            $actions['up-down'] = [
                'class' => UpDownAction::className()
            ];

            if (isset($this->query)) {
                $actions['editable'] = [
                    'class' => EditableAction::className(),
                    'modelClass' => $this->query->modelClass
                ];
            }

            if (isset($this->bulkActions['bulk-delete'])) {
                $actions['bulk-delete'] = [
                    'class' => BulkDeleteAction::className()
                ];
            }

            if (isset($this->bulkActions['bulk-publish'])) {
                $actions['bulk-publish'] = [
                    'class' => BulkPublishAction::className()
                ];
            }

            if (isset($this->bulkActions['bulk-unpublish'])) {
                $actions['bulk-unpublish'] = [
                    'class' => BulkUnpublishAction::className()
                ];
            }
        }

        if ($this->type === 'page') {
            $actions['page'] = [
                'class' => PageAction::className()
            ];
        }

        if ($this->type === 'settings') {
            $actions['settings'] = [
                'class' => SettingsAction::className()
            ];
        }

        return $actions;
    }

    /**
     * Behaviors
     * @return array
     */
    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::className(),
                'rules' => [
                    [
                        'allow' => true,
                        'actions' => [
                            'index',
                            'sub-list',
                            'create',
                            'update',
                            'delete',
                            'delete-sub-list',
                            'publish',
                            'up-down',
                            'editable',
                            'bulk-delete',
                            'bulk-publish',
                            'bulk-unpublish',
                            'sort',
                            'page',
                            'settings',
                        ],
                        'roles' => [
                            '@'
                        ],
                    ]
                ],
            ],
            'verbs' => [
                'class' => VerbFilter::className(),
                'actions' => [
                ],
            ],
        ];
    }
}


<?php

namespace Vinelab\Auth\Social\Providers;

use Vinelab\Auth\Social\Provider;
use Vinelab\Http\Client as HttpClient;
use Illuminate\Config\Repository as Config;
use Illuminate\Routing\Redirector;
use Vinelab\Auth\Contracts\StoreInterface;
use Vinelab\Auth\Contracts\ProfileInterface;
use Vinelab\Auth\Social\Providers\Twitter\Contracts\OAuthInterface;
use Vinelab\Auth\Social\Providers\Twitter\Contracts\OAuthTokenInterface;
use Vinelab\Auth\Social\Providers\Twitter\Contracts\OAuthConsumerInterface;
use Vinelab\Auth\Social\Providers\Twitter\Contracts\OAuthSignatureInterface;
use Vinelab\Auth\Exceptions\TwitterProfileException;
use Vinelab\Auth\Exceptions\InvalidOAuthTokenException;
use Vinelab\Auth\Exceptions\AuthenticationCanceledException;

class Twitter extends Provider
{
    protected $name = 'twitter';

    protected $mandatory = [
        'version',
        'consumer_key',
        'consumer_secret',
        'auth_api_url',
        'access_token_uri',
        'authentication_uri',
        'authorization_uri',
        'request_token_uri',
    ];

    /**
     * The data exchange format.
     *
     * @var string
     */
    protected $format = 'json';

    /**
     * The OAuth signature instance.
     *
     * @var Vinelab\Auth\Social\Providers\Twitter\Contracts\OAuthSignatureInterface
     */
    protected $signature;

    /**
     * The consumer instance.
     *
     * @var Vinelab\Auth\Social\Providers\Twitter\Contracts\OAuthConsumerInterface
     */
    protected $consumer;

    /**
     * The prefix of the store keys.
     *
     * @var string
     */
    protected $prefix = 'social:auth:twitter:token:';

    public function __construct(Config $config,
                                HttpClient $http,
                                Redirector $redirect,
                                StoreInterface $store,
                                ProfileInterface $profile,
                                OAuthSignatureInterface $signature,
                                OAuthConsumerInterface $consumer,
                                OAuthTokenInterface $token,
                                OAuthInterface $oauth)
    {
        parent::__construct($config);

        $this->http = $http;
        $this->signature = $signature;
        $this->consumer = $consumer;
        $this->oauth = $oauth;
        $this->token = $token;
        $this->redirect = $redirect;
        $this->store = $store;
        $this->profile = $profile;

        $this->consumer->make(
            $this->settings('consumer_key'),
            $this->settings('consumer_secret')
        );
    }

    /**
     * Authenticate with Twitter.
     */
    public function authenticate()
    {
        $request_token = $this->oauth->getRequestToken($this->settings, $this->consumer, $this->token);

        $auth_url = $this->settings('auth_api_url').$this->settings('authentication_uri');
        $auth_url .= '?'.http_build_query(['oauth_token' => $request_token->key]);

        return $this->redirect->to($auth_url);
    }

    /**
     * Handle the callback from a previous
     * authentication request.
     *
     * @param array $input
     *
     * @return Vinelab\Auth\Contracts\ProfileInterface
     */
    public function callback($input)
    {
        if (isset($input['denied'])) {
            throw new AuthenticationCanceledException();
        }

        if (!isset($input['oauth_token']) || !isset($input['oauth_verifier'])) {
            throw new InvalidOAuthTokenException('missing oauth_token or oauth_verifier');
        }

        $verifier_token = $this->token->verifier($input['oauth_token'], $input['oauth_verifier']);
        $access_token = $this->oauth->getAccessToken($this->settings, $this->consumer, $verifier_token);

        return $this->getProfile($access_token);
    }

    public function authenticateWithToken($token, $secret = null)
    {
        return $this->getProfile($this->token->make($token, $secret));
    }

    public function getProfile(OAuthTokenInterface $token)
    {
        $url = $this->api($this->settings('verify_credentials_uri'));
        $options = ['Content-Type: application/x-www-form-urlencoded'];

        $headers = $this->oauth->headers($this->settings, 'GET', $url, $this->consumer, $token);
        $headers = array_merge($headers, $options);

        $response = $this->http->get(compact('url', 'headers'));

        if ($response->statusCode() == 200) {
            return $this->profile->instantiate($response->json(), 'twitter');
        }

        throw new TwitterProfileException('invalid response');
    }

    public function api($uri)
    {
        return $this->settings('api_url').'/'.$this->settings('version').$uri.'.'.$this->format;
    }

    /**
     * Generates a key to be used in the store.
     *
     * @param string $key
     *
     * @return string
     */
    protected function storeKey($key)
    {
        return $this->prefix.$key;
    }
}


<?php
/**
 * Custom Rating Grifus · Extensions For Grifus
 *
 * @author    Josantonius <hello@josantonius.com>
 * @package   Josantonius/Custom-Rating-Grifus
 * @copyright 2017 - 2018 (c) Josantonius - Custom Rating Grifus
 * @license   GPL-2.0+
 * @link      https://github.com/eliasis-framework/custom-rating-grifus.git
 * @since     1.0.0
 */

namespace EFG\Modules\CustomRatingGrifus\Model;

use Eliasis\Framework\Model;
use Eliasis\Complement\Type\Module;

/**
 * Module main model.
 */
class Launcher extends Model {

	/**
	 * Create database tables.
	 */
	public function create_tables() {

		global $wpdb;

		$charset_collate = $wpdb->get_charset_collate();

		$table_name = $wpdb->prefix . 'efg_custom_rating';

		if ( $wpdb->get_var( "SHOW TABLES LIKE '$table_name'" ) != $table_name ) {
			$sql = "CREATE TABLE $table_name (
	          id      mediumint(9) NOT NULL AUTO_INCREMENT,
	          post_id mediumint(9) NOT NULL,
	          ip      varchar(45)  NOT NULL,
	          vote    int(2)       NOT NULL,
	          PRIMARY KEY  (id)
	        ) $charset_collate;";

			require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );

			dbDelta( $sql );
		}
	}

	/**
	 * Set database module options.
	 *
	 * @since 1.0.1
	 */
	public function add_options() {

		$slug = Module::CustomRatingGrifus()->getOption( 'slug' );

		if ( ! get_option( $slug . '-restart-when-add' ) ) {
			add_option( $slug . '-restart-when-add', 1 );
		}
	}

	/**
	 * Get database module options.
	 *
	 * @since 1.0.1
	 *
	 * @uses get_option()
	 *
	 * @return array
	 */
	public function get_options() {

		$slug = Module::CustomRatingGrifus()->getOption( 'slug' );

		return [
			'restart-when-add' => get_option( $slug . '-restart-when-add' ),
		];
	}

	/**
	 * Delete database module options.
	 *
	 * @since 1.0.1
	 */
	public function delete_options() {

		$slug = Module::CustomRatingGrifus()->getOption( 'slug' );

		delete_option( $slug . '-restart-when-add', true );
	}

	/**
	 * Remove database tables.
	 */
	public function remove_tables() {

		global $wpdb;

		$table_name = $wpdb->prefix . 'efg_custom_rating';
		$wpdb->query( "DROP TABLE IF EXISTS $table_name" );
	}

	/**
	 * Delete post meta by key.
	 */
	public function delete_post_meta() {

		delete_post_meta_by_key( 'imdbTotalVotes' );
	}
}


<?php

namespace mrstroz\wavecms\components\behaviors;

use Yii;
use yii\base\Behavior;
use yii\base\InvalidConfigException;
use yii\db\ActiveRecord;
use yii\helpers\FileHelper;
use yii\web\UploadedFile;

/**
 * Class FileBehavior
 * @package mrstroz\wavecms\components\behaviors
 * Behavior used for save files in WaveCMS
 */
class FileBehavior extends Behavior
{

    /**
     * @var string Attribute used in behavior
     */
    public $attribute;

    /**
     * @var string Folder name used for save files
     */
    public $folder = 'files';

    /**
     * Events
     * @inheritdoc
     * @return array
     */
    public function events()
    {
        return [
            ActiveRecord::EVENT_BEFORE_INSERT => 'uploadFile',
            ActiveRecord::EVENT_BEFORE_UPDATE => 'uploadFile',
            ActiveRecord::EVENT_AFTER_DELETE => 'deleteFile'
        ];
    }

    /**
     * Init function
     * @inheritdoc
     * @throws InvalidConfigException
     */
    public function init()
    {

        if (!$this->attribute) {
            throw new InvalidConfigException(Yii::t('wavecms/main', 'Property "attribute" is not defined in FileBehavior'));
        }

        parent::init();
    }

    /**
     * Upload files on save and update event
     * @param $event
     * @throws InvalidConfigException
     * @throws \yii\base\Exception
     */
    public function uploadFile($event)
    {
        if (!array_key_exists($this->attribute, $event->sender->attributes)) {
            throw new InvalidConfigException(Yii::t('wavecms/main', 'Attribute {attribute} not found in model {model}', ['attribute' => $this->attribute, 'model' => $event->sender->className()]));
        }

        $oldFile = false;
        if (isset($event->sender->oldAttributes[$this->attribute])) {
            $oldFile = $event->sender->oldAttributes[$this->attribute];
        }

        $uploadedFile = UploadedFile::getInstance($event->sender, $this->attribute);

        if (null !== $uploadedFile && $uploadedFile->size !== 0) {

            $folder = $this->getWebrootFolder();

            if ($oldFile) {
                $this->unlinkFiles($oldFile);
            }

            $baseName = $uploadedFile->baseName;
            $fileName = $baseName . '.' . $uploadedFile->extension;

            while (@file_exists($folder . '/' . $fileName)) {
                $baseName .= '_';
                $fileName = $baseName . '.' . $uploadedFile->extension;
            }

            FileHelper::createDirectory($folder, 0777);
            $uploadedFile->saveAs($folder . '/' . $fileName);

            $event->sender->{$this->attribute} = $fileName;
        } else {
            if (Yii::$app->request->post($this->attribute . '_file_delete')) {
                $this->unlinkFiles($oldFile);
                $event->sender->{$this->attribute} = null;
            } else {
                $event->sender->{$this->attribute} = $oldFile;
            }
        }
    }

    /**
     * Delete file on delete event
     * @param $event
     */
    public function deleteFile($event)
    {
        $this->unlinkFiles($event->sender->{$this->attribute});
    }

    /**
     * Helper function
     * @return string
     */
    public function getWebFolder()
    {
        return Yii::getAlias('@frontWeb') . '/' . $this->folder;
    }

    /**
     * Helper function
     * @return string
     */
    public function getWebrootFolder()
    {
        return Yii::getAlias('@frontWebroot') . '/' . $this->folder;
    }

    /**
     * Helper function used for unlink files
     * @return string
     */
    public function unlinkFiles($fileName)
    {
        $folder = $this->getWebrootFolder();

        if ($fileName) {
            if (@file_exists($folder . '/' . $fileName)) {
                unlink($folder . '/' . $fileName);
            }
        }
    }
}


<?php

namespace Creitive\Monolog\Processor;

/**
 * Injects arbitrary extra data in all records.
 *
 * @author Miloš Levačić <milos@levacic.net>
 */
class ExtraDataProcessor
{
    /**
     * The currently configured extra data.
     *
     * @var array
     */
    protected $extraData = [];

    /**
     * Create a new processor instance.
     *
     * @param array $extraData Extra data to be added
     */
    public function __construct(array $extraData = [])
    {
        $this->setExtraData($extraData);
    }

    /**
     * Magic method for instance invokation as a function.
     *
     * Merges the passed record's `extra` entry with the configured extra data
     * (overwriting existing keys), and returns the record.
     *
     * @param array $record
     * @return array
     */
    public function __invoke(array $record)
    {
        $record['extra'] = $this->appendExtraFields($record['extra']);

        return $record;
    }

    /**
     * Adds the extra data into the passed array.
     *
     * @param array $extra
     * @return array
     */
    private function appendExtraFields(array $extra)
    {
        foreach ($this->extraData as $key => $value) {
            $extra[$key] = $value;
        }

        return $extra;
    }

    /**
     * Sets all extra data.
     *
     * @param array $extraData
     */
    public function setExtraData(array $extraData = [])
    {
        $this->extraData = $extraData;
    }

    /**
     * Returns the currently configured extra data.
     *
     * @return array
     */
    public function getExtraData()
    {
        return $this->extraData;
    }

    /**
     * Adds more extra data into the processor.
     *
     * Overwrites existing data without warning.
     *
     * @param array $extraData
     * @return void
     */
    public function addExtraData(array $extraData = [])
    {
        foreach ($extraData as $key => $data) {
            $this->extraData[$key] = $data;
        }
    }

    /**
     * Removes the passed extra data keys.
     *
     * @param array $extraDataKeys
     * @return void
     */
    public function removeExtraData(array $extraDataKeys = [])
    {
        foreach ($extraDataKeys as $key) {
            if (array_key_exists($key, $this->extraData)) {
                unset($this->extraData[$key]);
            }
        }
    }
}


<?php

namespace Vinelab\Auth\Social\Providers\Twitter;

use Vinelab\Http\Client as HttpClient;
use Vinelab\Auth\Social\Providers\Twitter\Contracts\OAuthTokenInterface;
use Vinelab\Auth\Social\Providers\Twitter\Contracts\OAuthConsumerInterface;
use Vinelab\Auth\Social\Providers\Twitter\Contracts\OAuthSignatureInterface;

class OAuth implements Contracts\OAuthInterface
{
    /**
     * The request signature interface.
     *
     * @var Vinelab\Auth\Social\Providers\Twitter\Contracts\OAuthSignatureInterface
     */
    protected $signature;

    /**
     * Create a new OAuth instance.
     *
     * @param Vinelab\Auth\Social\Providers\Twitter\Contracts\OAuthTokenInterface     $token
     * @param Vinelab\Auth\Social\Providers\Twitter\Contracts\OAuthSignatureInterface $signature
     * @param Vinelab\Http\Client                                                     $http
     */
    public function __construct(OAuthTokenInterface $token,
                                OAuthSignatureInterface $signature,
                                HttpClient $http)
    {
        $this->token = $token;
        $this->http = $http;
        $this->signature = $signature;
    }

    /**
     * Requests Twitter for a request token.
     *
     * @param array                                                                  $settings
     * @param Vinelab\Auth\Social\Providers\Twitter\Contracts\OAuthConsumerInterface $consumer
     * @param Vinelab\Auth\Social\Providers\Twitter\Contracts\OAuthTokenInterface    $token
     *
     * @return Vinelab\Auth\Social\Providers\Twitter\Contracts\OAuthTokenInterface
     */
    public function getRequestToken($settings,
                                    OAuthConsumerInterface $consumer,
                                    OAuthTokenInterface $token)
    {
        $url = $settings['auth_api_url'].$settings['request_token_uri'];
        $options = ['oauth_callback' => $settings['callback_url']];

        $headers = $this->headers($settings, 'POST', $url, $consumer, $token, $options);
        // build request
        $request = ['url' => $url,'headers' => $headers];

        return $this->token->makeRequestToken($this->http->post($request));
    }

    /**
     * Transforms a verifier (request) token
     * into an access token.
     *
     * @param array                                                                  $settings
     * @param Vinelab\Auth\Social\Providers\Twitter\Contracts\OAuthConsumerInterface $consumer
     * @param Vinelab\Auth\Social\Providers\Twitter\Contracts\OAuthTokenInterface    $token
     *
     * @return Vinelab\Auth\Social\Providers\Twitter\Contracts\OAuthTokenInterface
     */
    public function getAccessToken($settings,
                                    OAuthConsumerInterface $consumer,
                                    OAuthTokenInterface $token)
    {
        $url = $settings['auth_api_url'].$settings['access_token_uri'];
        $params = ['oauth_verifier' => $token->verifier];
        $options = [
                'Content-Type: application/x-www-form-urlencoded',
                'Content-Length: '.strlen(http_build_query($params)),
        ];

        $headers = $this->headers($settings, 'POST', $url, $consumer, $token, $options);

        // build request
        $request = compact('url', 'headers', 'params');

        return $this->token->makeAccessToken($this->http->post($request));
    }

    public function headers($settings,
                            $httpverb,
                            $url,
                            OAuthConsumerInterface $consumer,
                            OAuthTokenInterface $token,
                            $options = [])
    {
        $headers = [
            'oauth_consumer_key' => $consumer->key,
            'oauth_nonce' => $this->generateNonce(),
            'oauth_signature_method' => $this->signature->method(),
            'oauth_timestamp' => $this->generateTimestamp(),
            'oauth_version' => '1.0',
        ];

        // check for a token to be added
        if (!is_null($token->key)) {
            $headers['oauth_token'] = $token->key;
        }

        // merge options with headers
        $headers = array_merge($headers, $options);

        // add signature
        $headers['oauth_signature'] = $this->signature->get($consumer, $token, $httpverb, $url, $headers);

        uksort($headers, 'strcmp');

        // normalize
        $headers = $this->normalizeHeaders($headers);

        return [
            'Authorization: OAuth '.$headers,
            'User-Agent: '.$settings['user_agent'],
        ];
    }

    /**
     * Transforms a parameters array into
     * a series of strings compatible to be
     * embedded in a request header.
     *
     * @param array $params
     *
     * @return string
     */
    public function normalizeHeaders($params)
    {
        $out = '';

        foreach ($params as $key => $param) {
            $out .= $key.'="'.rawurlencode(trim($param)).'",';
        }

        return rtrim($out, ',');
    }

    /**
     * Generates a request nonce.
     *
     * @return string
     */
    public function generateNonce()
    {
        return md5(microtime().mt_rand());
    }

    /**
     * Generates a request timestamp.
     *
     * @return int
     */
    public function generateTimestamp()
    {
        return time();
    }
}


<?php
/**
 * Api.php
 * @author    Daniel Mason <daniel@ayeayeapi.com>
 * @copyright (c) 2015 - 2016 Daniel Mason <daniel@ayeayeapi.com>
 * @license   MIT
 * @see       https://github.com/AyeAyeApi/Api
 */

namespace AyeAye\Api;

use AyeAye\Api\Exception as AyeAyeException;
use AyeAye\Api\Injector\LoggerInjector;
use AyeAye\Api\Injector\RequestInjector;
use AyeAye\Api\Injector\ResponseInjector;
use AyeAye\Api\Injector\RouterInjector;
use AyeAye\Api\Injector\WriterFactoryInjector;
use AyeAye\Formatter\Writer\Json;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LogLevel;

/**
 * Class Api
 * Quick start your API with this class
 * @package AyeAye/Api
 * @see     https://github.com/AyeAyeApi/Api
 */
class Api implements LoggerAwareInterface
{
    use LoggerInjector;
    use RequestInjector;
    use ResponseInjector;
    use RouterInjector;
    use WriterFactoryInjector;

    /**
     * The starting controller for the Api
     * @var Controller
     */
    protected $controller;

    /**
     * Set up the API
     *
     * Initialise the API with a controller that forms the starting point of
     * routing information.
     *
     * @param Controller      $initialController The starting point for the Api
     */
    public function __construct(Controller $initialController)
    {
        $this->controller = $initialController;
    }

    /**
     * Write to the logger.
     *
     * Implementing the PSR LogAware interface.
     *
     * @param integer $level
     * @param string  $message
     * @param array   $context
     * @return $this
     */
    protected function log($level, $message, array $context = array())
    {
        $this->getLogger()->log($level, $message, $context);
        return $this;
    }

    /**
     * Process the request, get a response and return it.
     *
     * Exceptions thrown in most places will be handled here.
     * Currently there's no nice way to handle exceptions in Response::respond
     *
     * @return Response
     * @SuppressWarnings(PHPMD.ShortMethodName)
     */
    public function go()
    {
        $response = $this->getResponse();

        try {
            $request = $this->getRequest();
            $response->setWriterFactory(
                $this->getWriterFactory()
            );
            $response->setRequest(
                $request
            );
            $response->setBodyData(
                $this->getRouter()->processRequest(
                    $this->getRequest(),
                    $this->controller
                )
            );
            $response->setStatus(
                $this->controller->getStatus()
            );
        } catch (AyeAyeException $e) {
            $this->log(LogLevel::INFO, $e->getPublicMessage());
            $this->log(LogLevel::ERROR, $e->getMessage(), ['exception' => $e]);
            $response->setBodyData($e->getPublicMessage());
            $response->setStatus(new Status($e->getCode()));
        } catch (\Exception $e) {
            $status = new Status(500);
            $this->log(LogLevel::CRITICAL, $e->getMessage(), ['exception' => $e]);
            $response->setBodyData($status->getMessage());
            $response->setStatus($status);
        }

        // Ultimate fail safe
        try {
            $response->prepareResponse();
        } catch (\Exception $e) {
            $this->log(LogLevel::CRITICAL, $e->getMessage(), ['exception' => $e]);
            return $this->createFailSafeResponse();
        }

        return $response;
    }

    /**
     * Returns a standardised 500 error.
     *
     * To be used in the event of a catastrophic failure, this method creates
     * all new objects, ignoring dependency injection and returns in JSON.
     *
     * This will be problematic for users expecting a response in a format
     * other than JSON and should only be called if the format they are
     * actually expecting can not be provided when using
     * Response::prepareResponse.
     *
     * @return Response
     */
    protected function createFailSafeResponse()
    {
        $status = new Status(500);
        $response = new Response();
        $response->setRequest(new Request());
        $response->setWriter(new Json());
        $response->setStatus($status);
        $response->setBodyData($status->getMessage());
        return $response;
    }
}


<?php

namespace Circuit\Middleware;

use Circuit\Interfaces\Middleware;
use Circuit\Interfaces\Delegate;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * Error Logger
 *
 * A middleware that pushes exceptions out into a logger
 *
 * @author Nik Barham <nik@brokencube.co.uk>
 */
class ErrorLogger implements Middleware
{
    /**
     * Constructor
     *
     * @param LoggerInterface $log Logger to log error to
     */
    public function __construct(LoggerInterface $log)
    {
        $this->log = $log;
    }

    /**
     * Run Middleware for a particular request
     *
     * @param Request  $request    HTTP Foundation Request object
     * @param Delegate $delegate   Either the Router or HandlerContainer, depending on whether this is run pre or post
     *                             routing
     * @return Response
     */
    public function process(Request $request, Delegate $delegate) : Response
    {
        try {
            return $delegate->process($request);
        } catch (\Throwable $e) {
            $this->log->error($e->getMessage(), ['trace' => $e->getTraceAsString(), 'line' => $e->getLine(), 'file' => $e->getFile(), 'code' => $e->getCode()]);
            throw $e;
        }
    }
}


<?php
/**
 * Exception.php
 * @author    Daniel Mason <daniel@ayeayeapi.com>
 * @copyright (c) 2015 - 2016 Daniel Mason <daniel@ayeayeapi.com>
 * @license   MIT
 * @see       https://github.com/AyeAyeApi/Api
 */

namespace AyeAye\Api;

/**
 * Class Exception
 *
 * An exception specifically designed to be thrown back to the API end user. It
 * provides a public message and HTTP status code.
 *
 * @package AyeAye/Api
 * @see     https://github.com/AyeAyeApi/Api
 */
class Exception extends \Exception implements \JsonSerializable
{
    const DEFAULT_ERROR_CODE = 500;
    const DEFAULT_MESSAGE = 'Internal Server Error';

    /**
     * A message to show the client if available
     * @var string
     */
    public $publicMessage;

    /**
     * Exception constructor.
     *
     * Include information to pass to the client.
     *
     * @param string $publicMessage Message to show the user if not caught. Optional
     * @param int $code HTTP Status code to send to the user
     * @param string $systemMessage Message to show the enter into the log if different from the public message
     * @param \Exception $previous Any previous Exception
     * @SuppressWarnings(PHPMD.StaticAccess)
     */
    public function __construct($publicMessage = '', $code = 500, $systemMessage = '', \Exception $previous = null)
    {
        // Shift all parameters along if the first parameter is a string
        if (is_int($publicMessage)) {
            if (is_string($code)) {
                if ($systemMessage instanceof \Exception) {
                    $previous = $systemMessage;
                }
                $systemMessage = $code;
            }
            $code = $publicMessage;
            $publicMessage = null;
        }

        // If a public message wasn't specified, get it from the code
        if (!$publicMessage) {
            $publicMessage = Status::getMessageForCode($code);
            if (!$publicMessage) {
                $publicMessage = static::DEFAULT_MESSAGE;
            }
        }

        // If the system message wasn't specified, use the public message
        if (!$systemMessage) {
            $systemMessage = $publicMessage;
        }

        $this->publicMessage = $publicMessage;

        parent::__construct($systemMessage, $code, $previous);
    }

    /**
     * Get the message to tell the client.
     *
     * This message should only ever contain information that is useful to the
     * client and will not compromise the condition of the server.
     *
     * @return string
     */
    public function getPublicMessage()
    {
        return $this->publicMessage;
    }

    /**
     * Return data to be serialised into Json.
     *
     * The returned data contains the public message and exception code (which
     * is likely to be the HTTP status code). It will also include any previous
     * Aye Aye Exceptions.
     *
     * @return array
     */
    public function jsonSerialize()
    {
        $serialized = [
            'message' => $this->getPublicMessage(),
            'code' => $this->getCode(),
        ];
        if ($this->getPrevious() instanceof $this) {
            /** @var static $previous */
            $previous = $this->getPrevious();
            $serialized['previous'] = $previous->jsonSerialize();
        }
        return $serialized;
    }
}


<?php
/**
 * ControllerDocumentation.php
 * @author    Daniel Mason <daniel@ayeayeapi.com>
 * @copyright (c) 2015 - 2016 Daniel Mason <daniel@ayeayeapi.com>
 * @license   MIT
 * @see       https://github.com/AyeAyeApi/Api
 */

namespace AyeAye\Api;

use AyeAye\Formatter\Serializable;

/**
 * Class ControllerDocumentation
 *
 * Parses the relevant child controller and endpoint methods of a Controller
 * object through a Documentation object and returns the result as an array.
 * This is used to provide API documentation to end users.
 *
 * @package AyeAye/Api
 * @see     https://github.com/AyeAyeApi/Api
 */
class ControllerDocumentation implements Serializable
{
    /**
     * @var Controller
     */
    protected $controller;

    /**
     * @var \ReflectionObject
     */
    protected $reflectedController;

    /**
     * @var Documentation
     */
    protected $documentation;

    /**
     * Multi dimensional array of endpoint information
     * @var array[]
     */
    protected $endpointsCache;

    /**
     * A list of child controllers
     * @var string[]
     */
    protected $controllersCache;

    /**
     * ControllerDocumentation constructor.
     *
     * The reflection object must contain a valid controller class.
     *
     * @param Controller $controller
     * @param \ReflectionObject $reflectionController
     * @throws \InvalidArgumentException
     */
    public function __construct(Controller $controller, \ReflectionObject $reflectionController = null)
    {
        $this->controller = $controller;
        $this->reflectedController = $reflectionController;
        if(!$this->reflectedController) {
            $this->reflectedController = new \ReflectionObject($this->controller);
        }
        if(!$this->reflectedController->isInstance($controller)) {
            throw new \InvalidArgumentException(
                'Controller did not match ReflectionObject'
            );
        }
        $this->documentation = new Documentation();
    }

    /**
     * List the endpoints the controller provides.
     *
     * It is the endpoint name, not the method name that is given. Endpoints
     * are grouped by http verb and will have their documentation listed. If
     * the endpoint has been "hidden" by the controller, it will not be listed.
     *
     * @return array
     */
    protected function getEndpoints()
    {
        if (!$this->endpointsCache) {
            $isHidden = $this->getControllerMethod('isMethodHidden');
            $endpoints = [];
            $parts = [];
            $methods = $this->reflectedController->getMethods(\ReflectionMethod::IS_PUBLIC);
            foreach ($methods as $method) {
                if (preg_match('/([a-z]+)([A-Z]\w+)Endpoint$/', $method->getName(), $parts)) {
                    if (!$isHidden($method->getName())) {
                        $httpVerb = strtolower($parts[1]);
                        $endpoint = $this->camelcaseToHyphenated($parts[2]);
                        if (!array_key_exists($httpVerb, $endpoints)) {
                            $endpoints[$httpVerb] = array();
                        }
                        $endpoints[$httpVerb][$endpoint] = $this->documentation->getMethodDocumentation($method);
                    }
                }
            }
            $this->endpointsCache = $endpoints;
        }
        return $this->endpointsCache;
    }

    /**
     * Lists child controllers the controller provides.
     *
     * It is the controller name, not the method name that is given. If the
     * controller has been "hidden" by the controller, it will not be listed.
     *
     * @return array
     */
    protected function getControllers()
    {
        if (!$this->controllersCache) {
            $isHidden = $this->getControllerMethod('isMethodHidden');
            $methods = $this->reflectedController->getMethods(\ReflectionMethod::IS_PUBLIC);
            $controllers = [];
            foreach ($methods as $method) {
                if (preg_match('/(\w+)Controller$/', $method->getName(), $parts)) {
                    if (!$isHidden($method->getName())) {
                        $controllers[] = $this->camelcaseToHyphenated($parts[1]);
                    }
                }
            }
            $this->controllersCache = $controllers;
        }
        return $this->controllersCache;
    }

    /**
     * Turns camel case strings into lowercase hyphenated strings.
     *
     * Hyphenated strings are more useful for breaking up words in urls.
     *
     * @param string $camelcaseString
     * @return string Hyphenated string for urls
     */
    protected function camelcaseToHyphenated($camelcaseString)
    {
        return strtolower(preg_replace('/([a-z])([A-Z])/s', '$1-$2', $camelcaseString));
    }

    /**
     * Gets a callable method from the original controller.
     *
     * Given a method name in the controller, this method will return a
     * callable function that will invoke the method with any arguments you
     * provide.
     *
     * @param string $methodName
     * @return \Closure
     */
    protected function getControllerMethod($methodName)
    {
        $reflectionMethod = $this->reflectedController->getMethod($methodName);
        $reflectionMethod->setAccessible(true);
        return function () use ($reflectionMethod) {
            return $reflectionMethod->invokeArgs($this->controller, func_get_args());
        };
    }

    /**
     * Returns the documentation of the controller.
     *
     * Returns an array containing bother child controllers and endpoints with
     * their respective documentation. This can be given to an end user so that
     * they can understand how this controller deals with requests.
     *
     * @return array
     */
    public function getDocumentation()
    {
        return [
            'controllers' => $this->getControllers(),
            'endpoints' => $this->getEndpoints(),
        ];
    }

    /**
     * Returns the documentation of the controller.
     *
     * @see ::getDocumentation
     * @return array
     */
    public function ayeAyeSerialize()
    {
        return $this->getDocumentation();
    }
}


<?php
/**
 * @author Adegoke Obasa <goke@cottacush.com>
 */

namespace CottaCush\Yii2\HttpClient;

use CottaCush\Yii2\HttpClient\Exceptions\HttpClientException;
use CottaCush\Yii2\HttpClient\Messages\HttpClientErrorMessages;
use linslin\yii2\curl\Curl;

abstract class BaseHttpClient implements HttpClientInterface
{
    protected $baseUrl;
    protected $rawResponse = false;
    protected $lastRequestUrl;
    protected $lastRequestParams;
    /** @var $curlAgent Curl */
    protected $curlAgent;

    public function __construct($baseUrl)
    {
        $this->init($baseUrl);
    }

    abstract protected function init($baseUrl);

    abstract protected function buildUrl($url, $params = []);

    abstract protected function filterParams($params);

    /**
     * @author Adegoke Obasa <goke@cottacush.com>
     */
    public function useRawResponse()
    {
        $this->rawResponse = true;
        return $this;
    }

    /**
     * @author Adegoke Obasa <goke@cottacush.com>
     */
    public function useJsonResponse()
    {
        $this->rawResponse = false;
        return $this;
    }

    /**
     * @author Adegoke Obasa <goke@cottacush.com>
     * @return boolean
     */
    public function isRawResponse()
    {
        return $this->rawResponse;
    }

    /**
     * @author Adegoke Obasa <goke@cottacush.com>
     * @return mixed
     */
    public function getBaseUrl()
    {
        return $this->baseUrl;
    }

    /**
     * @author Adegoke Obasa <goke@cottacush.com>
     * @return Curl
     */
    public function getCurlAgent()
    {
        return $this->curlAgent;
    }

    /**
     * @author Adegoke Obasa <goke@cottacush.com>
     * @return mixed
     */
    public function getLastRequestUrl()
    {
        return $this->lastRequestUrl;
    }

    /**
     * @author Adegoke Obasa <goke@cottacush.com>
     * @return mixed
     */
    public function getLastRequestParams()
    {
        return $this->lastRequestParams;
    }

    /**
     * Performs GET HTTP request
     * @author Adegoke Obasa <goke@cottacush.com>
     * @param $url
     * @param array $params
     * @return mixed
     * @throws HttpClientException
     */
    public function get($url, $params = [])
    {
        if (!is_array($params)) {
            throw new HttpClientException(HttpClientErrorMessages::INVALID_QUERY_PARAMS);
        }
        $params = $this->filterParams($params);
        $this->lastRequestParams = $params;
        $this->lastRequestUrl = $this->buildUrl($url, $params);
        return $this->curlAgent->get($this->lastRequestUrl, $this->rawResponse);
    }

    /**
     * Performs POST HTTP request
     * @author Adegoke Obasa <goke@cottacush.com>
     * @param $url
     * @param $params
     * @return mixed
     */
    public function post($url, $params)
    {
        if (is_array($params)) {
            $params = $this->filterParams($params);
        }
        $this->lastRequestParams = $params;
        $this->lastRequestUrl = $this->buildUrl($url);
        return $this->curlAgent->setOption(CURLOPT_POSTFIELDS, $params)
            ->post($this->lastRequestUrl, $this->rawResponse);
    }

    /**
     * Performs PUT HTTP request
     * @author Adegoke Obasa <goke@cottacush.com>
     * @param $url
     * @param $params
     * @return mixed
     */
    public function put($url, $params)
    {
        if (is_array($params)) {
            $params = $this->filterParams($params);
        }
        $this->lastRequestParams = $params;
        $this->lastRequestUrl = $this->buildUrl($url);
        return $this->curlAgent->setOption(CURLOPT_POSTFIELDS, $params)
            ->put($this->lastRequestUrl, $this->rawResponse);
    }

    /**
     * Performs DELETE HTTP request
     * @author Adegoke Obasa <goke@cottacush.com>
     * @param $url
     * @param $params
     * @return mixed
     */
    public function delete($url, $params)
    {
        if (is_array($params)) {
            $params = $this->filterParams($params);
        }
        $this->lastRequestParams = $params;
        $this->lastRequestUrl = $this->buildUrl($url);
        return $this->curlAgent->setOption(CURLOPT_POSTFIELDS, $params)
            ->delete($this->lastRequestUrl, $this->rawResponse);
    }
}


<?php

namespace Vinelab\Auth\Social;

/*
 * @author  Abed Halawi <abed.halawi@vinelab.com>
 */

use Vinelab\Auth\Contracts\ProfileInterface;

class Profile implements ProfileInterface
{
    /**
     * The profile info;.
     *
     * @var array
     */
    protected $info;

    /**
     * The social network service.
     *
     * @var string
     */
    protected $provider;

    /**
     * Instantiates a profile by parsing
     * it and mapping it to commonly used
     * values across the different providers.
     *
     * @param object $profile
     * @param string $provider
     *
     * @return Vinelab\Auth\Social\Profile
     */
    public function instantiate($profile, $provider)
    {
        $this->provider = $provider;

        switch ($provider) {
            case 'facebook':
                $this->info = $this->parseFb($profile);
            break;

            case 'twitter':
                $this->info = $this->parseTwt($profile);
            break;
        }

        return $this;
    }

    /**
     * Returns the profile.
     *
     * @return array
     */
    public function info()
    {
        return $this->info;
    }

    /**
     * Returns the provider.
     *
     * @return string
     */
    public function provider()
    {
        return $this->provider;
    }

    /**
     * Parses a Twitter profile.
     *
     * @param object $profile
     *
     * @return array
     */
    public function parseTwt($profile)
    {
        // remove unecessary fields
        unset($profile->status);
        // stick avatar
        $profile->avatar = $profile->profile_image_url;

        return (array) $profile;
    }

    /**
     * Parse a Facebook profile.
     *
     * @param object $raw_profile
     *
     * @return array
     */
    public function parseFb($raw_profile)
    {
        $profile = $raw_profile;
        $profile->avatar = sprintf('http://graph.facebook.com/%s/picture', $profile->id);

        return (array) $profile;
    }

    /**
     * Implement the __get Magic method
     * to return profile attributes directly.
     *
     * @param string $attr
     *
     * @return mixed
     */
    public function __get($attr)
    {
        return isset($this->info[$attr]) ? $this->info[$attr] : null;
    }

    /**
     * Implement the __set Magic method
     * to open the ability to assign
     * values to the profile.
     *
     * @param string $attr
     * @param mixed  $val
     */
    public function __set($attr, $val)
    {
        $this->info[$attr] = $val;
    }

    /**
     * Implement the __isset Magic method
     * to bypass issues when checking for
     * empty attributes of this class.
     *
     * @param string $attr
     *
     * @return bool
     */
    public function __isset($attr)
    {
        return isset($this->info[$attr]);
    }
}


<?php
/**
 * Response.php
 * @author    Daniel Mason <daniel@ayeayeapi.com>
 * @copyright (c) 2015 - 2016 Daniel Mason <daniel@ayeayeapi.com>
 * @license   MIT
 * @see       https://github.com/AyeAyeApi/Api
 */

namespace AyeAye\Api;

use AyeAye\Api\Injector\RequestInjector;
use AyeAye\Api\Injector\StatusInjector;
use AyeAye\Formatter\WriterFactory;
use AyeAye\Formatter\Writer;

/**
 * Class Response.
 *
 * Contains a payload of information to return to the client.
 *
 * @package AyeAye/Api
 * @see     https://github.com/AyeAyeApi/Api
 */
class Response
{
    use StatusInjector;
    use RequestInjector;

    const DEFAULT_DATA_NAME = 'data';

    /**
     * The name of the object that is returned to the user where appropriate.
     *
     * @var string
     */
    protected $responseName = 'response';

    /**
     * The writer factory to use when the response is to be formatted
     * @var WriterFactory
     */
    protected $writerFactory;

    /**
     * The specific writer that will be used to format this response
     * @var Writer
     */
    protected $writer;

    /**
     * The data you wish to return in the response.
     * @var mixed
     */
    protected $body = [];

    /**
     * The formatted response.
     * We can prepare a response earlier to take advantage of the main API
     * class' error handling.
     * @var string
     */
    protected $preparedResponse;

    /**
     * Get all data that is being returned.
     *
     * This will return an array. Unless otherwise stated, data will usually be
     * attached to the 'data' key of this array.
     *
     * @return array
     */
    public function getBody()
    {
        return $this->body;
    }

    /**
     * Set the data that is to be returned.
     *
     * If data is directly returned from an endpoint, it will be attached to
     * the default data name (usually "data").
     *
     * @example
     *   return 'hello world'; becomes { "data" => "hello world" }
     *
     * However, if a Generator is returned, the keys returned will be used
     * instead.
     *
     * @example
     *   yield 'hello' => 'world'; becomes { "hello" => "world" }
     *
     * If no key is given, the default will still be used. This is useful to
     * provide uniformity in response while adding additional data such as
     * HATEOAS.
     *
     * @example
     *   yield 'hello';
     *   yield 'links' => $this->generateLinks();
     *
     * @param \Generator|mixed $data
     * @return $this
     */
    public function setBodyData($data)
    {
        if (!$data instanceof \Generator) {
            $this->body[static::DEFAULT_DATA_NAME] = $data;
            return $this;
        }
        foreach ($data as $key => $value) {
            $actualKey = $key ?: static::DEFAULT_DATA_NAME;
            $this->body[$actualKey] = $value;
        }
        return $this;
    }

    /**
     * Set the writer factory.
     *
     * This will be choose a writer to format the data based on the request.
     *
     * @param WriterFactory $writerFactory
     * @return $this
     */
    public function setWriterFactory(WriterFactory $writerFactory)
    {
        $this->writerFactory = $writerFactory;
        return $this;
    }

    /**
     * Set the writer.
     *
     * This overrides any choice that might otherwise be made by the writer
     * factory and should therefore be avoided.
     *
     * @param Writer $writer
     * @return $this
     */
    public function setWriter(Writer $writer)
    {
        $this->writer = $writer;
        return $this;
    }

    /**
     * Prepare the response.
     *
     * This selects a writer from the writer factory and prepares serialises
     * the data into a string. This is done early to allow exceptions and
     * errors to be caught and handled earlier.
     *
     * @return $this
     */
    public function prepareResponse()
    {
        if (!$this->writer) {
            $this->writer = $this->writerFactory->getWriterFor(
                $this->request->getFormats()
            );
        }
        $this->preparedResponse = $this->writer->format($this->getBody(), $this->responseName);
        return $this;
    }

    /**
     * Send the response.
     *
     * This method sends headers and writes the data to the output stream.
     *
     * If the response has not yet been prepared, this method will prepare it
     * first. This method should be the last thing that happens before the
     * script ends.
     *
     * @return $this
     */
    public function respond()
    {
        if (is_null($this->preparedResponse)) {
            $this->prepareResponse();
        }

        if ($this->status instanceof Status) {
            header($this->status->getHttpHeader());
        }

        header("Content-Type: {$this->writer->getContentType()}");
        echo $this->preparedResponse;

        return $this;
    }
}


<?php
/**
 * Custom Rating Grifus · Extensions For Grifus
 *
 * @author    Josantonius <hello@josantonius.com>
 * @package   Josantonius/Custom-Rating-Grifus
 * @copyright 2017 - 2018 (c) Josantonius - Custom Rating Grifus
 * @license   GPL-2.0+
 * @link      https://github.com/eliasis-framework/custom-rating-grifus.git
 * @since     1.0.0
 */

namespace EFG\Modules\CustomRatingGrifus\Controller\Admin;

use Eliasis\Framework\App;
use Eliasis\Complement\Type\Module;
use Eliasis\Framework\Controller;
use Josantonius\WP_Register\WP_Register;

/**
 * Rating controller
 */
class Rating extends Controller {

	/**
	 * Set movie params to use on Ajax.
	 *
	 * @return array
	 */
	public function set_movie_params() {

		$post_id   = get_the_ID();
		$is_active = $this->get_rating_state( $post_id );
		$options   = $this->model->get_theme_options();

		$params = [
			'postID'       => $post_id,
			'dark'         => $options['enable-dark'],
			'imdb_button'  => __( 'TOTAL', 'extensions-for-grifus-rating' ),
			'is_active'    => $is_active,
		];

		return $params;
	}

	/**
	 * Get rating state.
	 *
	 * @since 1.0.1
	 *
	 * @param string $post_id → post id.
	 *
	 * @return boolean → movie rating state
	 */
	public function get_rating_state( $post_id ) {

		return ( ! $this->model->get_movie_votes( $post_id ) ) ? false : true;
	}

	/**
	 * Add movie rating.
	 *
	 * @since 1.0.1
	 */
	public function add_movie_rating() {

		$nonce = isset( $_POST['nonce'] ) ? $_POST['nonce'] : '';

		if ( ! wp_verify_nonce( $nonce, 'eliasis' ) && ! wp_verify_nonce( $nonce, 'customRatingGrifus' ) ) {
			die( 'Busted!' );
		}

		$ip      = $this->get_ip();
		$vote    = $_POST['vote'];
		$post_id = $_POST['postID'];

		$this->clear_cache( $post_id );

		$votes = $this->model->get_movie_votes( $post_id );
		$votes = $this->model->set_user_vote( $post_id, $votes, $vote, $ip );

		$response = $this->set_rating_and_votes( $post_id, $votes );

		echo json_encode( $response, true );

		die();
	}

	/**
	 * Get Ip.
	 *
	 * @since 1.0.1
	 *
	 * @return string → ip
	 */
	public function get_ip() {

		return getenv( 'HTTP_CLIENT_IP' ) ?:
		getenv( 'HTTP_X_FORWARDED_FOR' ) ?:
		getenv( 'HTTP_X_FORWARDED' ) ?:
		getenv( 'HTTP_FORWARDED_FOR' ) ?:
		getenv( 'HTTP_FORWARDED' ) ?:
		getenv( 'REMOTE_ADDR' );
	}

	/**
	 * Clear cache (WP Super Cache) when updating rating.
	 *
	 * @since 1.0.1
	 *
	 * @param string $post_id → post id.
	 */
	public function clear_cache( $post_id ) {

		if ( function_exists( 'wp_cache_post_change' ) ) {
			wp_cache_post_change( $post_id );
		}
	}

	/**
	 * Calculate rating.
	 *
	 * @since 1.0.1
	 *
	 * @param array $votes → votes number.
	 *
	 * @return int|float|string → rating
	 */
	public function get_movie_rating( $votes ) {

		$votations = [];

		foreach ( $votes as $key => $value ) {
			for ( $i = 0; $i < $value; $i++ ) {
				$votations[] = $key;
			}
		}

		if ( count( $votations ) ) {
			$rating = array_sum( $votations ) / count( $votations );
			return round( $rating, 1 );
		}

		return 'N/A';
	}

	/**
	 * Get total votes.
	 *
	 * @since 1.0.1
	 *
	 * @param array $votes → votes.
	 *
	 * @return int|string → total votes
	 */
	public function get_total_votes( $votes = null ) {

		return ( array_sum( array_values( $votes ) ) );
	}

	/**
	 * Restart rating when added or edited post if not done previously.
	 *
	 * @param int     $post_id → post ID.
	 * @param object  $post    → (WP_Post) post object.
	 * @param boolean $update  → true if update post.
	 */
	public function restart_rating( $post_id, $post, $update ) {

		App::setCurrentID( 'EFG' );

		if ( Module::CustomRatingGrifus()->getOption( 'restart-when-add' ) ) {
			unset( $_POST['imdbRating'], $_POST['imdbVotes'] );
			if ( App::main()->is_after_insert_post( $post, $update ) ) {
				if ( ! $this->model->get_movie_votes( $post_id ) ) {
					$votes = $this->get_default_votes( $post_id );
					$this->set_rating_and_votes( $post_id, $votes );
					return true;
				}
			}
		}

		return false;
	}

	/**
	 * Restart all ratings.
	 */
	public function restart_all_ratings() {

		$nonce = isset( $_POST['nonce'] ) ? $_POST['nonce'] : '';

		if ( ! wp_verify_nonce( $nonce, 'eliasis' ) && ! wp_verify_nonce( $nonce, 'customRatingGrifusAdmin' ) ) {
			die( 'Busted!' );
		}

		$response['ratings_restarted'] = 0;

		$posts = $this->model->get_posts();

		foreach ( $posts as $post ) {
			if ( isset( $post->ID ) && ! $this->model->get_movie_votes( $post->ID ) ) {
				$this->set_rating_and_votes(
					$post->ID,
					$this->get_default_votes( $post->ID )
				);
				$response['ratings_restarted']++;
			}
		}

		echo json_encode( $response );

		die();
	}

	/**
	 * Update rating if the movie editing page is updated.
	 *
	 * @since 1.0.1
	 *
	 * @param int     $post_id → post ID.
	 * @param object  $post    → (WP_Post) post object.
	 * @param boolean $update  → true if update post.
	 *
	 * @return boolean
	 */
	public function update_rating( $post_id, $post, $update ) {

		App::setCurrentID( 'EFG' );

		if ( App::main()->is_after_update_post( $post, $update ) ) {
			if ( isset( $_POST['efg-update-rating'] ) ) {
				for ( $i = 1; $i <= 10; $i++ ) {
					if ( ! isset( $_POST[ "efg-rating-$i" ] ) ) {
						return false;
					}
					$votes[ "$i" ] = (int) $_POST[ "efg-rating-$i" ];
				}
				$this->set_rating_and_votes( $post_id, $votes );
			}
		}

		return true;
	}

	/**
	 * Restart when added a movie.
	 *
	 * @since 1.0.1
	 */
	public function restart_when_add() {

		$state = isset( $_POST['state'] ) ? $_POST['state'] : null;
		$nonce = isset( $_POST['nonce'] ) ? $_POST['nonce'] : '';

		if ( ! wp_verify_nonce( $nonce, 'eliasis' ) && ! wp_verify_nonce( $nonce, 'customRatingGrifusAdmin' ) ) {
			die( 'Busted!' );
		}

		App::setCurrentID( 'EFG' );
		$slug = Module::CustomRatingGrifus()->getOption( 'slug' );
		$this->model->set_restart_when_add( $slug, $state );
		$response = [ 'restart-when-add' => $state ];

		echo json_encode( $response );

		die();
	}

	/**
	 * Get default votes.
	 *
	 * @since 1.0.1
	 *
	 * @param int $post_id → post ID
	 *
	 * @return array → default votes
	 */
	public function get_default_votes( $post_id ) {

		return [
			'1'  => 0,
			'2'  => 0,
			'3'  => 0,
			'4'  => 0,
			'5'  => 0,
			'6'  => 0,
			'7'  => 0,
			'8'  => 0,
			'9'  => 0,
			'10' => 0,
		];
	}

	/**
	 * Add movie rating.
	 *
	 * @since 1.0.1
	 *
	 * @param string $post_id → post id.
	 * @param array  $votes  → votes.
	 *
	 * @return array → rating and total votes
	 */
	public function set_rating_and_votes( $post_id, $votes ) {

		$total_votes = $this->get_total_votes( $votes );

		$this->model->set_movie_votes( $post_id, $total_votes );
		$this->model->set_total_votes( $post_id, $votes );

		$rating = $this->get_movie_rating( $votes );

		$this->model->set_movie_rating( $post_id, $rating );

		return [
			'rating' => $rating,
			'total'  => $total_votes,
		];
	}

	/**
	 * Add meta boxes.
	 *
	 * @since 1.0.1
	 *
	 * @param string $post_type → post type.
	 * @param object $post     → (WP_Post) post object.
	 */
	public function add_meta_boxes( $post_type, $post ) {

		App::setCurrentID( 'EFG' );

		$is_active = $this->get_rating_state( $post->ID );

		if ( App::main()->is_publish_post( $post ) && $is_active ) {

			$this->add_styles();
			$this->add_scripts();

			add_meta_box(
				'info_movie-rating-movie',
				__(
					'Extensions For Grifus - Custom rating',
					'extensions-for-grifus-rating'
				),
				[ $this, 'render_meta_boxes' ],
				$post_type,
				'normal',
				'high'
			);
		}
	}

	/**
	 * Renderizate post meta boxes.
	 *
	 * @since 1.0.1
	 *
	 * @param object $post → (WP_Post) post object.
	 */
	public function render_meta_boxes( $post ) {

		App::setCurrentID( 'EFG' );

		wp_nonce_field( '_rating_movie_nonce', 'rating_movie_nonce' );

		$meta_boxes = Module::CustomRatingGrifus()->getOption( 'path', 'meta-boxes' );

		$data = [ 'votes' => $this->model->get_movie_votes( $post->ID ) ];

		$this->view->renderizate( $meta_boxes, 'wp-insert-post', $data );
	}

	/**
	 * Add scripts.
	 *
	 * @since 1.0.2
	 */
	protected function add_scripts() {

		$script = 'customRatingGrifusEditPost';

		$params = [

			'votes'  => __( 'votes', 'extensions-for-grifus-rating' ),
			'rating' => __( 'Rating', 'extensions-for-grifus-rating' ),
		];

		$settings = Module::CustomRatingGrifus()->getOption( 'assets', 'js', $script );

		$settings['params'] = array_merge( $settings['params'], $params );

		WP_Register::add( 'script', $settings );
	}

	/**
	 * Add styles.
	 *
	 * @since 1.0.2
	 */
	protected function add_styles() {

		$css = 'customRatingGrifusEditPost';

		WP_Register::add(
			'style',
			Module::CustomRatingGrifus()->getOption( 'assets', 'css', $css )
		);
	}
}


<?php

namespace CottaCush\Yii2\Date;

use DateTime;

/**
 * Class DateUtils
 * @author Adeyemi Olaoye <yemi@cottacush.com>
 * @package CottaCush\Yii2
 */
class DateUtils
{
    const INTERVAL_LAST_WEEK = "-1 week";

    /**
     * Gets the difference between two date periods
     * @author Olawale Lawal <wale@cottacush.com>
     * @param $fromTime
     * @param string $toTime
     * @param string $format
     * @return string
     */
    public static function toRelativeTime($fromTime, $toTime = 'now', $format = 'days')
    {
        $startTime = new DateTime($fromTime);
        $endTime = new DateTime($toTime);

        return $startTime->diff($endTime)->$format;
    }

    /**
     * Returns date range text
     * @author Adeyemi Olaoye <yemi@cottacush.com>
     * @author Olawale Lawal <wale@cottacush.com>
     * @param $startDate
     * @param $endDate
     * @param string $toSeparator
     * @return string
     */
    public static function getDateRangeText($startDate, $endDate, $toSeparator = 'to')
    {
        if ($startDate == $endDate) {
            return self::format($startDate, DateFormat::FORMAT_SHORT);
        } elseif (self::format($startDate, DateFormat::FORMAT_YEAR)
            == self::format($endDate, DateFormat::FORMAT_YEAR)
        ) {
            $start_date = (
                self::format($startDate, DateFormat::FORMAT_MONTH)
                == self::format($endDate, DateFormat::FORMAT_MONTH))
                ? self::format($startDate, DateFormat::FORMAT_DAY) :
                self::format($startDate, DateFormat::FORMAT_SHORT_NO_YEAR);
        } else {
            $start_date = self::format($startDate, DateFormat::FORMAT_SHORT);
        }
        return $start_date . ' ' . $toSeparator . ' ' . self::format($endDate, DateFormat::FORMAT_SHORT);
    }

    /**
     * Format date
     * @author Olawale Lawal <wale@cottacush.com>
     * @param $format
     * @param $datetime
     * @return bool|string
     */
    public static function format($datetime, $format = DateFormat::FORMAT_SHORT)
    {
        $datetime = strtotime($datetime);
        if (!$datetime) {
            return '';
        }
        return date($format, $datetime);
    }

    /**
     * Get's the current datetime in the mysql datetime format
     * @author Adegoke Obasa <goke@cottacush.com>
     * @return bool|string
     */
    public static function getMysqlNow()
    {
        return self::getCurrentDateTime(DateFormat::FORMAT_MYSQL_STYLE);
    }

    /**
     * Get's the current datetime in the specified format
     * @author Adegoke Obasa <goke@cottacush.com>
     * @param $format
     * @return bool|string
     */
    public static function getCurrentDateTime($format)
    {
        return date($format);
    }

    /**
     * Get's the current datetime in the oracle datetime format
     * @author Adegoke Obasa <goke@cottacush.com>
     * @return bool|string
     */
    public static function getOracleNow()
    {
        return self::getCurrentDateTime(DateFormat::FORMAT_ORACLE);
    }

    /**
     * Converts a datetime string from one format to another format
     * @author Adegoke Obasa <goke@cottacush.com>
     * @param $dateString
     * @param $fromFormat
     * @param $toFormat
     * @return string
     */
    public static function convertDate($dateString, $fromFormat, $toFormat)
    {
        $date = DateTime::createFromFormat($fromFormat, $dateString);
        if (!$date && $fromFormat == DateFormat::FORMAT_ORACLE_WITH_MICROSECONDS) {
            $date = DateTime::createFromFormat(DateFormat::FORMAT_ORACLE_DATE_ONLY, $dateString);
        }

        if ($date) {
            return $date->format($toFormat);
        }
        return $dateString;
    }

    /**
     * Get's the datetime in the specified format
     * @author Adegoke Obasa <goke@cottacush.com>
     * @param $format
     * @param null|string $timestamp
     * @return bool|string
     */
    public static function getDateTime($format, $timestamp = 'now')
    {
        $date = strtotime($timestamp);
        if (!$date) {
            return $timestamp;
        }
        return date($format, $date);
    }
}