<?php

namespace Dothiv\Bundle\ContentfulBundle\Service\ImageScaler;

use Imagine\Image\AbstractImagine;
use Imagine\Image\Box;
use Imagine\Image\ImageInterface;
use Imagine\Image\Palette\RGB;
use Imagine\Image\Point;

class ImagineImageScaler implements ImageScalerInterface
{
    /**
     * @var AbstractImagine
     */
    private $imagine;

    public function __construct(AbstractImagine $imagine)
    {
        $this->imagine = $imagine;
    }

    /**
     * {@inheritdoc}
     */
    public function scale(\SplFileInfo $source, ThumbnailConfiguration $size, \SplFileInfo $target)
    {
        $img = $this->imagine->open($source->getPathname());

        if ($size->getThumbnail()) {
            $thumb = $this->makeThumbnail($img, $size->getSize());
            $thumb->save($target->getPathname());
        } else {
            $newSize  = $size->getSize();
            $origSize = $img->getSize();
            $factor   = min(
                $newSize->getWidth() / $origSize->getWidth(),
                $newSize->getHeight() / $origSize->getHeight()
            );
            if (!$size->getExact()) {
                // Do not upscale.
                $factor = min(1, $factor);
            }
            $scaledSize = $origSize->scale($factor);
            $img->resize($scaledSize);
            if ($size->getExact()) {
                // Force image size
                if ($img->palette()->supportsAlpha()) {
                    $palette = new RGB();
                    $color = $palette->color('#000', 0);
                    $bg = $this->imagine->create($newSize, $color);
                } else {
                    $bg = $this->imagine->create($newSize);
                }

                if ($size->getFillbg()) {
                    $this->fillWithBlurredImage($bg, $img);
                }

                $bg->paste(
                    $img,
                    new Point(
                        ($newSize->getWidth() - $scaledSize->getWidth()) / 2,
                        ($newSize->getHeight() - $scaledSize->getHeight()) / 2
                    )
                );
                $bg->save($target->getPathname());
            } else {
                $img->save($target->getPathname());
            }
        }
    }

    /**
     * {@inheritdoc}
     */
    public function makeThumbnail(ImageInterface $img, Box $size)
    {
        if ($img->getSize()->getWidth() < $size->getWidth()) {
            $origSize = $img->getSize();
            $img->resize($origSize->scale($size->getWidth() / $origSize->getWidth()));
        }
        if ($img->getSize()->getHeight() < $size->getHeight()) {
            $origSize = $img->getSize();
            $img->resize($origSize->scale($size->getHeight() / $origSize->getHeight()));
        }
        return $img->thumbnail($size, ImageInterface::THUMBNAIL_OUTBOUND);
    }

    /**
     * {@inheritdoc}
     */
    public function fillWithBlurredImage($imageToFill, $fillImage)
    {
        $thumb = $this->makeThumbnail($fillImage->copy(), $imageToFill->getSize());
        $thumb->effects()->blur(15);
        $imageToFill->paste($thumb, new Point(0, 0));
    }
}


<?php
namespace CampaignChain\Activity\SocialMediaBundle\Controller;

use CampaignChain\CoreBundle\Controller\Module\AbstractActivityHandler;
use CampaignChain\Operation\SocialMediaBundle\Job\SocialMediaSchedule;
use CampaignChain\Operation\SocialMediaBundle\EntityService\SocialMediaSchedule as SocialMediaScheduleService;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Form\Form;
use CampaignChain\CoreBundle\Entity\Location;
use CampaignChain\CoreBundle\Entity\Campaign;
use CampaignChain\CoreBundle\Entity\Activity;
use CampaignChain\CoreBundle\Entity\Operation;
use Doctrine\Common\Persistence\ManagerRegistry;
use Symfony\Bundle\TwigBundle\TwigEngine;
use Symfony\Component\HttpFoundation\Session\Session;
use CampaignChain\CoreBundle\Util\SchedulerUtil;

/**
 * Class SocialMediaScheduleHandler
 * @package CampaignChain\Activity\SocialMediaBundle\Controller\Module
 */
class SocialMediaScheduleHandler extends AbstractActivityHandler
{
    protected $em;
    protected $session;
    protected $templating;
    protected $contentService;
    protected $job;

    /** @var SchedulerUtil */
    protected $schedulerUtil;

    public function __construct(
        ManagerRegistry $managerRegistry,
        Session $session,
        TwigEngine $templating,
        SocialMediaScheduleService $contentService,
        SocialMediaSchedule $job,
        SchedulerUtil $schedulerUtil
    )
    {
        $this->em = $managerRegistry->getManager();
        $this->session = $session;
        $this->templating = $templating;
        $this->contentService = $contentService;
        $this->job = $job;
        $this->schedulerUtil = $schedulerUtil;
    }

    /**
     * When a new Activity is being created, this handler method will be called
     * to retrieve a new Content object for the Activity.
     *
     * Called in these views:
     * - new
     *
     * @param Location $location
     * @param Campaign $campaign
     * @return null
     */
    public function createContent(Location $location = null, Campaign $campaign = null)
    {
        return null;
    }

    /**
     * Overwrite this method to return an existing Activity Content object which
     * would be displayed in a view.
     *
     * Called in these views:
     * - edit
     * - editModal
     * - read
     *
     * @param Location $location
     * @param Operation $operation
     * @return null
     */
    public function getContent(Location $location = null, Operation $operation)
    {
        if($operation) {
            $status = $this->contentService->getSocialMediaScheduleByOperation($operation);

            return $status;
        }

        return null;
    }

    /**
     * Implement this method to change the data of an Activity as per the form
     * data that has been posted in a view.
     *
     * Called in these views:
     * - new
     *
     * @param Activity $activity
     * @param $data Form submit data of the Activity.
     * @return Activity
     */
    public function processActivity(Activity $activity, $data)
    {
        return $activity;
    }

    /**
     * Modifies the Location of the Activity.
     *
     * Called in these views:
     * - new
     *
     * @param Location $location The Activity's Location.
     * @return Location
     */
    public function processActivityLocation(Location $location = null)
    {
        return $location;
    }

    /**
     * After a new Activity was created, this method makes it possible to alter
     * the data of the Content's Location (not the Activity's Location!) as per
     * the data provided for the Content.
     *
     * Called in these views:
     * - new
     *
     * @param Location $location Location of the Content.
     * @param $data Form submit data of the Content.
     * @return Location
     */
    public function processContentLocation(Location $location, $data)
    {
        return $location;
    }

    /**
     * Create or modify the Content object from the form data.
     *
     * Called in these views:
     * - new
     * - editApi
     *
     * @param Operation $operation
     * @param $data Form submit data of the Content.
     * @return mixed
     */
    public function processContent(Operation $operation, $data)
    {
            if(is_array($data)) {
                // If the status has already been created, we modify its data.
                $status = $this->contentService->getSocialMediaScheduleByOperation($operation);
                // If data comes from API call, then Locations will not be
                // entities, but their IDs in an array.
                if(!$data['locations'] instanceof ArrayCollection){
                    $locations = $this->em
                        ->getRepository('CampaignChainCoreBundle:Location')
                        ->findById(array_values($data['locations']));
                    $locations = new ArrayCollection($locations);
                } else {
                    $locations = $data['locations'];
                }
                $status->setLocations($locations);
                $status->setMessage($data['message']);
            } else {
                $status = $data;
            }

        return $status;
    }

    public function processSingleContentMultiOperation(Activity $activity, Form $form)
    {
    }

    /**
    * Define custom template rendering options for the new view in this method
    * as an array. Here's a sample of such an array:
    *
    * array(
    *     'template' => 'foo_template::edit.html.twig',
    *     'vars' => array(
    *         'foo1' => $bar1,
    *         'foo2' => $bar2
    *         )
    *     );
    *
    * Called in these views:
    * - new
    *
    * @param Operation $operation
    * @return null
    */
    public function getNewRenderOptions(Operation $operation = null)
    {
        return null;
    }

    /**
     * @param Operation $operation
     * @param bool $isModal Modal view yes or no?
     * @return \Symfony\Component\HttpFoundation\Response
     * @throws \Exception
     */
    public function readAction(Operation $operation, $isModal = false)
    {
    }

    /**
     * The Activity controller calls this method after the form was submitted
     * and the new activity was persisted.
     *
     * @param Activity $activity
     * @param $data
     */
    public function postFormSubmitNewEvent(Activity $activity, $data)
    {
    }

    /**
     * This event is being called after the new Activity and its related
     * content was persisted.
     *
     * Called in these views:
     * - new
     *
     * @param Operation $operation
     * @param Form $form
     * @param $content The Activity's content object.
     * @return null
     */
    public function postPersistNewEvent(Operation $operation, $content = null)
    {
        // Content to be published immediately?
        $this->publishNow($operation);
    }

    /**
     * This event is being called before the edit form data has been submitted.
     *
     * Called in these views:
     * - edit
     *
     * @param Operation $operation
     * @return null
     */
    public function preFormSubmitEditEvent(Operation $operation)
    {
        return null;
    }

    /**
     * This event is being called after the edited Activity and its related
     * content was persisted.
     *
     * Called in these views:
     * - edit
     *
     * @param Operation $operation
     * @param Form $form
     * @param $content The Activity's content object.
     * @return null
     */
    public function postPersistEditEvent(Operation $operation, $content = null)
    {
        // Content to be published immediately?
        $this->publishNow($operation);
    }

    /**
     * Define custom template rendering options for the edit view in this method
     * as an array. Here's a sample of such an array:
     *
     * array(
     *     'template' => 'foo_template::edit.html.twig',
     *     'vars' => array(
     *         'foo1' => $bar1,
     *         'foo2' => $bar2
     *         )
     *     );
     *
     * Called in these views:
     * - edit
     *
     * @param Operation $operation
     * @return null
     */
    public function getEditRenderOptions(Operation $operation)
    {
        return null;
    }

    /**
     * This event is being called before the editModal form data has been
     * submitted.
     *
     * Called in these views:
     * - editModal
     *
     * @param Operation $operation
     * @return null
     */
    public function preFormSubmitEditModalEvent(Operation $operation)
    {
        return null;
    }

    /**
     * Define custom template rendering options for editModal view as array.
     *
     * Called in these views:
     * - editModal
     *
     * @see AbstractActivityHandler::getEditRenderOptions()
     * @param Operation $operation
     * @return null
     */
    public function getEditModalRenderOptions(Operation $operation)
    {
        return null;
    }

    /**
     * Let's a handler implementation define whether the Content should be
     * displayed or processed in a specific view or not.
     *
     * Called in these views:
     * - new
     * - edit
     * - editModal
     * - editApi
     *
     * @param $view
     * @return bool
     */
    public function hasContent($view)
    {
        return true;
    }

    private function publishNow(Operation $operation)
    {
        if ($this->schedulerUtil->isDueNow($operation->getStartDate())) {
            $this->job->execute($operation->getId());
            $content = $this->contentService->getSocialMediaScheduleByOperation($operation);
            foreach($content->getLocations() as $location){
                $flashMsgPart =
                    '
getUrl().'">View it on '
                    .$location->getName()
                    .' ('
                    .$location->getLocationModule()->getDisplayName()
                    .')
';
            }
            $this->session->getFlashBag()->add(
                'success',
                'The message was published on these Locations:'
                .'
'
                .$flashMsgPart
                .'
'
            );

            return true;
        }

        return false;
    }
}


<?php

/*
 * This file is part of the overtrue/wechat.
 *
 * (c) overtrue <i@overtrue.me>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

/**
 * OAuthServiceProvider.php.
 *
 * This file is part of the wechat.
 *
 * (c) overtrue <i@overtrue.me>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace EasyWeChat\Foundation\ServiceProviders;

use Overtrue\Socialite\SocialiteManager as Socialite;
use Pimple\Container;
use Pimple\ServiceProviderInterface;

/**
 * Class OAuthServiceProvider.
 */
class OAuthServiceProvider implements ServiceProviderInterface
{
    /**
     * Registers services on the given container.
     *
     * This method should only be used to configure services and parameters.
     * It should not get services.
     *
     * @param Container $pimple A container instance
     */
    public function register(Container $pimple)
    {
        $pimple['oauth'] = function ($pimple) {
            $callback = $this->prepareCallbackUrl($pimple);
            $scopes = $pimple['config']->get('oauth.scopes', []);
            $socialite = (new Socialite(
                [
                    'wechat' => [
                        'client_id' => $pimple['config']['app_id'],
                        'client_secret' => $pimple['config']['secret'],
                        'redirect' => $callback,
                    ],
                ]
            ))->driver('wechat');

            if (!empty($scopes)) {
                $socialite->scopes($scopes);
            }

            return $socialite;
        };
    }

    /**
     * Prepare the OAuth callback url for wechat.
     *
     * @param Container $pimple
     *
     * @return string
     */
    private function prepareCallbackUrl($pimple)
    {
        $callback = $pimple['config']->get('oauth.callback');
        if (0 === stripos($callback, 'http')) {
            return $callback;
        }
        $baseUrl = $pimple['request']->getSchemeAndHttpHost();

        return $baseUrl.'/'.ltrim($callback, '/');
    }
}


<?php

namespace OpenOrchestra\ModelBundle\Repository;

use OpenOrchestra\ModelInterface\Model\KeywordInterface;
use OpenOrchestra\ModelInterface\Repository\KeywordRepositoryInterface;
use OpenOrchestra\Pagination\Configuration\PaginateFinderConfiguration;
use OpenOrchestra\Repository\AbstractAggregateRepository;
use OpenOrchestra\ModelBundle\Repository\RepositoryTrait\UseTrackableTrait;
use Solution\MongoAggregation\Pipeline\Stage;

/**
 * Class KeywordRepository
 */
class KeywordRepository extends AbstractAggregateRepository implements KeywordRepositoryInterface
{
    use UseTrackableTrait;

    /**
     * @param string $label
     *
     * @return KeywordInterface|null
     */
    public function findOneByLabel($label)
    {
        return $this->findOneBy(array('label' => $label));
    }

    /**
     * @return mixed
     */
    public function getManager()
    {
        return $this->getDocumentManager();
    }

    /**
     * @param PaginateFinderConfiguration $configuration
     *
     * @return array
     */
    public function findForPaginate(PaginateFinderConfiguration $configuration)
    {
        $qa = $this->createAggregationQuery();

        $this->filterSearch($configuration, $qa);

        $order = $configuration->getOrder();
        if (!empty($order)) {
            $qa->sort($order);
        }

        $qa->skip($configuration->getSkip());
        $qa->limit($configuration->getLimit());

        return $this->hydrateAggregateQuery($qa);
    }

    /**
     * @param PaginateFinderConfiguration $configuration
     *
     * @return int
     */
    public function countWithFilter(PaginateFinderConfiguration $configuration)
    {
        $qa = $this->createAggregationQuery();
        $this->filterSearch($configuration, $qa);

        return $this->countDocumentAggregateQuery($qa);
    }

    /**
     * @return int
     */
    public function count()
    {
        $qa = $this->createAggregationQuery();

        return $this->countDocumentAggregateQuery($qa);
    }

    /**
     * @param array $keywordIds
     *
     * @throws \Doctrine\ODM\MongoDB\MongoDBException
     */
    public function removeKeywords(array $keywordIds)
    {
        array_walk($keywordIds, function(&$keywordId) {$keywordId = new \MongoId($keywordId);});

        $qb = $this->createQueryBuilder();
        $qb->remove()
            ->field('id')->in($keywordIds)
            ->getQuery()
            ->execute();
    }

    /**
     * @param PaginateFinderConfiguration $configuration
     * @param Stage                       $qa
     *
     * @return array
     */
    protected function filterSearch(PaginateFinderConfiguration $configuration, Stage $qa)
    {
        $label = $configuration->getSearchIndex('label');

        if (null !== $label && '' !== $label) {
            $qa->match(array('label' => new \MongoRegex('/.*'.$label.'.*/i')));
        }

        return $qa;
    }
}


<?php

/*
 * Copyright (c) 2013, Flaming Code
 *
 */

namespace FlamingBase\Controller;

use Zend\Mvc\Controller\AbstractActionController;

/**
 * AbstractCliController
 *
 * @author Flemming Andersen <flemming@flamingcode.com>
 * @copyright (c) 2013, Flaming Code
 * @link https://github.com/FlamingCode/FlamingBase for the canonical source repository
 * @license http://opensource.org/licenses/MIT MIT
 */
abstract class AbstractCliController extends AbstractActionController
{
	const FILE_SUFFIX = '.lock';

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

	/**
	 *
	 * @var string
	 */
	protected $lockdir = 'data/tmp';

	/**
	 * Check to see if a cronjob is already running
	 *
	 * @return bool
	 */
	private function isrunning()
	{
		$pids = explode(PHP_EOL, `ps -e | awk '{print $1}'`);
		if (in_array($this->pid, $pids))
			return true;

		return false;
	}

	/**
	 * Create a lock for this process
	 *
	 * @return int
	 */
	public function lock()
	{
		$lock_file = $this->getLockFile();

		if (file_exists($lock_file)) {
			// Is running?
			$this->pid = file_get_contents($lock_file);
			if ($this->isrunning()) {
				error_log("==".$this->pid."== Already in progress...");
				return false;
			} else
				error_log("==".$this->pid."== Previous job died abruptly...");
		}

		$this->pid = getmypid();
		$s = file_put_contents($lock_file, $this->pid);
		error_log("==".$this->pid."== Lock acquired, processing the job...");
		return $this->pid;
	}

	/**
	 *
	 * @return bool
	 */
	public function unlock()
	{
		$lock_file = $this->getLockFile();

		if(file_exists($lock_file))
			unlink($lock_file);

		error_log("==".$this->pid."== Releasing lock...");
		return true;
	}

	/**
	 * Gets the Path to the lock file
	 *
	 * @return string
	 */
	protected function getLockFile()
	{
		$request = $this->getRequest();
		$params = $request->getParams();
		$controller = $params->controller;
		$action = $params->action;

		$normalizedController = strtolower(stripslashes(str_replace(__NAMESPACE__, '', $controller)));

		$fileBaseName = implode('_', array(
			basename($request->getScriptName()),
			$normalizedController,
			$action
		));

		return $this->lockdir . DIRECTORY_SEPARATOR . $fileBaseName . self::FILE_SUFFIX;
	}
}


<?php
/**
 * User: Alex Gusev <alex@flancer64.com>
 */

namespace Praxigento\BonusHybrid\Service\Calc;

use Praxigento\BonusBase\Api\Service\Period\Calc\Get\Dependent\Request as AGetPeriodRequest;
use Praxigento\BonusBase\Api\Service\Period\Calc\Get\Dependent\Response as AGetPeriodResponse;
use Praxigento\BonusBase\Repo\Data\Log\Opers as ELogOper;
use Praxigento\BonusHybrid\Config as Cfg;
use Praxigento\BonusHybrid\Service\Calc\PvWriteOff\A\Data\Trans as DTrans;

class PvWriteOff
    implements \Praxigento\Core\Api\App\Service\Process
{
    /** @var \Praxigento\BonusHybrid\Service\Calc\PvWriteOff\A\PrepareTrans */
    private $aPrepareTrans;
    /** @var \Praxigento\BonusHybrid\Service\Calc\PvWriteOff\A\Query\GetData\Builder */
    private $aQGetData;
    /** @var \Praxigento\BonusHybrid\Service\Calc\PvWriteOff\A\SaveDownline */
    private $aSaveDownline;
    /** @var \Praxigento\BonusHybrid\Service\Calc\PvWriteOff\A\Validate */
    private $aValidate;
    /** @var \Praxigento\BonusBase\Repo\Dao\Calculation */
    private $daoCalc;
    /** @var \Praxigento\BonusBase\Repo\Dao\Log\Opers */
    private $daoLogOper;
    /** @var  \Praxigento\Accounting\Repo\Dao\Type\Asset */
    private $daoTypeAsset;
    /** @var \Praxigento\Core\Api\Helper\Date */
    private $hlpDate;
    /** @var  \Praxigento\Core\Api\Helper\Period */
    private $hlpPeriod;
    /** @var \Praxigento\Core\Api\App\Logger\Main */
    private $logger;
    /** @var \Praxigento\Accounting\Service\Operation\Create */
    private $servOperation;
    /** @var \Praxigento\BonusBase\Api\Service\Period\Calc\Get\Dependent */
    private $servPeriodGet;

    public function __construct(
        \Praxigento\Core\Api\App\Logger\Main $logger,
        \Praxigento\Core\Api\Helper\Date $hlpDate,
        \Praxigento\Core\Api\Helper\Period $hlpPeriod,
        \Praxigento\Accounting\Repo\Dao\Type\Asset $daoTypeAsset,
        \Praxigento\BonusBase\Repo\Dao\Calculation $daoCalc,
        \Praxigento\BonusBase\Repo\Dao\Log\Opers $daoLogOper,
        \Praxigento\Accounting\Service\Operation\Create $servOperation,
        \Praxigento\BonusBase\Api\Service\Period\Calc\Get\Dependent $servPeriodGet,
        \Praxigento\BonusHybrid\Service\Calc\PvWriteOff\A\Query\GetData\Builder $aQGetData,
        \Praxigento\BonusHybrid\Service\Calc\PvWriteOff\A\PrepareTrans $aPrepareTrans,
        \Praxigento\BonusHybrid\Service\Calc\PvWriteOff\A\SaveDownline $aSaveDownline,
        \Praxigento\BonusHybrid\Service\Calc\PvWriteOff\A\Validate $aValidate
    ) {
        $this->logger = $logger;
        $this->hlpDate = $hlpDate;
        $this->hlpPeriod = $hlpPeriod;
        $this->daoTypeAsset = $daoTypeAsset;
        $this->daoCalc = $daoCalc;
        $this->daoLogOper = $daoLogOper;
        $this->servOperation = $servOperation;
        $this->servPeriodGet = $servPeriodGet;
        $this->aQGetData = $aQGetData;
        $this->aPrepareTrans = $aPrepareTrans;
        $this->aSaveDownline = $aSaveDownline;
        $this->aValidate = $aValidate;
    }

    /**
     * Register new operation.
     *
     * @param \Praxigento\Accounting\Repo\Data\Transaction[] $trans
     * @param string $dsBegin
     * @return int operation ID
     * @throws \Exception
     */
    private function createOperation($trans, $dsBegin)
    {
        $datePerformed = $this->hlpDate->getUtcNowForDb();
        $req = new \Praxigento\Accounting\Api\Service\Operation\Create\Request();
        $req->setOperationTypeCode(Cfg::CODE_TYPE_OPER_PV_WRITE_OFF);
        $req->setDatePerformed($datePerformed);
        $req->setTransactions($trans);
        $period = substr($dsBegin, 0, 6);
        $note = "PV Write Off ($period)";
        $req->setOperationNote($note);
        $resp = $this->servOperation->exec($req);
        $result = $resp->getOperationId();
        return $result;
    }

    public function exec(\Praxigento\Core\Data $ctx)
    {
        $this->logger->info("PV Write Off calculation is started.");
        /**
         * perform processing
         */
        $ctx->set(self::CTX_OUT_SUCCESS, false);
        /* get dependent calculation data */
        list($periodData, $calcData) = $this->getCalcData();
        $dsBegin = $periodData->getDstampBegin();
        $dsEnd = $periodData->getDstampEnd();
        $calcId = $calcData->getId();
        /* get accounting data for calculation (PV transitions) */
        $transitions = $this->getTransitions($dsBegin, $dsEnd);
        /* group PV transitions by account */
        $balances = $this->groupPvTrans($transitions);
        /* look up fo accounts with negative balance, compose list & throw exception */
        $this->aValidate->exec($balances);
        /* compose transactions for the operation */
        $trans = $this->getTransactions($balances, $dsEnd);
        /* create 'PV Write Off' operation */
        $operId = $this->createOperation($trans, $dsBegin, $dsEnd);
        /* calculate PV/TV/OV and save plain downline */
        $this->aSaveDownline->exec($calcId, $dsEnd, $balances);
        /* register operation in log */
        $this->saveLog($operId, $calcId);
        /* mark this calculation complete */
        $this->daoCalc->markComplete($calcId);
        /* mark process as successful */
        $ctx->set(self::CTX_OUT_SUCCESS, true);
        $this->logger->info("PV Write Off calculation is completed.");
    }

    /**
     * Get data for dependent calculation.
     *
     * @return array [$periodData, $calcData]
     */
    private function getCalcData()
    {
        /**
         * Get period & calc data.
         */
        $req = new AGetPeriodRequest();
        $req->setBaseCalcTypeCode(Cfg::CODE_TYPE_CALC_BONUS_SIGN_UP_DEBIT);
        $req->setDepCalcTypeCode(Cfg::CODE_TYPE_CALC_PV_WRITE_OFF);
        /** @var AGetPeriodResponse $resp */
        $resp = $this->servPeriodGet->exec($req);
        /** @var \Praxigento\BonusBase\Repo\Data\Period $periodData */
        $periodData = $resp->getDepPeriodData();
        /** @var \Praxigento\BonusBase\Repo\Data\Calculation $calcData */
        $calcData = $resp->getDepCalcData();
        /**
         * Compose result.
         */
        $result = [$periodData, $calcData];
        return $result;
    }

    /**
     * Convert turnover data into transactions data to create operation.
     *
     * @param array $turnover [accId => pvTurnover]
     * @param string $dsEnd (YYYYMMDD)
     * @return \Praxigento\Accounting\Repo\Data\Transaction[]
     */
    private function getTransactions($turnover, $dsEnd)
    {
        $dateApplied = $this->hlpPeriod->getTimestampUpTo($dsEnd);
        $result = $this->aPrepareTrans->exec($turnover, $dateApplied);
        return $result;
    }

    /**
     * Get PV transitions data for period.
     *
     * @param string $dsBegin
     * @param string $dsEnd
     * @return  DTrans[]
     * @throws \Exception
     */
    private function getTransitions($dsBegin, $dsEnd)
    {
        $assetTypeId = $this->daoTypeAsset->getIdByCode(Cfg::CODE_TYPE_ASSET_PV);
        $dateFrom = $this->hlpPeriod->getTimestampFrom($dsBegin);
        $dateTo = $this->hlpPeriod->getTimestampNextFrom($dsEnd);

        $query = $this->aQGetData->build();
        $bind = [
            $this->aQGetData::BND_ASSET_TYPE_ID => $assetTypeId,
            $this->aQGetData::BND_DATE_FROM => $dateFrom,
            $this->aQGetData::BND_DATE_TO => $dateTo
        ];

        $conn = $query->getConnection();
        $rs = $conn->fetchAll($query, $bind);
        $result = [];
        foreach ($rs as $one) {
            $item = new \Praxigento\BonusHybrid\Service\Calc\PvWriteOff\A\Data\Trans($one);
            $result[] = $item;
        }
        return $result;
    }

    /**
     * Collect PV transitions on accounts and get PV turnover for period.
     *
     * @param \Praxigento\BonusHybrid\Service\Calc\PvWriteOff\A\Data\Trans[] $transData
     * @return array [accId => pvTurnover]
     */
    private function groupPvTrans($transData)
    {
        $result = [];
        foreach ($transData as $one) {
            $debitAccId = $one->get(DTrans::A_ACC_ID_DEBIT);
            $creditAccId = $one->get(DTrans::A_ACC_ID_CREDIT);
            $value = $one->get(DTrans::A_AMOUNT);
            if (isset($result[$debitAccId])) {
                $result[$debitAccId] -= $value;
            } else {
                $result[$debitAccId] = -$value;
            }
            if (isset($result[$creditAccId])) {
                $result[$creditAccId] += $value;
            } else {
                $result[$creditAccId] = $value;
            }
        }
        return $result;
    }

    /**
     * Bind operations with calculation.
     *
     * @param int $operIdWriteOff
     * @param int $calcId
     * @throws \Exception
     */
    private function saveLog($operIdWriteOff, $calcId)
    {
        /* log PvWriteOff operation itself */
        $log = new ELogOper();
        $log->setCalcId($calcId);
        $log->setOperId($operIdWriteOff);
        $this->daoLogOper->create($log);
    }
}


<?php

/*
 * This file is part of the Сáша framework.
 *
 * (c) tchiotludo <http://github.com/tchiotludo>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

declare(strict_types = 1);

namespace Cawa\Session\SessionStorage;

class FileStorage extends AbstractStorage
{
    /**
     * @var string
     */
    private $path;

    /**
     * @param string $path
     */
    public function __construct(string $path = null)
    {
        $this->path = $path ?? ini_get('session.save_path');
    }

    /**
     * {@inheritdoc}
     */
    public function open() : bool
    {
        if (!is_dir($this->path)) {
            mkdir($this->path, 0777);
        }

        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function close() : bool
    {
        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function read(string $id)
    {
        if (!($content = @file_get_contents($this->path . '/sess_' . $id))) {
            return false;
        }

        $length = strlen($content);
        $saveData = self::unserialize($content);

        return [$saveData['data'], $saveData['startTime'], $saveData['accessTime'], $length];
    }

    /**
     * {@inheritdoc}
     */
    public function write(string $id, array $data, int $startTime, int $accessTime)
    {
        $saveData = [
            'startTime' => $startTime,
            'accessTime' => $accessTime,
            'data' => $data,
        ];

        $stringData = self::serialize($saveData);
        if (file_put_contents($this->path . '/sess_' . $id, $stringData, LOCK_EX) === false) {
            return false;
        } else {
            return strlen($stringData);
        }
    }

    /**
     * {@inheritdoc}
     */
    public function destroy(string $id) : bool
    {
        $file = $this->path . '/sess_' . $id;
        if (file_exists($file)) {
            unlink($file);

            return true;
        }

        return false;
    }

    /**
     * {@inheritdoc}
     */
    public function touch(string $id, array $data, int $startTime, int $accessTime)
    {
        return $this->write($id, $data, $startTime, $accessTime);
    }
}


<?php
namespace eMacros\Runtime\Builder;

use eMacros\Applicable;
use eMacros\Scope;
use eMacros\GenericList;

class InstanceBuilder implements Applicable {
	/**
	 * Creates a new instance from a string
	 * Usage: (instance _class (array 1 2 3))
	 * Returns: object
	 * (non-PHPdoc)
	 * @see \eMacros\Applicable::apply()
	 */
	public function apply(Scope $scope, GenericList $arguments) {
		if (count($arguments) == 0) throw new \BadFunctionCallException("InstanceBuilder: No arguments found.");
		$class = $arguments[0]->evaluate($scope);
		if (!is_string($class))
			throw new \InvalidArgumentException(sprintf("InstanceBuilder: Expected string as first argument but %s was found instead.", gettype($class)));
		//get additional arguments
		$list = array_slice($arguments->getArrayCopy(), 1);
		$args = [];
		//build constructor parameters
		foreach ($list as $el)
			$args[] = $el->evaluate($scope);
		$rc = new \ReflectionClass($class);
		return empty($args) ? $rc->newInstance() : $rc->newInstanceArgs($args);
	}
}
?>


<?php

/*
 * This file is part of the overtrue/wechat.
 *
 * (c) overtrue <i@overtrue.me>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

/**
 * Relation.php.
 *
 * @author    allen05ren <allen05ren@outlook.com>
 * @copyright 2016 overtrue <i@overtrue.me>
 *
 * @see       https://github.com/overtrue
 * @see       http://overtrue.me
 */

namespace EasyWeChat\ShakeAround;

use EasyWeChat\Core\AbstractAPI;

/**
 * Class Relation.
 */
class Relation extends AbstractAPI
{
    const API_DEVICE_BINDPAGE = 'https://api.weixin.qq.com/shakearound/device/bindpage';
    const API_RELATION_SEARCH = 'https://api.weixin.qq.com/shakearound/relation/search';

    /**
     * Bind pages for device.
     *
     * @param array $deviceIdentifier
     * @param array $pageIds
     *
     * @return \EasyWeChat\Support\Collection
     */
    public function bindPage(array $deviceIdentifier, array $pageIds)
    {
        $params = [
            'device_identifier' => $deviceIdentifier,
            'page_ids' => $pageIds,
        ];

        return $this->parseJSON('json', [self::API_DEVICE_BINDPAGE, $params]);
    }

    /**
     * Get pageIds by deviceId.
     *
     * @param array $deviceIdentifier
     * @param bool  $raw
     *
     * @return array|\EasyWeChat\Support\Collection
     */
    public function getPageByDeviceId(array $deviceIdentifier, $raw = false)
    {
        $params = [
            'type' => 1,
            'device_identifier' => $deviceIdentifier,
        ];

        $result = $this->parseJSON('json', [self::API_RELATION_SEARCH, $params]);

        if ($raw === true) {
            return $result;
        }
        $page_ids = [];
        if (!empty($result->data['relations'])) {
            foreach ($result->data['relations'] as $item) {
                $page_ids[] = $item['page_id'];
            }
        }

        return $page_ids;
    }

    /**
     * Get devices by pageId.
     *
     * @param int $pageId
     * @param int $begin
     * @param int $count
     *
     * @return \EasyWeChat\Support\Collection
     */
    public function getDeviceByPageId($pageId, $begin, $count)
    {
        $params = [
            'type' => 2,
            'page_id' => intval($pageId),
            'begin' => intval($begin),
            'count' => intval($count),
        ];

        return $this->parseJSON('json', [self::API_RELATION_SEARCH, $params]);
    }
}


<?php
/**
 * @link http://psesd.org/
 *
 * @copyright Copyright (c) 2015 Puget Sound ESD
 * @license http://psesd.org/license/
 */

namespace cascade\components\types;

use canis\base\exceptions\Exception;
use canis\helpers\ArrayHelper;
use Yii;

/**
 * Collector [[@doctodo class_description:cascade\components\types\Collector]].
 *
 * @author Jacob Morrison <email@ofjacob.com>
 */
class Collector extends \canis\base\collector\Module
{
    /**
     * @var [[@doctodo var_type:_tableRegistry]] [[@doctodo var_description:_tableRegistry]]
     */
    protected $_tableRegistry;

    /**
     * @inheritdoc
     */
    public function getCollectorItemClass()
    {
        return Item::className();
    }

    /**
     * @inheritdoc
     */
    public function getModulePrefix()
    {
        return 'Type';
    }

    /**
     * @inheritdoc
     */
    public function isReady()
    {
        $this->load();
        foreach ($this->bucket as $type) {
            if (!$type->object) {
                continue;
            }
            if (!isset($this->tableRegistry[$type->object->systemId])) {
                Yii::trace("Type {$type->object->systemId} is not registered in the object type registry.");

                return false;
            }
            if ($this->tableRegistry[$type->object->systemId]->system_version < $type->object->version) {
                Yii::trace("Type {$type->object->systemId} is out of date.");

                return false;
            }
            Yii::trace("Type {$type->object->systemId} ready to go!");
        }

        return true;
    }

    /**
     * @inheritdoc
     */
    public function initialize()
    {
        Yii::beginProfile('Component:::types::initialize');
        foreach ($this->bucket as $type) {
            if (is_null($type->object) || !$type->object) {
                // module isn't in our installation
                continue;
            }
            $module = $type->object;
            $systemId = $module->systemId;
            // Database module registry
            $this->registerObjectType($module);

            if (!isset($this->tableRegistry[$systemId])) {
                throw new Exception("Unable to initialize module $systemId");
            }

            if ($this->tableRegistry[$systemId]->system_version < $module->version) {
                $oldVersion = $this->_tableRegistry[$systemId]->system_version;
                $this->_tableRegistry[$systemId]->system_version = $module->version;
                if (!$module->upgrade($oldVersion) || !$this->_tableRegistry[$systemId]->save()) {
                    throw new Exception("Unable to upgrade module $systemId to {$module->version} from {$oldVersion}");
                }
            }
        }
        Yii::endProfile('Component:::types::initialize');

        return true;
    }

    /**
     * [[@doctodo method_description:registerObjectType]].
     *
     * @param [[@doctodo param_type:module]] $module [[@doctodo param_description:module]]
     *
     * @return [[@doctodo return_type:registerObjectType]] [[@doctodo return_description:registerObjectType]]
     */
    public function registerObjectType($module)
    {
        if (!Yii::$app->isDbAvailable) {
            return false;
        }
        $systemId = $module->systemId;

        if (!isset($this->tableRegistry[$systemId])) {
            $objectTypeClass = Yii::$app->classes['ObjectTypeRegistry'];
            $this->_tableRegistry[$systemId] = new $objectTypeClass();
            $this->_tableRegistry[$systemId]->name = $systemId;
            $this->_tableRegistry[$systemId]->system_version = $module->version;
            if (!$this->_tableRegistry[$systemId]->save()) {
                unset($this->_tableRegistry[$systemId]);

                return false;
            }
            $module->objectTypeModel = $this->_tableRegistry[$systemId];
            if (!$module->setup()) {
                $this->_tableRegistry[$systemId]->delete();
                unset($this->_tableRegistry[$systemId]);

                return false;
            }
        }

        if (isset($this->_tableRegistry[$systemId])) {
            $module->objectTypeModel = $this->_tableRegistry[$systemId];
        }

        return true;
    }

    /**
     * Get table registry.
     *
     * @return [[@doctodo return_type:getTableRegistry]] [[@doctodo return_description:getTableRegistry]]
     */
    public function getTableRegistry()
    {
        if (is_null($this->_tableRegistry)) {
            $objectTypeClass = Yii::$app->classes['ObjectTypeRegistry'];
            $this->_tableRegistry = [];
            if ($objectTypeClass::tableExists()) {
                $om = $objectTypeClass::find()->all();
                $this->_tableRegistry = ArrayHelper::index($om, 'name');
            }
        }

        return $this->_tableRegistry;
    }
    /**
     * [[@doctodo method_description:addRelationship]].
     *
     * @param unknown $parent
     * @param unknown $child
     * @param unknown $options (optional)
     *
     * @return unknown
     */
    public function addRelationship($parent, $child, $options = [])
    {
        $parentRef = $this->getOne($parent);
        $childRef = $this->getOne($child);
        $relationship = Relationship::getOne($parentRef, $childRef, $options);
        $parentRef->addChild($child, $relationship);
        $childRef->addParent($parent, $relationship);

        return true;
    }

    /**
     * Get authorities.
     *
     * @return [[@doctodo return_type:getAuthorities]] [[@doctodo return_description:getAuthorities]]
     */
    public function getAuthorities()
    {
        $authorities = [];
        foreach ($this->getAll() as $typeItem) {
            if (isset($typeItem->object) && $typeItem->object->getBehavior('Authority') !== null) {
                $authorities[$typeItem->object->systemId] = $typeItem->object;
            }
        }

        return $authorities;
    }

    /**
     * Get page meta.
     *
     * @return [[@doctodo return_type:getPageMeta]] [[@doctodo return_description:getPageMeta]]
     */
    public function getPageMeta()
    {
        $m = [];
        foreach ($this->getAll() as $typeItem) {
            if (empty($typeItem->object)) {
                continue;
            }
            $m[$typeItem->systemId] = $typeItem->object->pageMeta;
        }

        return $m;
    }
}


<?php
/**
 * @link http://psesd.org/
 *
 * @copyright Copyright (c) 2015 Puget Sound ESD
 * @license http://psesd.org/license/
 */

namespace cascade\components\web\widgets\grid;

use cascade\web\widgets\grid\columns\Data as DataColumn;
use canis\base\exceptions\Exception;
use Yii;

/**
 * View [[@doctodo class_description:cascade\components\web\widgets\grid\View]].
 *
 * @author Jacob Morrison <email@ofjacob.com>
 */
class View extends \yii\base\Widget
{
    /**
     * @var [[@doctodo var_type:widget]] [[@doctodo var_description:widget]]
     */
    public $widget;
    /**
     * @var [[@doctodo var_type:state]] [[@doctodo var_description:state]]
     */
    public $state;
    /**
     * @var [[@doctodo var_type:dataProvider]] [[@doctodo var_description:dataProvider]]
     */
    public $dataProvider;
    /**
     * @var [[@doctodo var_type:emptyText]] [[@doctodo var_description:emptyText]]
     */
    public $emptyText = 'No items found';
    /**
     * @var [[@doctodo var_type:htmlOptions]] [[@doctodo var_description:htmlOptions]]
     */
    public $htmlOptions = [];
    /**
     * @var [[@doctodo var_type:sortableAttributes]] [[@doctodo var_description:sortableAttributes]]
     */
    public $sortableAttributes;
    /**
     * @var [[@doctodo var_type:filters]] [[@doctodo var_description:filters]]
     */
    public $filters;
    /**
     * @var [[@doctodo var_type:views]] [[@doctodo var_description:views]]
     */
    public $views = ['list'];
    /**
     * @var [[@doctodo var_type:currentView]] [[@doctodo var_description:currentView]]
     */
    public $currentView = 'list';
    /**
     * @var [[@doctodo var_type:itemsPerRequest]] [[@doctodo var_description:itemsPerRequest]]
     */
    public $itemsPerRequest = 20;
    /**
     * @var [[@doctodo var_type:limit]] [[@doctodo var_description:limit]]
     */
    public $limit;
    /**
     * @var [[@doctodo var_type:rendererSettings]] [[@doctodo var_description:rendererSettings]]
     */
    public $rendererSettings = [];
    /**
     * @var [[@doctodo var_type:itemMenu]] [[@doctodo var_description:itemMenu]]
     */
    public $itemMenu = [];
    /**
     * @var [[@doctodo var_type:additionalClasses]] [[@doctodo var_description:additionalClasses]]
     */
    public $additionalClasses;
    /**
     * @var [[@doctodo var_type:specialItemClasses]] [[@doctodo var_description:specialItemClasses]]
     */
    public $specialItemClasses = [];
    /**
     * @var [[@doctodo var_type:nullDisplay]] [[@doctodo var_description:nullDisplay]]
     */
    public $nullDisplay = '';
    /**
     * @var [[@doctodo var_type:_totalItems]] [[@doctodo var_description:_totalItems]]
     */
    protected $_totalItems;
    /**
     * @var [[@doctodo var_type:_currentData]] [[@doctodo var_description:_currentData]]
     */
    protected $_currentData;
    /**
     * @var [[@doctodo var_type:_currentDataRaw]] [[@doctodo var_description:_currentDataRaw]]
     */
    protected $_currentDataRaw;
    /**
     * @var [[@doctodo var_type:_columns]] [[@doctodo var_description:_columns]]
     */
    protected $_columns;
    /**
     * @var [[@doctodo var_type:_columnSettings]] [[@doctodo var_description:_columnSettings]]
     */
    protected $_columnSettings;
    /**
     * @var [[@doctodo var_type:_formatter]] [[@doctodo var_description:_formatter]]
     */
    protected $_formatter;

    /**
     * @inheritdoc
     */
    public function init()
    {
        if ($this->dataProvider === null) {
            throw new Exception(Yii::t('zii', 'The "dataProvider" property cannot be empty.'));
        }

        $this->htmlOptions['id'] = $this->getId();
        $this->htmlOptions['class'] = 'grid-view';
        $this->_prepareDataProvider();
    }

    /**
     * @inheritdoc
     */
    public function run()
    {
        $this->_prepareDataProvider();
        $data = $this->getData();
        if (!empty($this->state['fetch'])) {
            ob_clean();
            // you need a subset of the data
            Yii::$app->controller->json($data);
            Yii::$app->end();
        } else {
            $columnSettings = $this->getColumnSettings();
            $options = [];
            $options['currentPage'] = $this->dataProvider->pagination->currentPage + 1;
            $options['widget'] = $this->widget;
            $options['state'] = $this->state;
            $options['columns'] = $columnSettings;
            $options['data'] = $data;
            $options['totalItems'] = $this->getTotalItems();
            $options['currentView'] = $this->currentView;
            $options['views'] = $this->views;
            $options['itemMenu'] = $this->itemMenu;
            $options['loadMore'] = is_null($this->limit);
            $options['emptyText'] = $this->emptyText;
            $options['specialItemClasses'] = $this->specialItemClasses;
            $options['rendererSettings'] = $this->rendererSettings;
            $options['rendererSettings']['grid']['sortableLabel'] = 'Sort by:';
            $options['rendererSettings']['grid']['sortable'] = $this->sortableAttributes;
            $options = CJSON::encode($options);
            if (!empty($this->additionalClasses)) {
                $this->htmlOptions['class'] .= ' ' . $this->additionalClasses;
            }
            $this->htmlOptions['data-grid-view-options'] = $options;
            echo Html::tag('div', '', $this->htmlOptions);
        }
    }

    /**
     * Get column settings.
     *
     * @return [[@doctodo return_type:getColumnSettings]] [[@doctodo return_description:getColumnSettings]]
     */
    public function getColumnSettings()
    {
        if (is_null($this->_columnSettings)) {
            $this->_columnSettings = [];
            foreach ($this->columns as $key => $c) {
                if (!$c->visible) {
                    continue;
                }
                $this->_columnSettings[$key] = ['label' => $c->getDataLabel()];

                if (!isset($c->htmlOptions)) {
                    $c->htmlOptions = [];
                }
                $this->_columnSettings[$key]['htmlOptions'] = $c->htmlOptions;
                $sortableResolve = $this->dataProvider->sort->resolveAttribute($c->name);
                $this->_columnSettings[$key]['sortable'] = !empty($sortableResolve);
            }
        }

        return $this->_columnSettings;
    }

    /**
     * Get data.
     *
     * @return [[@doctodo return_type:getData]] [[@doctodo return_description:getData]]
     */
    public function getData()
    {
        if (is_null($this->_currentData)) {
            $this->_currentDataRaw = $this->dataProvider->getData();
            $this->_currentData = [];
            $itemNumber = $this->dataProvider->pagination->offset;
            $row = 0;
            foreach ($this->_currentDataRaw as $r) {
                $p = ['itemNumber' => $itemNumber, 'id' => $r->primaryKey, 'values' => []];
                foreach ($this->columns as $key => $c) {
                    $p['values'][$key] = $c->getDataValue($row, $r, false);
                }
                $p['acl'] = [];
                if ($this->owner->instanceSettings['whoAmI'] === 'parent' and isset($r->childObject) and $r->childObject->hasBehavior('Access')) {
                    $p['acl'] = $r->childObject->aclSummary();
                } elseif ($this->owner->instanceSettings['whoAmI'] === 'child' and isset($r->parentObject) and $r->parentObject->hasBehavior('Access')) {
                    $p['acl'] = $r->parentObject->aclSummary();
                } elseif ($r->hasBehavior('Access')) {
                    $p['acl'] = $r->aclSummary();
                }
                $this->_currentData['item-' . $itemNumber] = $p;
                $row++;
                $itemNumber++;
            }
        }

        return $this->_currentData;
    }

    /**
     * Set columns.
     *
     * @param [[@doctodo param_type:columns]] $columns [[@doctodo param_description:columns]]
     *
     * @return [[@doctodo return_type:setColumns]] [[@doctodo return_description:setColumns]]
     */
    public function setColumns($columns)
    {
        $this->_columns = [];
        foreach ($columns as $key => $columnName) {
            if (is_array($columnName)) {
                $settings = $columnName;
                $settings['name'] = $key;
            } else {
                $settings = ['name' => $columnName];
            }
            if (!isset($settings['class'])) {
                $settings['class'] = '\cascade\web\widgets\grid\columns\Data';
            }
            if (!isset($settings['value'])) {
                $settings['type'] = 'raw';
                $settings['value'] = function ($data, $row) use ($settings) {
                    $key = explode('.', $settings['name']);
                    $object = $data;
                    while (count($key) > 1) {
                        $next = array_shift($key);
                        if (is_object($object)) {
                            $object = $object->{$next};
                        } else {
                            $object = $object[$next];
                        }
                    }
                    $key = $key[0];
                    if (is_object($object)) {
                        $model = get_class($object);
                        $fields = $model::getFields($object);
                        if (isset($fields[$key])) {
                            return $fields[$key]->getFormattedValue();
                        }
                    }

                    return $object->{$key};
                };
            }
            if (!isset($settings['type'])) {
                $settings['type'] = 'raw';
            }
            $column = Yii::createObject($settings, $this);
            $key = $column->name;

            if (!$column->visible) {
                //	continue;
            }
            $this->_columns[$key] = $column;
        }
    }

    /**
     * [[@doctodo method_description:createGridColumn]].
     *
     * @param [[@doctodo param_type:text]] $text [[@doctodo param_description:text]]
     *
     * @throws Exception [[@doctodo exception_description:Exception]]
     * @return [[@doctodo return_type:createGridColumn]] [[@doctodo return_description:createGridColumn]]
     *
     */
    protected function createGridColumn($text)
    {
        if (!preg_match('/^([\w\.]+)(:(\w*))?(:(.*))?$/', $text, $matches)) {
            throw new Exception(Yii::t('zii', 'The column must be specified in the format of "Name:Type:Label", where "Type" and "Label" are optional.'));
        }
        $column = new DataColumn($this);
        $column->name = $matches[1];
        if (isset($matches[3]) && $matches[3] !== '') {
            $column->type = $matches[3];
        }
        if (isset($matches[5])) {
            $column->header = $matches[5];
        }

        return $column;
    }

    /**
     * Get columns.
     *
     * @return [[@doctodo return_type:getColumns]] [[@doctodo return_description:getColumns]]
     */
    public function getColumns()
    {
        if (is_null($this->_columns)) {
            $this->columns = $this->dataProvider->model->attributeNames();
        }

        return $this->_columns;
    }

    /**
     * Get data key.
     *
     * @return [[@doctodo return_type:getDataKey]] [[@doctodo return_description:getDataKey]]
     */
    public function getDataKey()
    {
        return 'ajax-' . $this->id;
    }

    /**
     * Get total items.
     *
     * @return [[@doctodo return_type:getTotalItems]] [[@doctodo return_description:getTotalItems]]
     */
    public function getTotalItems()
    {
        if (is_null($this->_totalItems)) {
            $this->_totalItems = $this->dataProvider->totalItemCount;
        }

        return $this->_totalItems;
    }

    /**
     * [[@doctodo method_description:_prepareDataProvider]].
     */
    protected function _prepareDataProvider()
    {
        if (!is_null($this->limit)) {
            $this->dataProvider->pagination->pageSize = $this->limit;
        } else {
            $this->dataProvider->pagination->pageSize = $this->itemsPerRequest;
        }
    }

    /**
     * Get formatter.
     *
     * @return CFormatter the formatter instance. Defaults to the 'format' application component.
     */
    public function getFormatter()
    {
        if ($this->_formatter === null) {
            $this->_formatter = Yii::$app->format;
        }

        return $this->_formatter;
    }

    /**
     * Set formatter.
     *
     * @param CFormatter $value the formatter instance
     */
    public function setFormatter($value)
    {
        $this->_formatter = $value;
    }
}


<?php

/*
 * This file is part of the Predis package.
 *
 * (c) Daniele Alessandri <suppakilla@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Predis\Pipeline;

use Predis\ClientContextInterface;
use Predis\ClientException;
use Predis\ClientInterface;
use Predis\Command\CommandInterface;
use Predis\Connection\ConnectionInterface;
use Predis\Connection\Replication\ReplicationInterface;
use Predis\Response\ErrorInterface as ErrorResponseInterface;
use Predis\Response\ResponseInterface;
use Predis\Response\ServerException;

/**
 * Implementation of a command pipeline in which write and read operations of
 * Redis commands are pipelined to alleviate the effects of network round-trips.
 *
 * {@inheritdoc}
 *
 * @author Daniele Alessandri <suppakilla@gmail.com>
 */
class Pipeline implements ClientContextInterface
{
    private $client;
    private $pipeline;

    private $responses = array();
    private $running = false;

    /**
     * @param ClientInterface $client Client instance used by the context.
     */
    public function __construct(ClientInterface $client)
    {
        $this->client = $client;
        $this->pipeline = new \SplQueue();
    }

    /**
     * Queues a command into the pipeline buffer.
     *
     * @param string $method    Command ID.
     * @param array  $arguments Arguments for the command.
     *
     * @return $this
     */
    public function __call($method, $arguments)
    {
        $command = $this->client->createCommand($method, $arguments);
        $this->recordCommand($command);

        return $this;
    }

    /**
     * Queues a command instance into the pipeline buffer.
     *
     * @param CommandInterface $command Command to be queued in the buffer.
     */
    protected function recordCommand(CommandInterface $command)
    {
        $this->pipeline->enqueue($command);
    }

    /**
     * Queues a command instance into the pipeline buffer.
     *
     * @param CommandInterface $command Command instance to be queued in the buffer.
     *
     * @return $this
     */
    public function executeCommand(CommandInterface $command)
    {
        $this->recordCommand($command);

        return $this;
    }

    /**
     * Throws an exception on -ERR responses returned by Redis.
     *
     * @param ConnectionInterface    $connection Redis connection that returned the error.
     * @param ErrorResponseInterface $response   Instance of the error response.
     *
     * @throws ServerException
     */
    protected function exception(ConnectionInterface $connection, ErrorResponseInterface $response)
    {
        $connection->disconnect();
        $message = $response->getMessage();

        throw new ServerException($message);
    }

    /**
     * Returns the underlying connection to be used by the pipeline.
     *
     * @return ConnectionInterface
     */
    protected function getConnection()
    {
        $connection = $this->getClient()->getConnection();

        if ($connection instanceof ReplicationInterface) {
            $connection->switchToMaster();
        }

        return $connection;
    }

    /**
     * Implements the logic to flush the queued commands and read the responses
     * from the current connection.
     *
     * @param ConnectionInterface $connection Current connection instance.
     * @param \SplQueue           $commands   Queued commands.
     *
     * @return array
     */
    protected function executePipeline(ConnectionInterface $connection, \SplQueue $commands)
    {
        foreach ($commands as $command) {
            $connection->writeRequest($command);
        }

        $responses = array();
        $exceptions = $this->throwServerExceptions();

        while (!$commands->isEmpty()) {
            $command = $commands->dequeue();
            $response = $connection->readResponse($command);

            if (!$response instanceof ResponseInterface) {
                $responses[] = $command->parseResponse($response);
            } elseif ($response instanceof ErrorResponseInterface && $exceptions) {
                $this->exception($connection, $response);
            } else {
                $responses[] = $response;
            }
        }

        return $responses;
    }

    /**
     * Flushes the buffer holding all of the commands queued so far.
     *
     * @param bool $send Specifies if the commands in the buffer should be sent to Redis.
     *
     * @return $this
     */
    public function flushPipeline($send = true)
    {
        if ($send && !$this->pipeline->isEmpty()) {
            $responses = $this->executePipeline($this->getConnection(), $this->pipeline);
            $this->responses = array_merge($this->responses, $responses);
        } else {
            $this->pipeline = new \SplQueue();
        }

        return $this;
    }

    /**
     * Marks the running status of the pipeline.
     *
     * @param bool $bool Sets the running status of the pipeline.
     *
     * @throws ClientException
     */
    private function setRunning($bool)
    {
        if ($bool && $this->running) {
            throw new ClientException('The current pipeline context is already being executed.');
        }

        $this->running = $bool;
    }

    /**
     * Handles the actual execution of the whole pipeline.
     *
     * @param mixed $callable Optional callback for execution.
     *
     * @throws \Exception
     * @throws \InvalidArgumentException
     *
     * @return array
     */
    public function execute($callable = null)
    {
        if ($callable && !is_callable($callable)) {
            throw new \InvalidArgumentException('The argument must be a callable object.');
        }

        $exception = null;
        $this->setRunning(true);

        try {
            if ($callable) {
                call_user_func($callable, $this);
            }

            $this->flushPipeline();
        } catch (\Exception $exception) {
            // NOOP
        }

        $this->setRunning(false);

        if ($exception) {
            throw $exception;
        }

        return $this->responses;
    }

    /**
     * Returns if the pipeline should throw exceptions on server errors.
     *
     * @return bool
     */
    protected function throwServerExceptions()
    {
        return (bool) $this->client->getOptions()->exceptions;
    }

    /**
     * Returns the underlying client instance used by the pipeline object.
     *
     * @return ClientInterface
     */
    public function getClient()
    {
        return $this->client;
    }
}


<?php

namespace ArtaxServiceBuilder;

use Danack\Code\Generator\ClassGenerator;
use Danack\Code\Generator\GeneratorInterface;
use Danack\Code\Generator\DocBlockGenerator;
use Danack\Code\Generator\InterfaceGenerator;
use Danack\Code\Generator\MethodGenerator;
use Danack\Code\Generator\ParameterGenerator;
use Danack\Code\Generator\AbstractMemberGenerator;
use Danack\Code\Generator\DocBlock\Tag\GenericTag;
use Danack\Code\Generator\DocBlock\Tag\ParamTag;
use Danack\Code\Generator\DocBlock\Tag\ReturnTag;
use Danack\Code\Generator\DocBlock\Tag\ThrowsTag;

use Danack\Code\Generator\PropertyGenerator;
use GithubService\GithubArtaxService\GithubArtaxServiceException;

function getNamespace($namespaceClass) {

    if (is_object($namespaceClass)) {
        $namespaceClass = get_class($namespaceClass);
    }

    $lastSlashPosition = mb_strrpos($namespaceClass, '\\');

    if ($lastSlashPosition !== false) {
        return mb_substr($namespaceClass, 0, $lastSlashPosition);
    }

    return "";
}

function getClassName($namespaceClass) {
    $lastSlashPosition = mb_strrpos($namespaceClass, '\\');

    if ($lastSlashPosition !== false) {
        return mb_substr($namespaceClass, $lastSlashPosition + 1);
    }

    return $namespaceClass;
}

/**
 * @param $savePath
 * @throws \RuntimeException
 */
function saveFile($savePath, $fqcn, $text) {

    $filename = str_replace('\\', '/', $fqcn);

    $fileHeader = <<< END
<?php

//Auto-generated by ArtaxServiceBuilder - https://github.com/Danack/ArtaxServiceBuilder
//
//Do not be surprised when any changes to this file are over-written.
//

END;

    $outputFilename = $savePath.'/'.$filename.'.php';
    @mkdir(dirname($outputFilename), 0777, true);
    $written = @file_put_contents($outputFilename, $fileHeader.$text);

    if ($written == false) {
        throw new APIBuilderException("Failed to write file $filename.");
    }
}

class APIGenerator {

    /**
     * @var ClassGenerator
     */
    private $classGenerator;

    private $interfaceGenerator;
    private $outputPath;
    private $namespace;
    private $parameterTranslations = [];
    private $apiParameters = [];
    private $delimiter = '#';
    private $operationNamespace;
    private $useNames = [];

    /**
     * Fully qualified classname - aka namespace + classname
     * @var
     */
    private $fqcn;

    private $fqExceptionClassname = null;

    /**
     * @var string[] The interfaces the generated API class should implement
     */
    private $interfaces = [];

    private $interfaceName;

    /**
     * @var bool Whether the API requires Oauth1 signing service.
     * Defaults to false.
     */
    private $requiresOauth1 = false;

    private $includeMethods = [];

    private $excludeMethods = [];

    /**
     * @var callable
     */
    private $normalizeMethodCallable = null;

    /**
     * @var callable
     */
    private $normalizeClassCallable = null;

    /**
     * @var \ArtaxServiceBuilder\OperationDefinition[]
     */
    private $operations = [];

    private $authErrorAsException = false;

    private $constructorParams;

    /**
     * @param $outputPath
     * @param $constructorParams
     */
    function __construct($outputPath, $constructorParams) {
        $this->classGenerator = new ClassGenerator();
        $this->interfaceGenerator = new InterfaceGenerator();
        $this->constructorParams = $constructorParams;
        $this->outputPath = $outputPath;
    }

    /**
     * @param $requiresOauth1
     */
    function setRequiresOauth1($requiresOauth1) {
        $this->requiresOauth1 = $requiresOauth1;
    }

    /**
     * Whether to throw AuthException when an authorization error occurs.
     *
     * The service can generate code to handle authorisation errors in one of two ways:
     *
     * i) Throw an AuthException.
     * ii) Retutn an AuthorisationRequiredResponse
     *
     * @param $authErrorAsException
     */
    function setAuthErrorAsException($authErrorAsException) {
        $this->authErrorAsException = $authErrorAsException;
    }

    /**
     * @return mixed
     */
    function getFQCN() {
        return $this->fqcn;
    }

    /**
     * Get the list of parameters (by name) that should only exist at an API level, rather
     * than being copied all over the API.
     * @return mixed
     */
    function getAPIParameters() {
        return $this->apiParameters;
    }

    /**
     * @return OperationDefinition[]
     */
    function getOperations() {
        return $this->operations;
    }

    /**
     * @param $interface
     */
    function addInterface($interface) {
        $this->interfaces[] = $interface;
    }

    /**
     * @param $parameter
     * @return mixed
     */
    function translateParameter($parameter) {
        if (array_key_exists($parameter, $this->parameterTranslations) == true) {
            return $this->parameterTranslations[$parameter];
        }

        return $parameter;
    }

    /**
     * @param $fqcn
     */
    function setFQCN($fqcn) {
        $this->fqcn = $fqcn;
        $this->classGenerator->setFQCN($fqcn);

        if ($this->fqExceptionClassname == null) {
            $this->fqExceptionClassname =  $this->fqcn.'Exception';
        }

        $this->namespace = \ArtaxServiceBuilder\getNamespace($this->fqcn);
    }

    /**
     * @param $operationNamespace
     */
    function setOperationNamespace($operationNamespace) {
        $this->operationNamespace = $operationNamespace;
    }

    /**
     * @param $methodMatcher
     * @param $basePaginationOperationName
     * @throws ArtaxServiceException
     */
    public function addPaginationMethods($methodMatcher, $basePaginationOperationName) {

        if (isset($this->operations[$basePaginationOperationName]) == false) {
            throw new ArtaxServiceException("Could not find base pagination operation '$basePaginationOperationName'.");
        }

        $basePaginationOperation = $this->operations[$basePaginationOperationName];
        $methodMatcherPattern = '#'.$methodMatcher.'#';

        foreach ($this->operations as $operation) {
            if ($operation->getName() === $basePaginationOperationName) {
                //Avoid yo' dawging the  $basePaginationOperation
                continue;
            }

            $match = preg_match($methodMatcherPattern, $operation->getName());

            if (!$match) {
                continue;
            }

            if (strtoupper($operation->getHttpMethod()) !== "GET") {
                //It's only sensible to add pagination to GET methods.
                continue;
            }

            if (!$operation->getResponseClass()) {
                continue;
            }

            $params = ["responseClass" => $operation->getResponseClass()];

            $newName = $operation->getName()."Paginate";

            if (isset($this->operations[$newName])) {
                //Don't overwrite user created operations.
                continue;
            }

            $pageOperation = $basePaginationOperation->extend(
                $newName,
                $params
            );
            $this->addOperation($newName, $pageOperation);
        }
    }

    /**
     *
     */
    function addConstructorMethod() {
        if (count($this->constructorParams)) {
            $methodGenerator = new MethodGenerator('__construct');

            $body = '';
            $params = [];

            //Every API needs the Amp\Artax\Client object to send requests
            $param = new ParameterGenerator('client', 'Amp\Artax\Client', null);
            $params[] = $param;
            $body .= '$this->client = $client;'.PHP_EOL;

            $param = new ParameterGenerator('reactor', 'Amp\Reactor', null);
            $params[] = $param;
            $body .= '$this->reactor = $reactor;'.PHP_EOL;

            $param = new ParameterGenerator('responseCache', 'ArtaxServiceBuilder\ResponseCache', null);
            $params[] = $param;
            $body .= '$this->responseCache = $responseCache;'.PHP_EOL;

            //Add the params
            foreach ($this->constructorParams as $constructorParam) {
                $param = new ParameterGenerator($constructorParam);
                $params[] = $param;
                $body .= sprintf('$this->%s = $%s;', $constructorParam, $constructorParam);
                $body .= PHP_EOL;
            }

            //Add an oauth signing service if the API needs one
            if ($this->requiresOauth1 == true) {
                $param = new ParameterGenerator('oauthService', 'ArtaxServiceBuilder\Service\Oauth1', null);
                $param->setDefaultValue(null);
                $params[] = $param;
                $body .= sprintf('$this->%s = $%s;', 'oauthService', 'oauthService');
                $body .= PHP_EOL;
            }

            $methodGenerator->setBody($body);
            $methodGenerator->setParameters($params);
            $this->classGenerator->addMethodFromGenerator($methodGenerator);
        }
    }

    /**
     *
     */
    function addExecMethod() {
        $methodGenerator = new MethodGenerator('execute');
        $requestParam = new ParameterGenerator('request', 'Amp\Artax\Request');
        $successStatusParam = new ParameterGenerator('operation', 'ArtaxServiceBuilder\Operation');
        $methodGenerator->setParameters([$requestParam, $successStatusParam]);
        $methodGenerator->setBody($this->getExecuteBody());

        $tags = [];
        $tags[] = new GenericTag(
            'param',
            '$request \Amp\Artax\Request The request to send.'
        );
        $tags[] = new GenericTag(
            'param',
            '$operation \ArtaxServiceBuilder\Operation The response that is called the execute.'
        );
        $tags[] = new GenericTag(
            'return',
            '\Amp\Artax\Response The response from Artax'
        );

        $docBlockGenerator = new DocBlockGenerator('execute');
        $docBlockGenerator->setLongDescription("Sends a request to the API synchronously");
        $docBlockGenerator->setTags($tags);
        $methodGenerator->setDocBlock($docBlockGenerator);

        $this->classGenerator->addMethodFromGenerator($methodGenerator);
    }

    /**
     *
     */
    function addExecAsyncMethod() {
        $methodGenerator = new MethodGenerator('executeAsync');
        $requestParam = new ParameterGenerator('request', 'Amp\Artax\Request');
        $operationParam = new ParameterGenerator('operation', 'ArtaxServiceBuilder\Operation');
        $callableParam = new ParameterGenerator('callback', 'callable');

        $methodGenerator->setParameters([$requestParam, $operationParam, $callableParam]);

        $body = <<< 'END'

$originalRequest = clone $request;
$cachingHeaders = $this->responseCache->getCachingHeaders($request);
$request->setAllHeaders($cachingHeaders);
$promise = $this->client->request($request);
$promise->when(function(\Exception $error = null, Response $response = null) use ($originalRequest, $callback, $operation) {

    if ($response) {
        $operation->setResponse($response);
        $operation->setOriginalResponse($response);
    }

    if($error) {
        $callback($error, null, null);
        return;
    }

    if ($operation->shouldResponseBeCached($response)) {
        $this->responseCache->storeResponse($originalRequest, $response);
    }

    if ($operation->shouldUseCachedResponse($response)) {
        $cachedResponse = $this->responseCache->getResponse($originalRequest);
        if ($cachedResponse) {
            $response = $cachedResponse;
            $operation->setResponse($response);
        }
    }

    $responseException = $operation->translateResponseToException($response);
    if ($responseException) {
        $callback($responseException, null, $response);
        return;
    }

    if ($operation->shouldResponseBeProcessed($response)) {
        try {
            $parsedResponse = $operation->processResponse($response);
            $callback(null, $parsedResponse, $response);
        }
        catch(\Exception $e) {
            $exception = new ProcessResponseException("Exception parsing response: ".$e->getMessage(), 0, $e);
            $callback($exception, null, $response);
        }
    }
    else {
        $callback(null, null, $response);
    }
});

return $promise;
END;

        $methodGenerator->setBody($body);

        $tags = [];
        $tags[] = new GenericTag(
            'param',
            '\ArtaxServiceBuilder\Operation $operation The operation to perform'
        );
        $tags[] = new GenericTag(
            'param',
            'callable $callback The callback to call on completion/response. The signature of the method should be:
function(
    \Exception $error = null, // null if no error
    $parsedData = null, //The parsed operation data i.e. same type as responseClass of the operation.
    \Amp\Artax\Response $response = null //The response received or null if the request completely failed.
)'
        );

        $tags[] = new GenericTag(
            'return',
            '\Amp\Promise A promise to resolve the call at some time.'
        );

        $docBlockGenerator = new DocBlockGenerator('executeAsync');
        $docBlockGenerator->setLongDescription("Execute an operation asynchronously.");
        $docBlockGenerator->setTags($tags);
        $methodGenerator->setDocBlock($docBlockGenerator);
        $this->classGenerator->addMethodFromGenerator($methodGenerator);
        $this->interfaceGenerator->addMethodFromGenerator($methodGenerator);
    }

    /**
     *
     */
    function addSignMethod() {
        if ($this->requiresOauth1 !== true) {
            return;
        }

        $methodGenerator = new MethodGenerator('signRequest');
        $requestParam = new ParameterGenerator('request', 'Amp\Artax\Request');
        $methodGenerator->setParameters([$requestParam]);

        $body = 'if ($this->oauthService == null) {'.PHP_EOL;;
        $body .= '    throw new \ArtaxServiceBuilder\ArtaxServiceException("oauthService is null, so cannot call request that requires oauth.");'.PHP_EOL;;
        $body .= '}'.PHP_EOL;;

        $body .= 'return $this->oauthService->signRequest($request);'.PHP_EOL;
        $methodGenerator->setBody($body);
        $this->classGenerator->addMethodFromGenerator($methodGenerator);
    }

    /**
     *
     */
    function addPrepareMethod() {
        $methodGenerator = new MethodGenerator('prepareAPI');
        $methodGenerator->setParameters(['url', 'parameters']);
        $methodGenerator->setBody($this->getPrepareBody());
        $this->classGenerator->addMethodFromGenerator($methodGenerator);
    }

    /**
     * @return string
     */
    function getPrepareBody() {

        $body = <<< 'END'

$request = new \Amp\Artax\Request();
$fullURL = $url.'?'.http_build_query($parameters, '', '&', PHP_QUERY_RFC3986);
$request->setUri($fullURL);

return $request;
END;

        return $body;
    }

    /**
     * @return string
     */
    function getExecuteBody() {

        $body = <<< 'END'

$originalRequest = clone $request;
$cachingHeaders = $this->responseCache->getCachingHeaders($request);
$request->setAllHeaders($cachingHeaders);
$promise = $this->client->request($request);
$response = \Amp\wait($promise, $this->reactor);

if ($response) {
    $operation->setResponse($response);
    $operation->setOriginalResponse($response);
}

if ($operation->shouldResponseBeCached($response)) {
    $this->responseCache->storeResponse($originalRequest, $response);
}

if ($operation->shouldUseCachedResponse($response)) {
    $cachedResponse = $this->responseCache->getResponse($originalRequest);
    if ($cachedResponse) {
        $response = $cachedResponse;
        $operation->setResponse($response);
    }
    //@TODO This code should only be reached if the cache entry was deleted
    //so throw an exception? Or just leave the 304 to error?
}

$exception = $operation->translateResponseToException($response);

if ($exception) {
    throw $exception;
}

return $response;
END;
        $body = sprintf(
            $body,
            $this->fqExceptionClassname,
            $this->fqExceptionClassname
        );

        return $body;
    }

    /**
     * @param $methodName
     * @param $functionDefintion
     */
    function addOperation($methodName, OperationDefinition $operation) {
        $this->operations[$methodName] = $operation;
    }

    /**
     * Add the methods that return the operations in the API.
     */
    function addOperationGetter(
        $methodName,
        OperationDefinition $operation,
        OperationGenerator $operationGenerator
    ) {
        $operationName = $this->normalizeMethodName($methodName);
        $operationClassName = $this->normalizeClassName($methodName);
        $methodGenerator = new MethodGenerator($operationName);

        $apiParameters = $this->getAPIParameters();

        $body = '';

        //All required parameters must be passed in when the operation is created.
        $requiredParameters = $operation->getRequiredParams();

        $paramsStrings = [];
        $requiredParamsStringsWithDollar = [];
        $tags = [];

        $requiredParamsStringsWithDollar[] = '$this';

        foreach($requiredParameters as $requiredParam) {
            $translatedParam = ucfirst($this->translateParameter($requiredParam->getName()));
            $normalizedParamName = normalizeParamName($requiredParam->getName());

            if (array_key_exists($requiredParam->getName(), $apiParameters) == true) {
                $requiredParamsStringsWithDollar[] = sprintf(
                    '$this->get%s()',
                    $translatedParam
                );
            }
            else {
                $paramsStrings[] = $normalizedParamName;
                $tags[] = new GenericTag(
                    'param',
                    $requiredParam->getType().' $'.$requiredParam->getName().' '.$requiredParam->getDescription()
                );
                //TODO - replace with array_map on $paramsStrings
                $requiredParamsStringsWithDollar[] = '$'.$normalizedParamName;
            }
        }

        $paramString = implode(', ', $requiredParamsStringsWithDollar);
        $methodGenerator->setParameters($paramsStrings);

        $tags[] = new GenericTag(
            'return',
            '\\'.$operationGenerator->getFQCN().' The new operation '
        );

        $body .= "\$instance = new $operationClassName($paramString);".PHP_EOL;
        $body .= "return \$instance;".PHP_EOL;

        $docBlockGenerator = new DocBlockGenerator($methodName);
        $docBlockGenerator->setLongDescription($operation->getSummary());
        $docBlockGenerator->setTags($tags);

        $methodGenerator->setDocBlock($docBlockGenerator);
        $methodGenerator->setBody($body);
        $this->classGenerator->addMethodFromGenerator($methodGenerator);
        $this->interfaceGenerator->addMethodFromGenerator($methodGenerator);
    }

    /**
     *
     */
    private function generateMethods() {
        foreach ($this->operations as $methodName => $operation) {
            if ($this->shouldOperationBeGenerated($methodName)) {
                $operationGenerator = $this->generateOperationClass($methodName, $operation);
                $this->addOperationGetter($methodName, $operation, $operationGenerator);
            }
        }
    }

    /**
     * @param $methodName
     * @return mixed
     */
    public function normalizeMethodName($methodName) {
        if ($this->normalizeMethodCallable != null) {
            $callable = $this->normalizeMethodCallable;
            return $callable($methodName);
        }

        $pattern = '/\.(\w?)/i';

        $replaceCallable = function (array $matches) {
            return strtoupper($matches[1]);
        };

        return preg_replace_callback($pattern, $replaceCallable, $methodName);
    }

    /**
     * @param $methodName
     * @return mixed
     */
    public function normalizeClassName($methodName) {
        if ($this->normalizeClassCallable != null) {
            $callable = $this->normalizeClassCallable;
            return $callable($methodName);
        }

        $pattern = '/\.(\w?)/i';

        $replaceCallable = function (array $matches) {
            return strtoupper($matches[1]);
        };

        return preg_replace_callback($pattern, $replaceCallable, $methodName);
    }

    /**
     * @param $methodName
     * @param OperationDefinition $operation
     */
    private function generateOperationClass($methodName, OperationDefinition $operation) {
        $className = $this->normalizeClassName($methodName);

        $operationGenerator = new OperationGenerator(
            $this->operationNamespace,
            $className,
            $operation,
            $this->outputPath,
            $this
        );

        $operationGenerator->setAPIClassname($this->fqcn);
        $operationGenerator->generate();
        $this->addUseStatement($operationGenerator->getFQCN());
        $this->addUseStatement('Amp\Artax\Response');
        $this->addUseStatement('ArtaxServiceBuilder\BadResponseException');
        $this->addUseStatement('ArtaxServiceBuilder\ProcessResponseException');

        return $operationGenerator;
    }

    /**
     * @param $interfaceFQCN
     * @throws APIBuilderException
     */
    function generateInterface($interfaceFQCN) {
        $this->interfaceGenerator->setFQCN($interfaceFQCN);
        $text = $this->interfaceGenerator->generate();
        saveFile($this->outputPath, $interfaceFQCN, $text);
    }

    /**
     * @throws APIBuilderException
     */
    function sanityCheck() {

        if (!$this->fqcn) {
            throw new APIBuilderException("fqcn is empty, cannot generate API.");
        }

        if (!$this->fqExceptionClassname) {
            throw new APIBuilderException("fqExceptionClassname is empty, cannot generate API.");
        }
    }

    /**
     * @throws \ArtaxServiceBuilder\APIBuilderException
     */
    function generateExceptionClass() {

        $namespace = \ArtaxServiceBuilder\getNamespace($this->fqcn);
        $classname = \ArtaxServiceBuilder\getClassName($this->fqcn);
        $exceptionClassname = $classname.'Exception';

        if ($namespace) {
            $fqExceptionClassname = $namespace.'\\'.$classname.'Exception';
        }
        else {
            $fqExceptionClassname = $classname.'Exception';
        }

$classText = <<< END

namespace $namespace;

use Amp\Artax\Response;

class $exceptionClassname extends \Exception {

    /**
     * @var \Amp\Artax\Response
     */
    private \$response;

    function __construct(Response \$response, \$message = "", \$code = 0, \Exception \$previous = null) {
        parent::__construct(\$message, \$code, \$previous);
        \$this->response = \$response;
    }

    function getResponse() {
        return \$this->response;
    }
}

END;

        saveFile($this->outputPath, $fqExceptionClassname, $classText);
    }

    /**
     * @param array $methodNameArray
     */
    function includeMethods(array $methodNameArray) {
        $quoteCallable = function ($string) {
            return preg_quote($string, $this->delimiter);
        };
        $newIncludes = array_map($quoteCallable, $methodNameArray);
        $this->includeMethods = array_merge($this->includeMethods, $newIncludes);
    }

    /**
     * @param array $methodNameArray
     */
    function excludeMethods(array $methodNameArray) {
        $quoteCallable = function ($string) {
            return preg_quote($string, $this->delimiter);
        };
        $newExcludes = array_map($quoteCallable, $methodNameArray);
        $this->excludeMethods = array_merge($this->excludeMethods, $newExcludes);
    }

    /**
     * @param $pattern
     */
    function includePattern($pattern) {
        $this->includeMethods[] = $pattern;
    }

    /**
     * @param $pattern
     */
    function excludePattern($pattern) {
        $this->excludeMethods[] = $pattern;
    }

    /**
     * @param $operationName
     * @return bool
     */
    function shouldOperationBeGenerated($operationName) {

        $shouldInclude = false;

        if (count($this->includeMethods) == 0) {
            //Include filter is empty - so add all operations.
            $shouldInclude = true;
        }

        foreach ($this->includeMethods as $includePattern) {
            $includePattern = $this->delimiter.$includePattern.$this->delimiter;
            if (preg_match($includePattern, $operationName)) {
                $shouldInclude = true;
            }
        }

        foreach ($this->excludeMethods as $excludePattern) {
            $includePattern = $this->delimiter.$excludePattern.$this->delimiter;
            if (preg_match($includePattern, $operationName)) {
                $shouldInclude = false;
            }
        }

        return $shouldInclude;
    }

    /**
     * Guzzle style service descriptions have a bad habit of requiring certain parameters
     * that ought to be defined once, be defined in every operation that requires them.
     * For example the Flickr API requires the api_key be set for every operation. It dumb
     * and counter-productive to define this repeatedly in the API. It should be set once
     * in the API, and that value be passed to every operation that requires it.
     * @param array $apiParameters
     */
    public function addAPIParameters(array $apiParameters) {
        $this->apiParameters = array_merge($this->apiParameters, $apiParameters);
    }

    public function addAPIParameter($name, $type = null) {
        $this->apiParameters[$name] = $type;
    }

    private function createMethodGenerator($methodName, $body, $docBlock, $parameterInfoArray) {
        $parameters = [];
        foreach ($parameterInfoArray as $parameterInfo) {
            $parameters[] = new ParameterGenerator($parameterInfo[0], $parameterInfo[1]);
        }

        $methodGenerator = new MethodGenerator($methodName);
        $methodGenerator->setParameters($parameters);
        $methodGenerator->setDocBlock($docBlock);
        $methodGenerator->setBody($body);

        return $methodGenerator;
    }

    /**
     * Generate the docblock generator
     * @return DocBlockGenerator
     */
    private function generateExecuteDocBlock($methodDescription, $returnType) {
        $docBlock = new DocBlockGenerator($methodDescription, null);
        $tags[] = new GenericTag('return', $returnType);
        $docBlock->setTags($tags);

        return $docBlock;
    }

    function addShouldResponseBeProcessedMethod() {
        $body = 'return true;';
        $docBlock = $this->generateExecuteDocBlock('Determine whether the response should be processed.', 'boolean');

        $methodGenerator = $this->createMethodGenerator(
            'shouldResponseBeProcessed',
            $body,
            $docBlock,
            [['response', 'Amp\Artax\Response']]
        );

        $this->classGenerator->addMethodFromGenerator($methodGenerator);
    }

    /**
     *
     */
    function addShouldResponseBeCachedMethod() {

        $body = <<< 'END'
$status = $response->getStatus();
if ($status == 200) {
    return true;
}

return false;
END;

        $docBlock = $this->generateExecuteDocBlock('Determine whether the response should be cached.', 'boolean');

        $methodGenerator = $this->createMethodGenerator(
            'shouldResponseBeCached',
            $body,
            $docBlock,
            [['response', 'Amp\Artax\Response']]
        );

        $this->classGenerator->addMethodFromGenerator($methodGenerator);
    }

    /**
     *
     */
    function addShouldUseCachedResponseMethod() {

        $body = <<< 'END'
$status = $response->getStatus();
if ($status == 304) {
    return true;
}

return false;
END;

        $docBlock = $this->generateExecuteDocBlock('Determine whether the cached response should be used.', 'boolean');

        $methodGenerator = $this->createMethodGenerator(
            'shouldUseCachedResponse',
            $body,
            $docBlock,
            [['response', 'Amp\Artax\Response']]
        );

        $this->classGenerator->addMethodFromGenerator($methodGenerator);
    }

    function addAbstractInstantiateResultMethod() {

        //$docBlock = $this->generateExecuteDocBlock('Determine whether the cached response should be used.', 'boolean');
        $parameters = [];
        $parameters[] = new ParameterGenerator('response', 'Amp\Artax\Response');
        $parameters[] = new ParameterGenerator('operation', 'ArtaxServiceBuilder\Operation');

        $methodGenerator = new MethodGenerator('instantiateResult');
        $methodGenerator->setParameters($parameters);
        //$methodGenerator->setDocBlock($docBlock);
        $methodGenerator->setAbstract(true);

        $this->classGenerator->addMethodFromGenerator($methodGenerator);
    }

    /**
     *
     */
    function addIsErrorResponseMethod() {
        $body = <<< 'END'

$status = $response->getStatus();
if ($status < 200 || $status >= 300 ) {
    return true;
}

return false;
END;

        $docBlock = $this->generateExecuteDocBlock('Determine whether the response should be processed.', 'boolean');

        $methodGenerator = $this->createMethodGenerator(
            'isErrorResponse',
            $body,
            $docBlock,
            [['response', 'Amp\Artax\Response']]
        );

        $this->classGenerator->addMethodFromGenerator($methodGenerator);
    }

    /**
     *
     */
    function addtranslateResponseToExceptionMethod() {
        $body = <<< 'END'
$status = $response->getStatus();
if ($status < 200 || $status >= 300) {
    return new BadResponseException(
        "Status $status is not treated as OK.",
        $response
    );
}

return null;
END;

        $docBlock = $this->generateExecuteDocBlock('Inspect the response and return an exception if it is an error response.
     * Exceptions should extend \ArtaxServiceBuilder\BadResponseException', 'BadResponseException');

        $methodGenerator = $this->createMethodGenerator(
            'translateResponseToException',
            $body,
            $docBlock,
            [['response', 'Amp\Artax\Response']]
        );

        $this->classGenerator->addMethodFromGenerator($methodGenerator);
    }

    /**
     * Allows you to use your preference for formatting of variables in the API library
     * code, while still passing the correct variables to the API end-point.
     *
     * Because other people have no taste.
     * @param array $translations
     */
    public function addParameterTranslation(array $translations) {
        $this->parameterTranslations = array_merge($this->parameterTranslations, $translations);
    }

    /**
     * @param $service
     * @param $operationName
     * @param $baseURL
     * @return OperationDefinition
     * @throws \ArtaxServiceBuilder\APIBuilderException
     */
    function createOperationDescription($service, $operationName, $baseURL) {

        if (isset($service["operations"][$operationName]) == false) {
            throw new APIBuilderException("Service does not have operation named `$operationName`.");
        }

        $operationDescription = $service["operations"][$operationName];

        if (isset($operationDescription['extends'])) {
            $operation = $this->createOperationDescription($service, $operationDescription['extends'], $baseURL);
        }
        else {
            $operation = new OperationDefinition();
        }

        $operation->setName($operationName);
        $operation->setURL($baseURL);//Do this first, as it can be overwritten

        $operation->setFromServiceDescription($operationDescription, $baseURL, $this);

        return $operation;
    }

    /**
     * Parses a service file and adds all the operations to this
     * @param $serviceFilename
     * @return array
     * @throws APIBuilderException
     */
    function parseAndAddServiceFromFile($serviceFilename) {
        $service = require $serviceFilename;

        if ($service == false) {
            throw new APIBuilderException("Failed to open service file `$serviceFilename`.");
        }
        if (is_array($service) == false) {
            throw new APIBuilderException("File `$serviceFilename` did not return a service array. Cannot build API from it.");
        }

        $this->parseAndAddService($service);
    }

    /**
     * @param array $service
     * @throws APIBuilderException
     */
    function parseAndAddService(array $service) {
        $baseURL = null;
        if (isset($service["baseUrl"])) {
            $baseURL = $service["baseUrl"];
        }

        foreach ($service["operations"] as $operationName => $operationDescription) {
            $operation = $this->createOperationDescription($service, $operationName, $baseURL);
            $this->addOperation($operation->getName(), $operation);
        }
    }

    /**
     * @param string $serviceFilename
     * @return OperationDefinition[]
     * @throws APIBuilderException
     */
    function parseServiceFile($serviceFilename) {

        $service = require $serviceFilename;
        $operations = [];

        $baseURL = null;

        if (isset($service["baseUrl"])) {
            $baseURL = $service["baseUrl"];
        }

        foreach ($service["operations"] as $operationName => $operationDescription) {
            $operations[] = $this->createOperationDescription($service, $operationName, $baseURL);
        }

        return $operations;
    }

    /**
     *
     */
    function addAPIParameterAccessMethod() {

        foreach ($this->apiParameters as $apiParameter => $type) {
            $translatedParam = ucfirst($this->translateParameter($apiParameter));

            $methodGenerator = new MethodGenerator('get'.$translatedParam);
            $body = 'return $this->'.$apiParameter.';'.PHP_EOL;
            $methodGenerator->setBody($body);

            $methodGenerator->setDocBlock("@return $type");

            $this->classGenerator->addMethodFromGenerator($methodGenerator);

            $methodGenerator = new MethodGenerator('set'.$translatedParam);
            $body = '$this->'.$apiParameter.' = $value;'.PHP_EOL;
            $parameterParameter = new ParameterGenerator('value');
            $methodGenerator->setParameter($parameterParameter);
            $methodGenerator->setBody($body);
            $this->classGenerator->addMethodFromGenerator($methodGenerator);
        }
    }

    /**
     *
     */
    private function addProperties(array $nativeProperties) {

        if ($this->requiresOauth1 == true) {
            $nativeProperties['oauthService'] = 'ArtaxServiceBuilder\Service\Oauth1';
        }

        $nativeProperties['responseCache'] = 'ArtaxServiceBuilder\ResponseCache';
        $nativeProperties['reactor'] = 'Amp\Reactor';

        $allProperties = [$this->apiParameters, $nativeProperties];

        foreach ($allProperties as $properties) {
            foreach ($properties as $property => $type) {
                $propGenerator = new PropertyGenerator($property);
                $propGenerator->setStandardDocBlock($type);
                $this->classGenerator->addPropertyFromGenerator($propGenerator);
            }
        }
    }

    /**
     * @param $fqcn
     */
    function addUseStatement($fqcn) {
        if (in_array($fqcn, $this->useNames) == false) {
            $this->useNames[] = $fqcn;
        }

        $this->classGenerator->addUse($fqcn);
    }

    /**
     *
     */
    function generate() {

        $this->classGenerator->addUse('Amp\Artax\Request');
        $this->classGenerator->addUse('Amp\Artax\Response');
        $this->classGenerator->addUse('Amp\Reactor');

        $this->sanityCheck();
        $this->addProperties([]);
        $this->addConstructorMethod();
        $this->addSignMethod();
        $this->generateMethods();
        $this->addAPIParameterAccessMethod();

        if (count($this->interfaces)) {
            $this->classGenerator->setImplementedInterfaces($this->interfaces);
        }

        $this->classGenerator->addUse('ArtaxServiceBuilder\ResponseCache');
        $this->classGenerator->setAbstract(true);

        $this->generateExceptionClass();
        $this->addExecMethod();
        $this->addExecAsyncMethod();
        $this->addShouldResponseBeProcessedMethod();
        $this->addShouldResponseBeCachedMethod();
        $this->addShouldUseCachedResponseMethod();
        $this->addAbstractInstantiateResultMethod();

        //$this->addIsErrorResponseMethod();
        $this->addtranslateResponseToExceptionMethod();
        $text = $this->classGenerator->generate();
        saveFile($this->outputPath, $this->fqcn, $text);
    }
}


<?php

declare(strict_types=1);

namespace Ruwork\Reminder\Provider;

use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\Common\Persistence\ObjectRepository;
use Ruwork\Reminder\Item\EntityItem;

abstract class AbstractEntityProvider implements ProviderInterface
{
    protected $useKeyAsItemId = false;
    private $managerRegistry;

    public function __construct(ManagerRegistry $managerRegistry)
    {
        $this->managerRegistry = $managerRegistry;
    }

    /**
     * {@inheritdoc}
     */
    final public function getItems(\DateTimeImmutable $time): iterable
    {
        $class = $this->getClass();
        $manager = $this->managerRegistry->getManagerForClass($class);
        $repository = $manager->getRepository($class);

        foreach ($this->getEntityIds($repository, $time) as $key => $id) {
            $itemId = $this->useKeyAsItemId ? $key : null;

            yield new EntityItem($manager, $class, $id, $itemId);
        }
    }

    abstract protected function getClass(): string;

    abstract protected function getEntityIds(ObjectRepository $repository, \DateTimeImmutable $time): iterable;
}