<?php

namespace Yugo\SMSGateway\Vendors;

use Illuminate\Support\Facades\Log;
use Unirest\Request;
use Yugo\SMSGateway\Interfaces\SMS;

class Zenziva implements SMS
{
    /**
     * API base URL.
     *
     * @var string
     */
    private $baseUrl = 'https://reguler.zenziva.net/apps';

    /**
     * Default userkey from Zenziva.
     *
     * @var string
     */
    private $userkey = null;

    /**
     * Default passkey from Zenziva.
     *
     * @var string
     */
    private $passkey = null;

    public function __construct()
    {
        $this->userkey = config('message.zenziva.userkey');
        $this->passkey = config('message.zenziva.passkey');
    }

    /**
     * Set userkey manually via app.
     *
     * @param string $user
     *
     * @return self
     */
    public function setUser(string $user): self
    {
        $this->userkey = $user;

        return $this;
    }

    /**
     * Set password manually via app.
     *
     * @param string $password
     *
     * @return self
     */
    public function setPassword(string $password): self
    {
        $this->passkey = $password;

        return $this;
    }

    /**
     * Send message using Zenziva API.
     *
     * @param array  $destinations
     * @param string $message
     *
     * @return array|null
     */
    public function send(array $destinations, string $message): ?array
    {
        $this->checkConfig();

        if (!empty($destinations)) {
            $destination = $destinations[0];
        }

        $query = http_build_query([
            'userkey' => $this->userkey,
            'passkey' => $this->passkey,
            'nohp'    => $destination,
            'pesan'   => $message,
        ]);

        $response = Request::get($this->baseUrl.'/smsapi.php?'.$query);

        $xml = simplexml_load_string($response->body);
        $body = json_decode(json_encode($xml), true);

        if (!empty($body['message']) and $body['message']['status'] != 0) {
            Log::error(sprintf('Zenziva: %s.', $body['message']['text']));
        }

        return [
            'code'    => $response->code,
            'message' => ($response->code == 200) ? 'OK' : $body['message']['text'] ?? '',
            'data'    => $body,
        ];
    }

    /**
     * Check credit balance.
     *
     * @return array|null
     */
    public function credit(): ?array
    {
        $this->checkConfig();

        $query = http_build_query([
            'userkey' => $this->userkey,
            'passkey' => $this->passkey,
        ]);

        $response = Request::get($this->baseUrl.'/smsapibalance.php?'.$query);

        $xml = simplexml_load_string($response->body);
        $body = json_decode(json_encode($xml), true);

        return [
            'code'    => $response->code,
            'message' => ($response->code == 200) ? 'OK' : $body['message']['text'] ?? '',
            'data'    => $body,
        ];
    }

    /**
     * Check config and add to log for easy debugging.
     *
     * @return void
     */
    private function checkConfig(): void
    {
        if (empty($this->userkey)) {
            Log::warning('Config "message.zenziva.userkey" is not defined.');
        }

        if (empty($this->passkey)) {
            Log::warning('Config "message.zenziva.passkey" is not defined.');
        }
    }
}


<?php namespace Cerbero\Workflow\Console\Commands;

use Symfony\Component\Console\Input\InputOption;

class CreateWorkflowCommand extends WorkflowGeneratorCommand {

	use AttachesPipesTrait;

	/**
	 * The console command name.
	 *
	 * @var string
	 */
	protected $name = 'workflow:create';

	/**
	 * The console command description.
	 *
	 * @var string
	 */
	protected $description = 'Create a new workflow';

	/**
	 * @author	Andrea Marco Sartori
	 * @var		string	$type	Type of class to generate.
	 */
	protected $type = 'Pipe';

	/**
	 * Execute the console command.
	 *
	 * @return mixed
	 */
	public function fire()
	{
		$this->inflector->of($name = $this->getWorkflowName());

		if($this->pipelines->exists($name))
		{
			return $this->error("The workflow [$name] already exists.");
		}

		$this->generateAllNeededFiles();

		$this->pipelines->store($name, $this->getNamespacedPipesByOption('attach'));

		$this->info('Workflow created successfully.');
	}

	/**
	 * Generate all the needed files.
	 *
	 * @author	Andrea Marco Sartori
	 * @return	void
	 */
	protected function generateAllNeededFiles()
	{
		$this->settleRepositoryIfNotExists();

		$this->generateJob();

		$this->generateRequestIfGuarded();

		$this->generatePipes();
	}

	/**
	 * Settle the pipeline repository if it does not exist.
	 *
	 * @author	Andrea Marco Sartori
	 * @return	void
	 */
	protected function settleRepositoryIfNotExists()
	{
		$source = $this->pipelines->getSource();

		if( ! $this->files->exists($source))
		{
			$this->pipelines->settle();
		}
	}

	/**
	 * Create the job to handle.
	 *
	 * @author	Andrea Marco Sartori
	 * @return	void
	 */
	protected function generateJob()
	{
		$name = $this->inflector->getJob();

		$this->call('make:job', compact('name'));
	}

	/**
	 * Create the request if unguard is not set.
	 *
	 * @author	Andrea Marco Sartori
	 * @return	void
	 */
	protected function generateRequestIfGuarded()
	{
		if( ! $this->option('unguard'))
		{
			$name = $this->inflector->getRequest();

			$this->call('make:request', compact('name'));
		}
	}

	/**
	 * Get the console command options.
	 *
	 * @return array
	 */
	protected function getOptions()
	{
		return [
			['attach', '-a', InputOption::VALUE_OPTIONAL, 'The pipes to attach to the workflow.', null],
			['unguard', '-u', InputOption::VALUE_NONE, 'Do not make this workflow validate data.', null],
		];
	}

}


<?php

/*
 * This file is part of Laravel LogViewer.
 *
 * (c) Graham Campbell <graham@alt-three.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace GrahamCampbell\LogViewer;

use GrahamCampbell\LogViewer\Http\Controllers\LogViewerController;
use GrahamCampbell\LogViewer\Log\Data;
use GrahamCampbell\LogViewer\Log\Factory;
use GrahamCampbell\LogViewer\Log\Filesystem;
use Illuminate\Routing\Router;
use Illuminate\Support\ServiceProvider;

/**
 * This is the log viewer service provider class.
 *
 * @author Graham Campbell <graham@alt-three.com>
 */
class LogViewerServiceProvider extends ServiceProvider
{
    /**
     * Boot the service provider.
     *
     * @return void
     */
    public function boot()
    {
        $this->setupPackage();

        $this->setupRoutes($this->app->router);
    }

    /**
     * Setup the package.
     *
     * @return void
     */
    protected function setupPackage()
    {
        $source = realpath(__DIR__.'/../config/logviewer.php');

        $this->publishes([$source => config_path('logviewer.php')], 'config');
        $this->publishes([
            realpath(__DIR__.'/../assets/css') => public_path('assets/styles'),
            realpath(__DIR__.'/../assets/js')  => public_path('assets/scripts'),
        ], 'public');

        $this->mergeConfigFrom($source, 'logviewer');

        $this->loadViewsFrom(realpath(__DIR__.'/../views'), 'logviewer');
    }

    /**
     * Setup the routes.
     *
     * @param \Illuminate\Routing\Router $router
     *
     * @return void
     */
    protected function setupRoutes(Router $router)
    {
        $router->group(['namespace' => 'GrahamCampbell\LogViewer\Http\Controllers'], function (Router $router) {
            require __DIR__.'/Http/routes.php';
        });
    }

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->registerLogData();
        $this->registerLogFilesystem();
        $this->registerLogFactory();

        $this->registerLogViewer();

        $this->registerLogViewerController();
    }

    /**
     * Register the log data class.
     *
     * @return void
     */
    protected function registerLogData()
    {
        $this->app->singleton('logviewer.data', function () {
            return new Data();
        });

        $this->app->alias('logviewer.data', Data::class);
    }

    /**
     * Register the log filesystem class.
     *
     * @return void
     */
    protected function registerLogFilesystem()
    {
        $this->app->singleton('logviewer.filesystem', function ($app) {
            $files = $app['files'];
            $path = $app['path.storage'].'/logs';

            return new Filesystem($files, $path);
        });

        $this->app->alias('logviewer.filesystem', Filesystem::class);
    }

    /**
     * Register the log factory class.
     *
     * @return void
     */
    protected function registerLogFactory()
    {
        $this->app->singleton('logviewer.factory', function ($app) {
            $filesystem = $app['logviewer.filesystem'];
            $levels = $app['logviewer.data']->levels();

            return new Factory($filesystem, $levels);
        });

        $this->app->alias('logviewer.factory', Factory::class);
    }

    /**
     * Register the log data class.
     *
     * @return void
     */
    protected function registerLogViewer()
    {
        $this->app->singleton('logviewer', function ($app) {
            $factory = $app['logviewer.factory'];
            $filesystem = $app['logviewer.filesystem'];
            $data = $app['logviewer.data'];

            return new LogViewer($factory, $filesystem, $data);
        });

        $this->app->alias('logviewer', LogViewer::class);
    }

    /**
     * Register the log viewer controller class.
     *
     * @return void
     */
    protected function registerLogViewerController()
    {
        $this->app->bind(LogViewerController::class, function ($app) {
            $perPage = $app['config']['logviewer.per_page'];
            $middleware = $app['config']['logviewer.middleware'];

            return new LogViewerController($perPage, $middleware);
        });
    }

    /**
     * Get the services provided by the provider.
     *
     * @return string[]
     */
    public function provides()
    {
        return [
            'logviewer',
            'logviewer.data',
            'logviewer.factory',
            'logviewer.filesystem',
        ];
    }
}


<?php

/*
 * This file is part of Laravel LogViewer.
 *
 * (c) Graham Campbell <graham@alt-three.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace GrahamCampbell\LogViewer\Log;

use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Illuminate\Filesystem\Filesystem as Files;

/**
 * This is the filesystem class.
 *
 * @author Graham Campbell <graham@alt-three.com>
 */
class Filesystem
{
    /**
     * The files instance.
     *
     * @var \Illuminate\Filesystem\Filesystem
     */
    protected $files;

    /**
     * The base storage path.
     *
     * @var string
     */
    protected $path;

    /**
     * Create a new instance.
     *
     * @param \Illuminate\Filesystem\Filesystem $files
     * @param string                            $path
     *
     * @return void
     */
    public function __construct(Files $files, $path)
    {
        $this->files = $files;
        $this->path = $path;
    }

    /**
     * Get the log file path.
     *
     * @param string $date
     *
     * @throws \GrahamCampbell\LogViewer\Log\FilesystemException
     *
     * @return string
     */
    protected function path($date)
    {
        $path = $this->path.'/laravel-'.$date.'.log';

        if ($this->files->exists($path)) {
            return realpath($path);
        }

        throw new FilesystemException('The log(s) could not be located.');
    }

    /**
     * Read the log.
     *
     * @param string $date
     *
     * @throws \GrahamCampbell\LogViewer\Log\FilesystemException
     *
     * @return string
     */
    public function read($date)
    {
        try {
            return $this->files->get($this->path($date));
        } catch (FileNotFoundException $e) {
            throw new FilesystemException('There was an reading the log.');
        }
    }

    /**
     * Delete the log.
     *
     * @param string $date
     *
     * @throws \GrahamCampbell\LogViewer\Log\FilesystemException
     *
     * @return void
     */
    public function delete($date)
    {
        if (!$this->files->delete($this->path($date))) {
            throw new FilesystemException('There was an error deleting the log.');
        }
    }

    /**
     * List the log files.
     *
     * @return string[]
     */
    public function files()
    {
        return glob($this->path.'/laravel-*.log', GLOB_BRACE);
    }

    /**
     * Get the files instance.
     *
     * @return \Illuminate\Filesystem\Filesystem
     */
    public function getFiles()
    {
        return $this->files;
    }
}


<?php

/*
 * This file is part of Laravel LogViewer.
 *
 * (c) Graham Campbell <graham@alt-three.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace GrahamCampbell\LogViewer\Http\Controllers;

use Carbon\Carbon;
use GrahamCampbell\LogViewer\Facades\LogViewer;
use Illuminate\Pagination\Paginator;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Facades\View;

/**
 * This is the log viewer controller class.
 *
 * @author Graham Campbell <graham@alt-three.com>
 */
class LogViewerController extends Controller
{
    /**
     * The number of entries per page.
     *
     * @var int
     */
    protected $perPage;

    /**
     * Create a new instance.
     *
     * @param int      $perPage
     * @param string[] $middleware
     *
     * @return void
     */
    public function __construct($perPage, array $middleware)
    {
        $this->perPage = $perPage;

        foreach ($middleware as $class) {
            $this->middleware($class);
        }
    }

    /**
     * Redirect to the show page.
     *
     * @return \Illuminate\Http\Response
     */
    public function getIndex()
    {
        $today = Carbon::today()->format('Y-m-d');

        if (Session::has('success') || Session::has('error')) {
            Session::reflash();
        }

        return Redirect::to('logviewer/'.$today.'/all');
    }

    /**
     * Delete the log.
     *
     * @param string $date
     *
     * @return \Illuminate\Http\Response
     */
    public function getDelete($date)
    {
        try {
            LogViewer::delete($date);
            $today = Carbon::today()->format('Y-m-d');

            return Redirect::to('logviewer/'.$today.'/all')
                ->with('success', 'Log deleted successfully!');
        } catch (\Exception $e) {
            return Redirect::to('logviewer/'.$date.'/all')
                ->with('error', 'There was an error while deleting the log.');
        }
    }

    /**
     * Show the log viewing page.
     *
     * @param string      $date
     * @param string|null $level
     *
     * @return \Illuminate\Http\Response
     */
    public function getShow($date, $level = null)
    {
        $logs = LogViewer::logs();

        if (!is_string($level)) {
            $level = 'all';
        }

        $page = Input::get('page');
        if (empty($page)) {
            $page = '1';
        }

        $data = [
            'logs'       => $logs,
            'date'       => $date,
            'url'        => 'logviewer',
            'data_url'   => URL::route('logviewer.index').'/data/'.$date.'/'.$level.'?page='.$page,
            'levels'     => LogViewer::levels(),
            'current'    => $level,
        ];

        return View::make('logviewer::show', $data);
    }

    /**
     * Show the log contents.
     *
     * @param string      $date
     * @param string|null $level
     *
     * @return \Illuminate\Http\Response
     */
    public function getData($date, $level = null)
    {
        if (!is_string($level)) {
            $level = 'all';
        }

        $data = LogViewer::data($date, $level);
        $paginator = new Paginator($data, $this->perPage);

        $path = (new \ReflectionClass($paginator))->getProperty('path');
        $path->setAccessible(true);
        $path->setValue($paginator, URL::route('logviewer.index').'/'.$date.'/'.$level);

        if (count($data) > $paginator->perPage()) {
            $log = array_slice($data, $paginator->firstItem() - 1, $paginator->perPage());
        } else {
            $log = $data;
        }

        return View::make('logviewer::data', compact('paginator', 'log'));
    }
}


<?php

/*
 * This file is part of Laravel LogViewer.
 *
 * (c) Graham Campbell <graham@alt-three.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace GrahamCampbell\LogViewer\Log;

use Psr\Log\LogLevel;
use ReflectionClass;

/**
 * This is the data class.
 *
 * @author Graham Campbell <graham@alt-three.com>
 */
class Data
{
    /**
     * The cached log levels.
     *
     * @var string[]
     */
    protected $levels;

    /**
     * Get the log levels.
     *
     * @return string[]
     */
    public function levels()
    {
        if (!$this->levels) {
            $class = new ReflectionClass(new LogLevel());
            $this->levels = $class->getConstants();
        }

        return $this->levels;
    }
}


<?php

/*
 * This file is part of Laravel LogViewer.
 *
 * (c) Graham Campbell <graham@alt-three.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace GrahamCampbell\LogViewer\Log;

/**
 * This is the log class.
 *
 * @author Graham Campbell <graham@alt-three.com>
 */
class Log
{
    /**
     * The raw log contents.
     *
     * @var string
     */
    protected $raw;

    /**
     * The available log levels.
     *
     * @var string[]
     */
    protected $levels;

    /**
     * The selected log level.
     *
     * @var string
     */
    protected $level;

    /**
     * The processed log data.
     *
     * @var array
     */
    protected $data;

    /**
     * Create a new instance.
     *
     * @param string   $raw
     * @param string[] $levels
     * @param string   $level
     */
    public function __construct($raw, array $levels, $level = 'all')
    {
        $this->raw = $raw;
        $this->levels = $levels;
        $this->level = $level;
    }

    /**
     * Parse the log.
     *
     * @return array
     */
    protected function parse()
    {
        $log = [];

        $pattern = "/\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\].*/";

        preg_match_all($pattern, $this->raw, $headings);
        $data = preg_split($pattern, $this->raw);

        if ($data[0] < 1) {
            $trash = array_shift($data);
            unset($trash);
        }

        foreach ($headings as $heading) {
            for ($i = 0, $j = count($heading); $i < $j; $i++) {
                foreach ($this->levels as $level) {
                    if ($this->level == $level || $this->level == 'all') {
                        if (strpos(strtolower($heading[$i]), strtolower('.'.$level))) {
                            $log[] = ['level' => $level, 'header' => $heading[$i], 'stack' => $data[$i]];
                        }
                    }
                }
            }
        }

        unset($headings);
        unset($data);

        return array_reverse($log);
    }

    /**
     * Get the log data.
     *
     * @return array
     */
    public function data()
    {
        if (!$this->data) {
            $this->data = $this->parse();
        }

        return $this->data;
    }
}


<?php

/*
 * This file is part of Laravel LogViewer.
 *
 * (c) Graham Campbell <graham@alt-three.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace GrahamCampbell\LogViewer;

use GrahamCampbell\LogViewer\Log\Data;
use GrahamCampbell\LogViewer\Log\Factory;
use GrahamCampbell\LogViewer\Log\Filesystem;

/**
 * This is the log viewer class.
 *
 * @author Graham Campbell <graham@alt-three.com>
 */
class LogViewer
{
    /**
     * The factory instance.
     *
     * @var \GrahamCampbell\LogViewer\Log\Factory
     */
    protected $factory;

    /**
     * The filesystem instance.
     *
     * @var \GrahamCampbell\LogViewer\Log\Filesystem
     */
    protected $filesystem;

    /**
     * The data instance.
     *
     * @var \GrahamCampbell\LogViewer\Log\Data
     */
    protected $data;

    /**
     * Create a new instance.
     *
     * @param \GrahamCampbell\LogViewer\Log\Factory    $factory
     * @param \GrahamCampbell\LogViewer\Log\Filesystem $filesystem
     * @param \GrahamCampbell\LogViewer\Log\Data       $data
     *
     * @return void
     */
    public function __construct(Factory $factory, Filesystem $filesystem, Data $data)
    {
        $this->factory = $factory;
        $this->filesystem = $filesystem;
        $this->data = $data;
    }

    /**
     * Get the log data.
     *
     * @param string $date
     * @param string $level
     *
     * @return array
     */
    public function data($date, $level = 'all')
    {
        return $this->factory->make($date, $level)->data();
    }

    /**
     * Delete the log.
     *
     * @param string $date
     *
     * @return void
     */
    public function delete($date)
    {
        return $this->filesystem->delete($date);
    }

    /**
     * List the log files.
     *
     * @return string[]
     */
    public function logs()
    {
        $logs = array_reverse($this->filesystem->files());

        foreach ($logs as $index => $file) {
            $logs[$index] = preg_replace('/.*(\d{4}-\d{2}-\d{2}).*/', '$1', basename($file));
        }

        return $logs;
    }

    /**
     * Get the log levels.
     *
     * @return string[]
     */
    public function levels()
    {
        return $this->data->levels();
    }

    /**
     * Get the factory instance.
     *
     * @return \GrahamCampbell\LogViewer\Log\Factory
     */
    public function getFactory()
    {
        return $this->factory;
    }

    /**
     * Get the filesystem instance.
     *
     * @return \GrahamCampbell\Logviewer\Log\Filesystem
     */
    public function getFilesystem()
    {
        return $this->filesystem;
    }

    /**
     * Get the data instance.
     *
     * @return \GrahamCampbell\LogViewer\Log\Data
     */
    public function getData()
    {
        return $this->data;
    }
}


<?php

/*
 * This file is part of Laravel LogViewer.
 *
 * (c) Graham Campbell <graham@alt-three.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace GrahamCampbell\LogViewer\Log;

/**
 * This is the factory class.
 *
 * @author Graham Campbell <graham@alt-three.com>
 */
class Factory
{
    /**
     * The filesystem instance.
     *
     * @var \GrahamCampbell\LogViewer\Log\Filesystem
     */
    protected $filesystem;

    /**
     * The log levels.
     *
     * @var array
     */
    protected $levels;

    /**
     * Create a new instance.
     *
     * @param \GrahamCampbell\LogViewer\Log\Filesystem $filesystem
     * @param string[]                                 $levels
     */
    public function __construct(Filesystem $filesystem, array $levels)
    {
        $this->filesystem = $filesystem;
        $this->levels = $levels;
    }

    /**
     * Get the log instance.
     *
     * @param string $date
     * @param string $level
     *
     * @return \GrahamCampbell\LogViewer\Log\Log
     */
    public function make($date, $level = 'all')
    {
        $raw = $this->filesystem->read($date);
        $levels = $this->levels;

        return new Log($raw, $levels, $level);
    }

    /**
     * Get the filesystem instance.
     *
     * @return \GrahamCampbell\Logviewer\Log\Filesystem
     */
    public function getFilesystem()
    {
        return $this->filesystem;
    }
}


<?php

namespace JustPark\Deploy\Commands;

use InvalidArgumentException;
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Illuminate\Contracts\Config\Repository as Config;

class EnvoyerDeployCommand extends Command
{
    /**
     * Mask for deployment hook URL.
     */
    const DEPLOY_URL = 'https://envoyer.io/deploy/%s';

    /**
     * Default project configuration key.
     */
    const CONFIG_DEFAULT = 'envoyer.default';

    /**
     * Single project configuration key.
     */
    const CONFIG_PROJECT = 'envoyer.projects.%s';

    /**
     * The console command name.
     *
     * @var string
     */
    protected $name = 'envoyer:deploy';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Deploy an Envoyer.io project.';

    /**
     * Configuration repository.
     *
     * @var \Illuminate\Contracts\Config\Repository
     */
    protected $config;

    /**
     * Create a new command instance.
     *
     * @param \Illuminate\Contracts\Config\Repository $config
     * @return void
     */
    public function __construct(Config $config)
    {
        // Set configuration repository.
        $this->config = $config;

        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function fire()
    {
        // Get the project to deploy.
        $project = $this->getProjectToDeploy();

        // Trigger the deployment.
        $this->triggerDeploy($project);
    }

    /**
     * Retrieve hook from supplied project option or default.
     *
     * @return string
     */
    protected function getProjectToDeploy()
    {
        // Determine project to deploy.
        if (!$project = $this->option('project')) {
            $project = $this->getDefaultProjectHook();
        }

        return $project;
    }

    /**
     * Retrieve the default project hook.
     *
     * @return string
     */
    protected function getDefaultProjectHook()
    {
        // Get default project handle.
        $default = $this->config->get(self::CONFIG_DEFAULT);

        // Return project hook value.
        return $this->config->get(sprintf(self::CONFIG_PROJECT, $default));
    }

    /**
     * Trigger a deployment by project hook.
     *
     * @param  string $project
     * @return void
     */
    protected function triggerDeploy($project)
    {
        // Ensure we have a project hook.
        if (!$project) {
            throw new InvalidArgumentException('Incorrect project hook.');
        }

        // Trigger the deploy hook.
        file_get_contents(sprintf(self::DEPLOY_URL, $project));

        // Output message.
        $this->info('Deployment request successful!');
    }

    /**
     * Get the console command options.
     *
     * @return array
     */
    protected function getOptions()
    {
        return [
            [
                'project',
                'p',
                InputOption::VALUE_OPTIONAL,
                'The project that will be deployed.',
                false
            ]
        ];
    }
}


<?php

/**
 * @author     Michael Calcinai <michael@calcin.ai>
 */
namespace Calcinai\Strut;

abstract class BaseSchema implements \IteratorAggregate, \Countable, \JsonSerializable
{
    protected $data;

    protected static $enums = [];

    protected static $properties = [];

    protected static $pattern_properties = [];

    /**
     * This needs to be an array in the case that these schema has more than one
     * sub-schema in a oneOf, there's no point having to have an intermediary object.
     *
     * @var bool|array
     */
    protected static $additional_properties = [];

    /**
     * @param array $data
     * @throws \Exception
     */
    public function __construct($data = [])
    {
        $this->parseData($data);
    }

    /**
     * Pattern property setter
     *
     * @param $property_name
     * @param $value
     * @return $this
     * @throws \Exception
     */
    public function set($property_name, $value)
    {
        $this->validateProperty($property_name, $value);
        $this->data[$property_name] = $value;
        return $this;
    }

    /**
     * Pattern property array setter
     *
     * @param $property_name
     * @param $value
     * @return $this
     * @throws \Exception
     */
    public function add($property_name, $value)
    {
        $this->validateProperty($property_name, $value);
        $this->data[$property_name][] =& $value;
        return $this;
    }

    /**
     * Property getter
     *
     * @param $property_name
     * @return mixed
     */
    public function get($property_name)
    {
        return $this->data[$property_name];
    }

    /**
     * Property isset
     *
     * @param $property_name
     * @return bool
     */
    public function has($property_name)
    {
        return isset($this->data[$property_name]);
    }

    /**
     * Property unset
     *
     * @param $property_name
     * @return $this
     */
    public function remove($property_name)
    {
        unset($this->data[$property_name]);
        return $this;
    }

    /**
     * @param $property_name
     * @param $value
     * @return bool
     */
    private function validateProperty($property_name, $value)
    {
        //First check enums
        if (isset(static::$enums[$property_name]) && !in_array($value, static::$enums[$property_name])) {
            throw new \InvalidArgumentException(sprintf('Value for %s is not specified in the enum', $property_name));
        }
        //Test regular properties
        if (isset(static::$properties[$property_name])) {
            //There's no way to constrain it at this point
            if (empty(static::$properties[$property_name])) {
                return true;
            }
            foreach (static::$properties[$property_name] as $allowed_type) {
                if (gettype($value) === $allowed_type) {
                    return true;
                }
                $fq_class = self::getFQCN($allowed_type);
                if ($value instanceof $fq_class) {
                    return true;
                }
            }
        }
        //Then test additional
        if (is_bool(static::$additional_properties) && static::$additional_properties) {
            return true;
        } elseif (is_array(static::$additional_properties)) {
            if (empty(static::$additional_properties)) {
                return true;
            }
            foreach (static::$additional_properties as $allowed_type) {
                if (gettype($value) === $allowed_type) {
                    return true;
                }
                $fq_class = self::getFQCN($allowed_type);
                if ($value instanceof $fq_class) {
                    return true;
                }
            }
        }
        //Then test pattern
        foreach (static::$pattern_properties as $pattern => $types) {
            //Find an unused delimiter
            foreach (['/', '#', '+', '~', '%'] as $delimiter) {
                if (strpos($pattern, $delimiter) === false) {
                    break;
                }
            }
            /** @noinspection PhpUndefinedVariableInspection ...well, it is */
            if (preg_match("{$delimiter}{$pattern}{$delimiter}", $property_name)) {
                //If there's no rule, success anyway
                if (!isset($types[0])) {
                    return true;
                }
                foreach ($types as $allowed_type) {
                    if (gettype($value) === $allowed_type) {
                        return true;
                    }
                    $fq_class = self::getFQCN($allowed_type);
                    if ($value instanceof $fq_class) {
                        return true;
                    }
                }
            }
        }
        throw new \InvalidArgumentException(sprintf('[%s] does not accept property [%s]', get_class($this), $property_name));
    }

    /**
     * Parse a schema object into the correct objects
     *
     * @param $data
     * @throws \Exception
     */
    private function parseData($data)
    {
        foreach ($data as $property_name => $property) {
            //I think the best way to handle this, will at least always be consistent
            //without writing the same code twice.
            $types_to_try = [];
            //Collect regular props
            if (isset(static::$properties[$property_name])) {
                $types_to_try = array_merge($types_to_try, static::$properties[$property_name]);
            }
            //Collect pattern props
            foreach (static::$pattern_properties as $pattern_property) {
                $types_to_try = array_merge($types_to_try, $pattern_property);
            }
            //Collect additional props
            if (is_array(static::$additional_properties)) {
                $types_to_try = array_merge($types_to_try, static::$additional_properties);
            }
            if (is_array($property)) {
                foreach ($property as $property_element) {
                    $this->add($property_name, self::tryToCast($types_to_try, $property_element));
                }
            } else {
                $this->set($property_name, self::tryToCast($types_to_try, $property));
            }
        }
    }

    /**
     * @param $types_to_try
     * @param $object
     * @return BaseSchema
     * @throws \Exception
     */
    private static function tryToCast($types_to_try, $object)
    {
        //If there are no types, return as-is.
        if (empty($types_to_try)) {
            return $object;
        }
        foreach ($types_to_try as $type) {
            /** @var self $class */
            $class = self::getFQCN($type);
            if (!class_exists($class)) {
                settype($object, $type);
                return $object;
            }
            try {
                return $class::create($object);
            } catch (\InvalidArgumentException $e) {
                //let it continue to the next type
            }
        }
        //If it can't go into any of the possible types, throw.
        throw new \InvalidArgumentException();
    }

    /**
     * @param $relative_class
     * @return string
     */
    protected static function getFQCN($relative_class)
    {
        return sprintf('\\%s\\%s', __NAMESPACE__, $relative_class);
    }

    /**
     * @param array $data
     * @return static
     * @throws \Exception
     */
    public static function create($data = [])
    {
        return new static($data);
    }

    /**
     * @return mixed
     */
    function jsonSerialize()
    {
        return $this->data;
    }

    /**
     * Retrieve an external iterator
     */
    public function getIterator()
    {
        return new \ArrayIterator($this->data);
    }

    /**
     * Count elements of an object
     */
    public function count()
    {
        return count($this->data);
    }

}


<?php

namespace Rymanalu\LaravelSimpleUploader;

use Closure;
use Illuminate\Support\Str;
use InvalidArgumentException;
use Illuminate\Contracts\Container\Container;
use Rymanalu\LaravelSimpleUploader\Providers\UrlProvider;
use Rymanalu\LaravelSimpleUploader\Providers\LocalProvider;
use Rymanalu\LaravelSimpleUploader\Providers\HttpRequestProvider;
use Rymanalu\LaravelSimpleUploader\Contracts\Factory as FactoryContract;

class UploaderManager implements FactoryContract
{
    /**
     * The Container implementation.
     *
     * @var \Illuminate\Contracts\Container\Container
     */
    protected $app;

    /**
     * The array of file providers.
     *
     * @var array
     */
    protected $providers = [
        'local' => LocalProvider::class,
        'request' => HttpRequestProvider::class,
        'url' => UrlProvider::class,
    ];

    /**
     * The array of file custom providers.
     *
     * @var array
     */
    protected $customProviders = [];

    /**
     * The array of resolved file providers.
     *
     * @var array
     */
    protected $resolvedProviders = [];

    /**
     * Create a new UploaderManager instance.
     *
     * @param  \Illuminate\Contracts\Container\Container  $app
     * @return void
     */
    public function __construct(Container $app)
    {
        $this->app = $app;
    }

    /**
     * Register a custom file provider Closure.
     *
     * @param  string  $provider
     * @param  \Closure  $callback
     * @return \Rymanalu\LaravelSimpleUploader\Contracts\Factory
     * @throws \InvalidArgumentException
     */
    public function extend($provider, Closure $callback)
    {
        if ($this->isProviderAliasExists($provider)) {
            throw new InvalidArgumentException("Alias provider is already reserved [{$provider}]");
        }

        $this->customProviders[$provider] = $callback;

        return $this;
    }

    /**
     * Specify where the file is provided.
     *
     * @param  string|null  $provider
     * @return \Rymanalu\LaravelSimpleUploader\Contracts\Uploader
     */
    public function from($provider = null)
    {
        $provider = $provider ?: $this->getDefaultProvider();

        return new Uploader(
            $this->app->make('config'), $this->app->make('filesystem'), $this->createProviderInstance($provider)
        );
    }

    /**
     * Get the default file provider name.
     *
     * @return string
     */
    public function getDefaultProvider()
    {
        return $this->app->make('config')->get('uploader.default');
    }

    /**
     * Create the file provider instance.
     *
     * @param  string  $provider
     * @return \Rymanalu\LaravelSimpleUploader\Contracts\Provider
     *
     * @throws \InvalidArgumentException
     */
    protected function createProviderInstance($provider)
    {
        if (! $this->isProviderAliasExists($provider)) {
            throw new InvalidArgumentException("File provider [{$provider}] is invalid.");
        }

        if (! isset($this->resolvedProviders[$provider])) {
            $this->resolvedProviders[$provider] = isset($this->customProviders[$provider])
                ? $this->callCustomProvider($provider)
                : $this->app->make($this->providers[$provider]);
        }

        return $this->resolvedProviders[$provider];
    }

    /**
     * Call a custom file provider.
     *
     * @param  string  $provider
     * @return \Rymanalu\LaravelSimpleUploader\Contracts\Provider
     */
    protected function callCustomProvider($provider)
    {
        return $this->customProviders[$provider]($this->app);
    }

    /**
     * Handle dynamic "from" method calls.
     *
     * @param  string  $from
     * @return \Rymanalu\LaravelSimpleUploader\Contracts\Uploader
     */
    protected function dynamicFrom($from)
    {
        $provider = Str::snake(substr($from, 4));

        return $this->from($provider);
    }

    /**
     * Determine if the given provider alias is already exists in the default and custom providers array.
     *
     * @param  string  $provider
     * @return bool
     */
    protected function isProviderAliasExists($provider)
    {
        return array_key_exists($provider, $this->providers) || array_key_exists($provider, $this->customProviders);
    }

    /**
     * Handle dynamic method calls into the Uploader instance.
     *
     * @param  string  $method
     * @param  array  $parameters
     * @return mixed
     */
    public function __call($method, $parameters)
    {
        if (Str::startsWith($method, 'from')) {
            return $this->dynamicFrom($method);
        }

        return call_user_func_array([$this->from(), $method], $parameters);
    }
}


<?php

namespace Rymanalu\LaravelSimpleUploader;

use Illuminate\Support\ServiceProvider;

class UploaderServiceProvider extends ServiceProvider
{
    /**
     * Indicates if loading of the provider is deferred.
     *
     * @var bool
     */
    protected $defer = true;

    /**
     * Boot the application services.
     *
     * @return void
     */
    public function boot()
    {
        if ($this->app->runningInConsole()) {
            $this->publishes([
                __DIR__.'/../config/uploader.php' => config_path('uploader.php'),
            ], 'uploader');
        }
    }

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton('uploader', function ($app) {
            return new UploaderManager($app);
        });

        $this->app->alias('uploader', 'Rymanalu\LaravelSimpleUploader\Contracts\Factory');

        $this->app->singleton('uploader.from', function ($app) {
            return $app['uploader']->from();
        });

        $this->app->alias('uploader.from', 'Rymanalu\LaravelSimpleUploader\Contracts\Uploader');
    }

    /**
     * Get the services provided by the provider.
     *
     * @return array
     */
    public function provides()
    {
        return ['uploader', 'uploader.from'];
    }
}


<?php

namespace Rymanalu\LaravelSimpleUploader;

use Closure;
use BadMethodCallException;
use Illuminate\Support\Str;
use Illuminate\Contracts\Config\Repository as Config;
use Rymanalu\LaravelSimpleUploader\Contracts\Provider;
use Illuminate\Contracts\Filesystem\Factory as FilesystemManager;
use Rymanalu\LaravelSimpleUploader\Contracts\Uploader as UploaderContract;

class Uploader implements UploaderContract
{
    /**
     * The file storage where the file will be uploaded.
     *
     * @var string
     */
    public $disk;

    /**
     * The name of file.
     *
     * @var string
     */
    public $filename;

    /**
     * The file visibility.
     *
     * @var string|null
     */
    public $visibility;

    /**
     * The folder where the file will be stored.
     *
     * @var string
     */
    public $folder = '';

    /**
     * The Config implementation.
     *
     * @var \Illuminate\Contracts\Config\Repository
     */
    protected $config;

    /**
     * The file provider implementation.
     *
     * @var \Rymanalu\LaravelSimpleUploader\Contracts\Provider
     */
    protected $provider;

    /**
     * The FilesystemManager implementation.
     *
     * @var \Illuminate\Contracts\Filesystem\Factory
     */
    protected $filesystem;

    /**
     * Create a new Uploader instance.
     *
     * @param  \Illuminate\Contracts\Config\Repository  $config
     * @param  \Illuminate\Contracts\Filesystem\Factory  $filesystem
     * @param  \Rymanalu\LaravelSimpleUploader\Contracts\Provider  $provider
     * @return void
     */
    public function __construct(Config $config, FilesystemManager $filesystem, Provider $provider)
    {
        $this->config = $config;
        $this->provider = $provider;
        $this->filesystem = $filesystem;
    }

    /**
     * Specify the file storage where the file will be uploaded.
     *
     * @param  string  $disk
     * @return \Rymanalu\LaravelSimpleUploader\Contracts\Uploader
     */
    public function uploadTo($disk)
    {
        $this->disk = $disk;

        return $this;
    }

    /**
     * Specify the folder where the file will be stored.
     *
     * @param  string  $folder
     * @return \Rymanalu\LaravelSimpleUploader\Contracts\Uploader
     */
    public function toFolder($folder)
    {
        $this->folder = $folder;

        return $this;
    }

    /**
     * Rename the uploaded file to given new name.
     *
     * @param  string  $newName
     * @return \Rymanalu\LaravelSimpleUploader\Contracts\Uploader
     */
    public function renameTo($newName)
    {
        $this->filename = $newName;

        return $this;
    }

    /**
     * Set the visibility of the file.
     *
     * @param  string  $visibility
     * @return \Rymanalu\LaravelSimpleUploader\Contracts\Uploader
     */
    public function setVisibility($visibility)
    {
        $this->visibility = $visibility;

        return $this;
    }

    /**
     * Upload the file on a file storage.
     *
     * @param  string  $file
     * @param  \Closure|null $callback
     * @return bool
     */
    public function upload($file, Closure $callback = null)
    {
        $uploadedFile = $this->runUpload($file);

        if (! $uploadedFile) {
            return false;
        }

        if ($callback) {
            $callback($uploadedFile);
        }

        return true;
    }

    /**
     * Get the file visibility.
     *
     * @return string
     */
    public function getVisibility()
    {
        return $this->visibility ?: $this->getDefaultVisibility();
    }

    /**
     * Get the default file visibility.
     *
     * @return string
     */
    public function getDefaultVisibility()
    {
        return $this->config->get('uploader.visibility') ?: 'private';
    }

    /**
     * Upload the given file and returns the filename if succeed.
     *
     * @param  string  $file
     * @return string|bool
     *
     * @throws \Rymanalu\LaravelSimpleUploader\InvalidFileException
     */
    protected function runUpload($file)
    {
        $this->provider->setFile($file);

        if (! $this->provider->isValid()) {
            throw new InvalidFileException("Given file [{$file}] is invalid.");
        }

        $filename = $this->getFullFileName($this->provider);

        if ($this->filesystem->disk($this->disk)->put($filename, $this->provider->getContents(), $this->getVisibility())) {
            return $filename;
        }

        return false;
    }

    /**
     * Get the full filename.
     *
     * @param  \Rymanalu\LaravelSimpleUploader\Contracts\Provider  $provider
     * @return string
     */
    protected function getFullFileName(Provider $provider)
    {
        $folder = $this->folder ? rtrim($this->folder, '/').'/' : '';

        if ($this->filename) {
            $filename = $this->filename;
        } else {
            $filename = md5(uniqid(microtime(true), true));
        }

        return $folder.$filename.'.'.$provider->getExtension();
    }

    /**
     * Handle dynamic "uploadTo" method calls.
     *
     * @param  string  $uploadTo
     * @return \Rymanalu\LaravelSimpleUploader\Contracts\Uploader
     */
    protected function dynamicUploadTo($uploadTo)
    {
        $disk = Str::snake(substr($uploadTo, 8));

        return $this->uploadTo($disk);
    }

    /**
     * Handle dynamic method calls into the method.
     *
     * @param  string  $method
     * @param  array  $parameters
     * @return mixed
     *
     * @throws \BadMethodCallException
     */
    public function __call($method, $parameters)
    {
        if (Str::startsWith($method, 'uploadTo')) {
            return $this->dynamicUploadTo($method);
        }

        $className = static::class;

        throw new BadMethodCallException("Call to undefined method {$className}::{$method}()");
    }
}


<?php
/**
 * @link https://github.com/2amigos/yii2-semantic-ui
 * @copyright Copyright (c) 2013-2015 2amigOS! Consulting Group LLC
 * @license http://opensource.org/licenses/BSD-3-Clause
 */
namespace dosamigos\semantic\modules;

use dosamigos\semantic\Widget;
use yii\base\InvalidConfigException;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;
use dosamigos\semantic\helpers\Ui;

/**
 * Shape generates a semantic ui shape module. A three dimensional object displayed on a two dimensional plane.
 *
 * For example
 *
 * ```php
 * echo Shape::widget([
 *  'sides' => [
 *      ['content' => 'This side starts visible', 'active' => true], // first visible step
 *      ['content' => 'This is another ONEEEE'],
 *      ['content' => 'And ANOTHEEEER!']
 *  ]
 * ]);
 *
 * ```
 *
 * @see http://semantic-ui.com/modules/shape.html
 * @author Antonio Ramirez <amigo.cobos@gmail.com>
 * @link http://www.ramirezcobos.com/
 * @link http://www.2amigos.us/
 * @package dosamigos\semantic\modules
 */
class Shape extends Widget
{

    /**
     * @var array list of menu items in the shape. Each array element is an array representing a single side with the
     * following structure:
     *
     * - content: string, required, the HTML content of the side
     * - active: boolean, optional, whether this side should be active or not
     * - options: array, optional, the HTML attributes of the side item.
     */
    public $sides = [];
    /**
     * @var array the HTML attributes for the widget sides items container tag.
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
     */
    public $sidesOptions = [];

    /**
     * @inheritdoc
     */
    public function init()
    {
        parent::init();
        Html::addCssClass($this->options, 'shape');
        Html::addCssClass($this->sidesOptions, 'sides');
    }

    /**
     * @inheritdoc
     * @throws InvalidConfigException
     */
    public function run()
    {
        $lines = [];
        $lines[] = Html::beginTag('div', '', $this->options);
        $lines[] = $this->renderSides($this->sides);
        $lines[] = Html::endTag('div');

        echo implode("\n", $lines);
        $this->registerPlugin('shape');
    }

    /**
     * Renders the configured sides
     *
     * @param array $sides @see $sides
     *
     * @return string the generated shape sides
     * @throws InvalidConfigException
     */
    protected function renderSides($sides)
    {
        $lines = [];
        $lines[] = Html::beginTag('div', $this->sidesOptions);
        foreach($sides as $side) {
            if(!array_key_exists('content', $side)) {
                throw new InvalidConfigException("The 'content' option is required per sides");
            }
            $options = ArrayHelper::getValue($side, 'options', []);
            Ui::addCssClass($options, 'side');
            $active = ArrayHelper::getValue($side, 'active', false);
            if($active === true) {
                Ui::addCssClass($options, 'active');
            }
            $lines[] = Html::tag('div', $side['content'], $options);

        }
        $lines[] = Html::endTag('div');

        return implode("\n", $lines);
    }

}


<?php
/**
 * @link https://github.com/2amigos/yii2-semantic-ui
 * @copyright Copyright (c) 2013-2015 2amigOS! Consulting Group LLC
 * @license http://opensource.org/licenses/BSD-3-Clause
 */
namespace dosamigos\semantic\modules;

use dosamigos\semantic\collections\Menu;
use dosamigos\semantic\DosAmigosAsset;
use Yii;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;

/**
 * SideBar renders a Semantic UI sidebar
 *
 * For example
 *
 * ```php
 * echo SideBar::widget([
 *  'position' => 'left',
 *  'toggleButton' => [
 *      'style' => 'top:54px'
 *  ],
 *  'options' => [
 *      // 'class' => 'icon'
 *  ],
 * 'items' => [
 *      [
 *          'label' => 'Topics',
 *          'encode' => false
 *      ],
 *      [
 *          'label' => 'Elements',
 *          'encode' => false,
 *          'items' => [
 *              [
 *                  'label' => 'Topics',
 *                  'encode' => false
 *              ],
 *              [
 *                  'label' => 'Topics',
 *                  'encode' => false
 *              ],
 *          ]
 *      ]
 *  ]
 * ]);
 *
 * ``
 *
 * @see http://semantic-ui.com/modules/sidebar.html
 * @author Antonio Ramirez <amigo.cobos@gmail.com>
 * @link http://www.ramirezcobos.com/
 * @link http://www.2amigos.us/
 * @package dosamigos\semantic\modules
 */
class SideBar extends Menu
{
    const POS_TOP = 'top';
    const POS_BOTTOM = 'bottom';
    const POS_LEFT = 'left';
    const POS_RIGHT = 'right';
    const POS_DEFAULT = '';

    /**
     * @var string where to position the sidebar menu
     */
    public $position = self::POS_DEFAULT;
    /**
     * @var array the options for rendering the toggle button tag.
     * The toggle button is used to toggle the visibility of the modal window.
     * If this property is false, no toggle button will be rendered.
     *
     * The following special options are supported:
     *
     * - tag: string, the tag name of the button. Defaults to 'button'.
     * - label: string, the label of the button. Defaults to 'Show'.
     *
     * The rest of the options will be rendered as the HTML attributes of the button tag.
     */
    public $toggleButton = [];

    /**
     * @inheritdoc
     */
    public function init()
    {
        Html::addCssClass($this->options, $this->position);
        Html::addCssClass($this->options, 'sidebar');
        Html::addCssClass($this->options, 'vertical');
        parent::init();
    }

    /**
     * @inheritdoc
     */
    public function run()
    {
        parent::run();
        echo $this->renderToggleButton();
        $this->registerPlugin('sidebar');
    }

    /**
     * Generates the toggle button. The one that 'on-click', shows the sidebar.
     *
     * @return null|string the generated toggle button
     */
    public function renderToggleButton()
    {
        if ($this->toggleButton !== false) {
            $tag = ArrayHelper::remove($this->toggleButton, 'tag', 'div');
            $label = ArrayHelper::remove($this->toggleButton, 'label', Html::tag('i', '', ['class' => 'content icon']));

            Html::addCssClass($this->toggleButton, 'ui');
            Html::addCssClass($this->toggleButton, 'launch-sidebar icon');
            Html::addCssClass($this->toggleButton, 'button');
            Html::addCssClass($this->toggleButton, 'fixed');
            Html::addCssClass($this->toggleButton, 'attached');
            if ($this->position === static::POS_LEFT) {
                $position = static::POS_RIGHT;
            } else {
                $position = static::POS_LEFT;
            }
            Html::addCssClass($this->toggleButton, $position);
            $view = $this->getView();
            DosAmigosAsset::register($view);
            $view->registerJs('dosamigos.semantic.init();');
            return Html::tag($tag, $label, $this->toggleButton);
        } else {
            return null;
        }
    }
}


<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */
namespace dosamigos\semantic\collections;

use dosamigos\semantic\modules\Dropdown;
use Yii;
use dosamigos\semantic\Widget;
use yii\base\InvalidConfigException;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;

/**
 * Menu renders a Menu collection.
 *
 * For example
 *
 * ```php
 * echo Menu::widget([
 *  'items' => [
 *      Html::tag('div', 'Cat University', ['class' => 'header item']),
 *      [ 'label' => 'Menu A', 'url' => ['/menu-a']],
 *      [ 'label' => 'Menu B', 'url' => ['/menu-b']],
 *      [ 'label' => 'Only label'],
 *      [
 *          'label' => 'Menu C',
 *          'options' => [ 'class' => 'right' ],
 *          'items' => [
 *              [ 'label' => 'Menu C-A', 'url' => ['/menu-ca']],
 *              [ 'label' => 'Menu C-B', 'url' => ['/menu-cb']],
 *              [ 'label' => 'Only label' ],
 *          ]
 *      ],
 *  ]
 * ]);
 * ```
 *
 * @author Antonio Ramirez <amigo.cobos@gmail.com>
 * @link http://www.ramirezcobos.com/
 * @link http://www.2amigos.us/
 * @package dosamigos\semantic\collections
 */
class Menu extends Widget
{
    /**
     * @var array list of items in the nav widget. Each array element represents a single
     * menu item which can be either a string or an array with the following structure:
     *
     * - label: string, required, the nav item label.
     * - url: optional, the item's URL. Defaults to "#".
     * - visible: boolean, optional, whether this menu item is visible. Defaults to true.
     * - linkOptions: array, optional, the HTML attributes of the item's link.
     * - options: array, optional, the HTML attributes of the item container.
     * - active: boolean, optional, whether the item should be on active state or not.
     * - items: array|string, optional, the configuration array for creating a [[Dropdown]] widget,
     *   or a string representing the dropdown menu. Note that Bootstrap does not support sub-dropdown menus.
     *
     * If a menu item is a string, it will be rendered directly without HTML encoding.
     */
    public $items = [];
    /**
     * @var boolean whether the nav items labels should be HTML-encoded.
     */
    public $encodeLabels = true;
    /**
     * @var boolean whether to automatically activate items according to whether their route setting
     * matches the currently requested route.
     * @see isItemActive
     */
    public $activateItems = true;
    /**
     * @var boolean whether to activate parent menu items when one of the corresponding child menu items is active.
     */
    public $activateParents = false;
    /**
     * @var string the route used to determine if a menu item is active or not.
     * If not set, it will use the route of the current request.
     * @see params
     * @see isItemActive
     */
    public $route;
    /**
     * @var array the parameters used to determine if a menu item is active or not.
     * If not set, it will use `$_GET`.
     * @see route
     * @see isItemActive
     */
    public $params;

    /**
     * @inheritdoc
     */
    public function init()
    {
        parent::init();
        if ($this->route === null && Yii::$app->controller !== null) {
            $this->route = Yii::$app->controller->getRoute();
        }
        if ($this->params === null) {
            $this->params = Yii::$app->request->getQueryParams();
        }
        Html::addCssClass($this->options, 'menu');
    }

    /**
     * @inheritdoc
     */
    public function run()
    {
        echo Html::beginTag('div', $this->options);
        echo $this->renderItems($this->items);
        echo Html::endTag('div');
    }

    /**
     * Renders widget items.
     *
     * @param array $menuItems
     *
     * @return string
     * @throws InvalidConfigException
     */
    public function renderItems($menuItems)
    {
        $items = [];
        foreach ($menuItems as $i => $item) {
            if (isset($item['visible']) && !$item['visible']) {
                unset($items[$i]);
                continue;
            }
            $items[] = $this->renderItem($item);
        }
        return implode("\n", $items);
    }

    /**
     * Renders a widget's item.
     *
     * @param string|array $item the item to render.
     *
     * @return string the rendering result.
     * @throws InvalidConfigException
     */
    public function renderItem($item)
    {
        if (is_string($item)) {
            return $item;
        }
        if (!isset($item['label'])) {
            throw new InvalidConfigException("The 'label' option is required.");
        }
        $options = ArrayHelper::getValue($item, 'options', []);

        $label = $this->getLabel($item);
        $url = ArrayHelper::getValue($item, 'url', '#');

        if (isset($item['active'])) {
            $active = ArrayHelper::remove($item, 'active', false);
        } else {
            $active = $this->isItemActive($item);
        }

        if ($this->activateItems && $active) {
            Html::addCssClass($options, 'active');
        }
        Html::addCssClass($options, 'item');

        $items = ArrayHelper::getValue($item, 'items');
        if ($items !== null) {
            return Dropdown::widget(
                [
                    'encodeText' => false,
                    'text' => $label,
                    'items' => $items,
                    'options' => $options
                ]
            );
        } else {
            return Html::a($label, $url, $options);
        }
    }

    /**
     * Renders the given items as a dropdown.
     * This method is called to create sub-menus.
     *
     * @param array $items the given items. Please refer to [[Dropdown::items]] for the array structure.
     * @param array $parentItem the parent item information. Please refer to [[items]] for the structure of this array.
     *
     * @return string the rendering result.
     */
    protected function renderMenu($items, $parentItem)
    {
        $options = ArrayHelper::getValue($parentItem, 'options');
        $label = $this->getLabel($parentItem);
        $items = Html::tag('div', $this->renderItems($items), ['class' => 'menu']);
        Html::addCssClass($options, 'ui');
        Html::addCssClass($options, 'header');
        return
            Html::tag(
                'div',
                Html::tag('div', $label, $options) . $items,
                ['class' => 'item']
            );
    }

    /**
     * Returns the label
     *
     * @param array $item the item configuration
     *
     * @return string the label
     */
    protected function getLabel($item)
    {
        $encodeLabel = isset($item['encode']) ? $item['encode'] : $this->encodeLabels;
        return $encodeLabel ? Html::encode($item['label']) : $item['label'];
    }

    /**
     * Check to see if a child item is active optionally activating the parent.
     *
     * @param array $items @see items
     * @param boolean $active should the parent be active too
     *
     * @return array @see items
     */
    protected function isChildActive($items, &$active)
    {
        foreach ($items as $i => $child) {
            if (ArrayHelper::remove($items[$i], 'active', false) || $this->isItemActive($child)) {
                Html::addCssClass($items[$i]['options'], 'active');
                if ($this->activateParents) {
                    $active = true;
                }
            }
        }
        return $items;
    }

    /**
     * Checks whether a menu item is active.
     * This is done by checking if [[route]] and [[params]] match that specified in the `url` option of the menu item.
     * When the `url` option of a menu item is specified in terms of an array, its first element is treated
     * as the route for the item and the rest of the elements are the associated parameters.
     * Only when its route and parameters match [[route]] and [[params]], respectively, will a menu item
     * be considered active.
     *
     * @param array $item the menu item to be checked
     *
     * @return boolean whether the menu item is active
     */
    protected function isItemActive($item)
    {
        if (isset($item['url']) && is_array($item['url']) && isset($item['url'][0])) {
            $route = $item['url'][0];
            if ($route[0] !== '/' && Yii::$app->controller) {
                $route = Yii::$app->controller->module->getUniqueId() . '/' . $route;
            }
            if (ltrim($route, '/') !== $this->route) {
                return false;
            }
            unset($item['url']['#']);
            if (count($item['url']) > 1) {
                foreach (array_splice($item['url'], 1) as $name => $value) {
                    if ($value !== null && (!isset($this->params[$name]) || $this->params[$name] != $value)) {
                        return false;
                    }
                }
            }
            return true;
        }
        return false;
    }
}


<?php
/**
 * @link https://github.com/2amigos/yii2-semantic-ui
 * @copyright Copyright (c) 2013-2015 2amigOS! Consulting Group LLC
 * @license http://opensource.org/licenses/BSD-3-Clause
 */
namespace dosamigos\semantic\modules;

use dosamigos\semantic\Widget;
use yii\base\InvalidConfigException;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;

/**
 * Dropdown renders a semantic ui dropdown module
 *
 * For example:
 *
 * ```php
 * echo Dropdown::widget([
 *  'text' => 'Shop',
 *  'items' => [
 *      '<div class="header">Categories</div>',
 *      [
 *          'label' => 'Clothing'
 *      ],
 *      '<div class="divider"></div>',
 *      '<div class="header">Order</div>',
 *      [
 *          'label' => 'Status',
 *          'url' => '#'
 *      ],
 *  ],
 * ]);
 *
 * ```
 *
 * @see http://semantic-ui.com/modules/dropdown.html
 * @author Antonio Ramirez <amigo.cobos@gmail.com>
 * @link http://www.ramirezcobos.com/
 * @link http://www.2amigos.us/
 * @package dosamigos\semantic\modules
 */
class Dropdown extends Widget
{
    /**
     * @var array the HTML attributes for the widget menu items container tag.
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
     */
    public $itemsOptions = [];
    /**
     * @var array list of menu items in the dropdown. Each array element can be either an HTML string,
     * or an array representing a single menu with the following structure:
     *
     * - label: string, required, the label of the item link
     * - url: string|array, optional, the url of the item link. This will be processed by [[Url::to()]].
     *   If not set, the item will be treated as a menu header when the item has no sub-menu.
     * - visible: boolean, optional, whether this menu item is visible. Defaults to true.
     * - linkOptions: array, optional, the HTML attributes of the item link.
     * - options: array, optional, the HTML attributes of the item.
     * - items: array, optional, the submenu items. The structure is the same as this property.
     *
     * To insert divider use `<div class="divider"></div>`.
     * To insert a header use `<div class="header">Text</div>`
     */
    public $items = [];
    /**
     * @var boolean whether the labels for header items should be HTML-encoded.
     */
    public $encodeItemLabels = true;
    /**
     * @var boolean whether the text of the dropdown should be HTML-encoded
     */
    public $encodeText = true;
    /**
     * @var string the text that will be displayed as the dropdown title.
     */
    public $text;
    /**
     * @var string displays the dropdown caret icon. Set to false if you do not want to show a dropdown caret icon.
     */
    public $icon = '<i class="dropdown icon"></i>';
    /**
     * @var bool whether to display the search in dropdown input
     */
    public $displaySearchInput = false;
    /**
     * @var array the HTML attributes of the search input as name-value pairs.
     */
    public $searchInputOptions = [];

    /**
     * Initializes the widget.
     * If you override this method, make sure you call the parent implementation first.
     */
    public function init()
    {
        parent::init();
        Html::addCssClass($this->options, 'dropdown');
        Html::addCssClass($this->itemsOptions, 'menu');
    }

    /**
     * Renders the widget.
     */
    public function run()
    {
        echo $this->renderDropdown();
        $this->registerPlugin('dropdown');
    }

    /**
     * Renders the dropdown
     *
     * @return string the generated dropdown module
     * @throws InvalidConfigException
     */
    protected function renderDropdown()
    {
        $lines = [];
        $lines[] = $this->encodeText ? Html::encode($this->text) : $this->text;
        if ($this->icon && is_string($this->icon)) {
            $lines[] = $this->icon;
        }
        $lines[] = $this->renderItems($this->items, $this->options, $this->displaySearchInput);
        return Html::tag('div', implode("\n", $lines), $this->options);
    }

    /**
     * Renders menu items.
     *
     * @param array $items the menu items to be rendered
     * @param array $options the container HTML attributes
     * @param bool $displaySearchInput whether to render the search input or not
     *
     * @return string the rendering result.
     * @throws InvalidConfigException if the label option is not specified in one of the items.
     */
    protected function renderItems($items, $options = [], $displaySearchInput = false)
    {
        $lines = [];
        if($displaySearchInput) {
            $lines[] = $this->renderSearchInput();
        }
        foreach ($items as $i => $item) {
            if (isset($item['visible']) && !$item['visible']) {
                unset($items[$i]);
                continue;
            }
            if (is_string($item)) {
                $lines[] = $item;
                continue;
            }
            if (!array_key_exists('label', $item)) {
                throw new InvalidConfigException("The 'label' option is required.");
            }
            $encodeLabel = isset($item['encode']) ? $item['encode'] : $this->encodeItemLabels;
            $label = $encodeLabel ? Html::encode($item['label']) : $item['label'];
            $itemOptions = ArrayHelper::getValue($item, 'options', []);
            $linkOptions = ArrayHelper::getValue($item, 'linkOptions', []);
            $linkOptions['tabindex'] = '-1';
            $url = array_key_exists('url', $item) ? $item['url'] : null;
            if (empty($item['items'])) {
                if ($url === null) {
                    $content = $label;
                } else {
                    $content = Html::a($label, $url, $linkOptions);
                }
            } else {
                $submenuOptions = $options;
                unset($submenuOptions['id']);
                $label = $url === null ? $label : Html::a($label, $url, $linkOptions);
                Html::addCssClass($itemOptions, 'text');
                $content =
                    Html::tag('i', '', ['class' => 'dropdown icon']) .
                    Html::tag('span', $label, $itemOptions) .
                    $this->renderItems($item['items'], $submenuOptions);
            }
            Html::addCssClass($itemOptions, 'item');
            $lines[] = Html::tag('div', $content, $itemOptions);
        }

        return Html::tag('div', implode("\n", $lines), $this->itemsOptions);

    }

    /**
     * Renders the search input
     *
     * @return string the generated search input
     */
    protected function renderSearchInput()
    {
        $lines = [];
        $lines[] = Html::beginTag('div', ['class' =>'ui icon search input']);
        $lines[] = Html::tag('i', '', ['class' => 'search icon']);
        $lines[] = Html::input('text', $this->getId() . '-search', '', $this->searchInputOptions);
        $lines[] = Html::endTag('div');
        $lines[] = Html::tag('div', '', ['class' => 'divider']);
        return implode("\n", $lines);
    }
}


<?php
/**
 * @link https://github.com/2amigos/yii2-semantic-ui
 * @copyright Copyright (c) 2013-2015 2amigOS! Consulting Group LLC
 * @license http://opensource.org/licenses/BSD-3-Clause
 */
namespace dosamigos\semantic\modules;

use dosamigos\semantic\Widget;
use yii\helpers\Html;

/**
 * Progress renders a progress semantic ui module
 *
 * @author Antonio Ramirez <amigo.cobos@gmail.com>
 * @link http://www.ramirezcobos.com/
 * @link http://www.2amigos.us/
 * @package dosamigos\semantic\modules
 */
class Progress extends Widget
{

    const SIZE_TINY = 'tiny';
    const SIZE_SMALL = 'small';
    const SIZE_DEFAULT = '';
    const SIZE_LARGE = 'large';
    const SIZE_BIG = 'big';

    /**
     * @var string the size of the rating. Can be [[SIZE_TINY]], [[SIZE_SMALL]], [[SIZE_DEFAULT]],
     * [[SIZE_LARGE], and [[SIZE_BIG]] or empty for default.
     */
    public $size = self::SIZE_DEFAULT;
    /**
     * @var string the progress label.
     */
    public $label;
    /**
     * @var bool whether to encode the label or not.
     */
    public $encodeLabel = true;
    /**
     * @var integer the amount of progress as a percentage. Set to null if you don't wish to display the percent number.
     */
    public $percent;
    /**
     * @var bool whether to display the percentage amount inside the bar or not
     */
    public $showPercent = true;
    /**
     * @var array the HTML attributes of the bar.
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
     */
    public $barOptions = [];

    /**
     * Initializes the widget.
     * If you override this method, make sure you call the parent implementation first.
     */
    public function init()
    {
        parent::init();
        if ($this->percent !== null) {
            $this->clientOptions['percent'] = $this->percent;
        }
        if (!empty($this->size)) {
            Html::addCssClass($this->options, $this->size);
        }
        Html::addCssClass($this->barOptions, 'bar');
        Html::addCssClass($this->options, 'progress');
    }

    /**
     * Renders the widget.
     */
    public function run()
    {
        echo Html::beginTag('div', $this->options) . "\n";
        echo $this->renderBar($this->label) . "\n";
        echo Html::endTag('div') . "\n";
        $this->registerPlugin('progress');
    }

    /**
     * Generates a bar
     *
     * @param string $label , optional, the label to display at the bar
     *
     * @return string the rendering result.
     */
    protected function renderBar($label = null)
    {

        $lines = [];
        $content = $this->showPercent ? Html::tag('div', '', ['class' => 'progress']) : '';
        $lines[] = Html::tag('div', $content, $this->barOptions);
        if ($this->label) {
            $label = $this->encodeLabel ? Html::encode($label) : $label;
            $lines[] = Html::tag('div', $label, ['class' => 'label']);
        }
        return implode("\n", $lines);
    }
}


<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */
namespace dosamigos\semantic;

use Yii;
use yii\helpers\Html;
use yii\helpers\Json;
use yii\web\JsExpression;

/**
 * Widget is the base class for all semantic ui widgets.
 *
 * @author Antonio Ramirez <amigo.cobos@gmail.com>
 * @link http://www.ramirezcobos.com/
 * @link http://www.2amigos.us/
 * @package dosamigos\semantic
 */
class Widget extends \yii\base\Widget
{
    /**
     * @var string whether to use a custom selector instead of the id of the widget.
     */
    public $selector;
    /**
     * @var array the HTML attributes for the widget container tag.
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
     */
    public $options = [];
    /**
     * @var array the options for the underlying Semantic UI JS plugin.
     * Please refer to the corresponding Semantic UI plugin Web page for possible options.
     * For example, [this page](http://semantic-ui.com/modules/modal.html#/settings) shows
     * how to use the "Modal" plugin and the supported options (e.g. "remote").
     */
    public $clientOptions = [];
    /**
     * @var array the event handlers for the underlying Semantic UI JS plugin.
     * Please refer to the corresponding Semantic UI plugin Web page for possible events.
     * For example, [this page](http://semantic-ui.com/modules/modal.html#/examples) shows
     * how to use the "Modal" plugin and the supported events (e.g. "onShow").
     */
    public $clientEvents = [];

    /**
     * Initializes the widget.
     * This method will register the semantic ui asset bundle and the translations. If you override this method,
     * make sure you call the parent implementation first.
     */
    public function init()
    {
        parent::init();

        Html::addCssClass($this->options, 'ui');

        if (!isset($this->options['id'])) {
            $this->options['id'] = $this->getId();
        }
        $this->registerTranslations();
    }

    /**
     * Registers the required translations of the widgets
     */
    public function registerTranslations()
    {
        $i18n = Yii::$app->i18n;
        $i18n->translations['dosamigos/semantic/*'] = [
            'class' => 'yii\i18n\PhpMessageSource',
            'basePath' => dirname(__FILE__) . '/messages',
        ];
    }

    /**
     * Registers a specific Semantic UI plugin and the related events
     *
     * @param string $name the name of the Semantic UI plugin
     */
    protected function registerPlugin($name)
    {
        $view = $this->getView();
        SemanticUiPluginAsset::register($view);
        $selector = $this->selector ? : '#' . $this->options['id'];
        if ($this->clientOptions !== false) {
            $options = empty($this->clientOptions) ? '' : Json::encode($this->clientOptions);
            $js = "jQuery('$selector').$name($options);";
            $view->registerJs($js);
        }
        if (!empty($this->clientEvents)) {
            $js = [];
            foreach ($this->clientEvents as $event => $handler) {
                $handler = $handler instanceof JsExpression ? $handler : new JsExpression($handler);
                $js[] = "jQuery('$selector').$name('setting', '$event', $handler);";
            }
            $view->registerJs(implode("\n", $js));
        }
    }
}


<?php
/**
 * @link https://github.com/2amigos/yii2-semantic-ui
 * @copyright Copyright (c) 2013-2015 2amigOS! Consulting Group LLC
 * @license http://opensource.org/licenses/BSD-3-Clause
 */
namespace dosamigos\semantic\modules;

use yii\base\InvalidConfigException;
use yii\helpers\Html;
use yii\widgets\InputWidget;
use Yii;

/**
 * Selection generates a semantic ui selection list
 * For example
 *
 * ```php
 * echo Selection::widget([
 *  'name' => 'test-selection',
 *  'items' => [
 *      'value1' => [ 'label' => 'Value 1' ],
 *      'value2' => [ 'label' => 'Value 2' ]
 *  ]
 * ]);
 * ```
 *
 * @see http://semantic-ui.com/collections/form.html#selection-dropdown
 * @author Antonio Ramirez <amigo.cobos@gmail.com>
 * @link http://www.ramirezcobos.com/
 * @link http://www.2amigos.us/
 * @package dosamigos\semantic\modules
 */
class Selection extends InputWidget
{
    /**
     * @var boolean whether the labels for header items should be HTML-encoded.
     */
    public $encodeItemLabels = true;
    /**
     * @var boolean whether the text of the dropdown should be HTML-encoded
     */
    public $encodeDefaultText = true;
    /**
     * @var string the default text to display
     */
    public $defaultText;
    /**
     * @var array the selection data items. The array keys are option values, and the array values
     * are the corresponding option labels.
     */
    public $items = [];
    /**
     * @var string|array upload route
     */
    public $url;
    /**
     * @var array the plugin options. For more information see the jQuery File Upload options documentation.
     * @see https://github.com/blueimp/jQuery-File-Upload/wiki/Options
     */
    public $clientOptions = [];
    /**
     * @var array the event handlers for the jQuery File Upload plugin.
     * Please refer to the jQuery File Upload plugin web page for possible options.
     * @see https://github.com/blueimp/jQuery-File-Upload/wiki/Options#callback-options
     */
    public $clientEvents = [];

    /**
     * Initializes the widget.
     * @throws \yii\base\InvalidConfigException
     */
    public function init()
    {
        parent::init();

        foreach ($this->items as $value => $item) {
            if (is_string($item)) {
                throw new InvalidConfigException("Items cannot be of type string.");
            }
            $item['options'] = ['value' => $value];
        }
        if ($this->hasModel()) {
            $value = Html::getAttributeValue($this->model, $this->attribute);
            if (!empty($value)) {
                $defaultText = $value;
            }
        } else {
            if (!empty($this->value)) {
                $defaultText = $this->value;
            }
        }
        if (empty($defaultText)) {
            $defaultText = Yii::t('dosamigos/semantic/selection', 'Select...');
        }
        $this->defaultText = $this->encodeDefaultText ? Html::encode($defaultText) : $defaultText;
        Html::addCssClass($this->options, 'selection');
    }

    /**
     * @inheritdoc
     */
    public function run()
    {
        $input = $this->hasModel()
            ? Html::activeHiddenInput($this->model, $this->attribute)
            : Html::hiddenInput($this->name, $this->value);

        $defaultText = $this->defaultText
            ? Html::tag('div', $this->defaultText, ['class' => 'default text'])
            : '';

        echo Dropdown::widget(
            [
                'id' => $this->getId(),
                'encodeText' => false,
                'encodeItemLabels' => $this->encodeItemLabels,
                'text' => $input . $defaultText,
                'items' => $this->items,
                'options' => $this->options,
                'clientOptions' => $this->clientOptions,
                'clientEvents' => $this->clientEvents
            ]
        );
    }
}


<?php
/**
 * @link https://github.com/2amigos/yii2-semantic-ui
 * @copyright Copyright (c) 2013-2015 2amigOS! Consulting Group LLC
 * @license http://opensource.org/licenses/BSD-3-Clause
 */
namespace dosamigos\semantic\modules;

use dosamigos\semantic\Widget;
use yii\base\InvalidConfigException;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;

/**
 * Accordion renders an accordion semantic ui module.
 *
 * For example:
 *
 * ```php
 * echo Accordion::widget([
 *      'items' => [
 *          [
 *              'label' => 'Clothing',
 *              'active' => true,
 *              'content' => 'This is the content for clothing'
 *          ],
 *          [
 *              'label' => 'Status',
 *              'content' => 'This is the content for status'
 *          ],
 *      ],
 *  ]);
 * ```
 *
 * @see http://semantic-ui.com/modules/accordion.html
 * @author Antonio Ramirez <amigo.cobos@gmail.com>
 * @link http://www.ramirezcobos.com/
 * @link http://www.2amigos.us/
 * @package dosamigos\semantic\modules
 */
class Accordion extends Widget
{
    /**
     * @var array list of groups in the collapse widget. Each array element represents a single
     * group with the following structure:
     *
     * - label: string, required, the group header label.
     * - active: boolean, optional, whether this item should be active
     * - encode: boolean, optional, whether this label should be HTML-encoded. This param will override
     *   global `$this->encodeLabels` param.
     * - content: string, required, the content (HTML) of the group
     * - options: array, optional, the HTML attributes of the group
     * - contentOptions: optional, the HTML attributes of the group's content
     *
     * ```
     */
    public $items = [];
    /**
     * @var boolean whether the labels for header items should be HTML-encoded.
     */
    public $encodeLabels = true;

    /**
     * Initializes the widget.
     */
    public function init()
    {
        parent::init();
        Html::addCssClass($this->options, 'accordion');
    }

    /**
     * Renders the widget.
     */
    public function run()
    {
        echo Html::beginTag('div', $this->options) . "\n";
        echo $this->renderItems() . "\n";
        echo Html::endTag('div') . "\n";
        $this->registerPlugin('accordion');
    }

    /**
     * Renders collapsible items as specified on [[items]].
     * @throws InvalidConfigException if label isn't specified
     * @return string the rendering result
     */
    public function renderItems()
    {
        $items = [];
        $index = 0;
        foreach ($this->items as $item) {
            if (!array_key_exists('label', $item)) {
                throw new InvalidConfigException("The 'label' option is required.");
            }
            $items[] = $this->renderItem($item, ++$index);
        }
        return implode("\n", $items);
    }

    /**
     * Renders a single collapsible item group
     *
     * @param array $item a single item from [[items]]
     * @param integer $index the item index as each item group content must have an id
     *
     * @return string the rendering result
     * @throws InvalidConfigException
     */
    public function renderItem($item, $index)
    {
        if (array_key_exists('content', $item)) {
            $label = ArrayHelper::getValue($item, 'label');
            $options = ArrayHelper::getValue($item, 'options', []);
            $options['id'] = $this->options['id'] . '-accordion' . $index;
            $contentOptions = ArrayHelper::getValue($item, 'contentOptions', []);

            if (ArrayHelper::getValue($item, 'active')) {
                Html::addCssClass($options, 'active');
                Html::addCssClass($contentOptions, 'active');
            }

            Html::addCssClass($options, 'title');
            Html::addCssClass($contentOptions, 'content');

            $encodeLabel = isset($item['encode']) ? $item['encode'] : $this->encodeLabels;
            if ($encodeLabel) {
                $label = Html::encode($label);
            }
            $title = Html::tag('i', '', ['class' => 'dropdown icon']) . $label;
        } else {
            throw new InvalidConfigException('The "content" option is required.');
        }
        $group = [];
        $group[] = Html::tag('div', $title, $options) . "\n";
        $group[] = Html::tag('div', $item['content'], $contentOptions) . "\n";
        return implode("\n", $group);
    }
}


<?php
/**
 * @link https://github.com/2amigos/yii2-semantic-ui
 * @copyright Copyright (c) 2013-2015 2amigOS! Consulting Group LLC
 * @license http://opensource.org/licenses/BSD-3-Clause
 */
namespace dosamigos\semantic\modules;

use dosamigos\semantic\DosAmigosAsset;
use dosamigos\semantic\Widget;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;

/**
 * Modal renders a modal window that can be toggled by clicking on a button.
 *
 * The following example will show the content enclosed between the [[begin()]]
 * and [[end()]] calls within the modal window:
 *
 * ```php
 * Modal::begin([
 *     'header' => '<h2>Hello world</h2>',
 *     'toggleButton' => ['label' => 'click me'],
 * ]);
 *
 * echo 'Say hello...';
 *
 * Modal::end();
 * ```
 *
 * ```php
 * Modal::begin([
 *  'toggleButton' => ['label' => 'Show modal'],
 *  'size' => 'fullscreen',
 *  'type' => 'basic',
 *  'footer' => '<div class="ui black negative button">Nope</div>' +
 *             '<div class="ui positive right labeled icon button">Yep, that\'s me<i class="checkmark icon"></i></div>',
 *  'clientEvents' => [
 *      'onDeny' => 'function(){ console.log("denied");}'
 *  ]
 * ]);
 * ```
 *
 * @author Antonio Ramirez <amigo.cobos@gmail.com>
 * @link http://www.ramirezcobos.com/
 * @link http://www.2amigos.us/
 * @package dosamigos\semantic\modules
 */
class Modal extends Widget
{

    const TYPE_BASIC = "basic";
    const TYPE_STANDARD = "";

    const SIZE_FULLSCREEN = "fullscreen";
    const SIZE_SMALL = "small";
    const SIZE_LARGE = "large";

    /**
     * @var string the header content in the modal window.
     */
    public $header;
    /**
     * @var string additional header options
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
     */
    public $headerOptions;
    /**
     * @var string the footer content in the modal window.
     */
    public $footer;
    /**
     * @var string additional footer options
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
     */
    public $footerOptions;
    /**
     * @var string the modal size. Can be [[SIZE_LARGE]], [[SIZE_SMALL]], and [[SIZE_FULLSCREEN]]or empty for default.
     */
    public $size;
    /**
     * @var string the modal type. Can be [[TYPE_BASIC]],  and [[TYPE_STANDARD]] or empty for default.
     */
    public $type;
    /**
     * @var array|false the options for rendering the close button tag.
     * The close button is displayed in the header of the modal window. Clicking
     * on the button will hide the modal window. If this is false, no close button will be rendered.
     *
     * The following special options are supported:
     *
     * - tag: string, the tag name of the button. Defaults to 'button'.
     * - label: string, the label of the button. Defaults to '×'.
     *
     * The rest of the options will be rendered as the HTML attributes of the button tag.
     * Please refer to the [Modal plugin help](http://semantic-ui.com/modules/modal.html)
     * for the supported HTML attributes.
     */
    public $closeButton = [];
    /**
     * @var array the options for rendering the toggle button tag.
     * The toggle button is used to toggle the visibility of the modal window.
     * If this property is false, no toggle button will be rendered.
     *
     * The following special options are supported:
     *
     * - tag: string, the tag name of the button. Defaults to 'button'.
     * - label: string, the label of the button. Defaults to 'Show'.
     *
     * The rest of the options will be rendered as the HTML attributes of the button tag.
     * Please refer to the [Modal plugin help](http://semantic-ui.com/modules/modal.html)
     * for the supported HTML attributes.
     */
    public $toggleButton = false;

    /**
     * Initializes the widget.
     */
    public function init()
    {
        parent::init();
        $this->initOptions();
        echo $this->renderToggleButton() . "\n";
        echo Html::beginTag('div', $this->options) . "\n";
        echo $this->renderHeader() . "\n";
        echo $this->renderBodyBegin() . "\n";
    }

    /**
     * Renders the widget.
     */
    public function run()
    {
        echo "\n" . $this->renderBodyEnd();
        echo "\n" . $this->renderFooter();
        echo "\n" . Html::endTag('div');
        $this->registerPlugin('modal');
    }

    /**
     * Renders the header HTML markup of the modal
     * @return string the rendering result
     */
    protected function renderHeader()
    {
        $button = $this->renderCloseButton();

        if ($this->header !== null) {
            Html::addCssClass($this->headerOptions, 'header');
            $this->header = Html::tag('div', "\n" . $this->header . "\n", $this->headerOptions);
        }

        if ($button !== null || $this->header !== null) {
            return $button . "\n" . $this->header;
        } else {
            return null;
        }

    }

    /**
     * Renders the opening tag of the modal body.
     * @return string the rendering result
     */
    protected function renderBodyBegin()
    {
        return Html::beginTag('div', ['class' => 'content']);
    }

    /**
     * Renders the closing tag of the modal body.
     * @return string the rendering result
     */
    protected function renderBodyEnd()
    {
        return Html::endTag('div');
    }

    /**
     * Renders the HTML markup for the footer of the modal
     * @return string the rendering result
     */
    protected function renderFooter()
    {
        if ($this->footer !== null) {
            Html::addCssClass($this->footerOptions, 'actions');
            return Html::tag('div', "\n" . $this->footer . "\n", $this->footerOptions);
        } else {
            return null;
        }
    }

    /**
     * Renders the toggle button.
     * @return string the rendering result
     */
    protected function renderToggleButton()
    {
        if ($this->toggleButton !== false) {
            $tag = ArrayHelper::remove($this->toggleButton, 'tag', 'div');
            $label = ArrayHelper::remove($this->toggleButton, 'label', 'Show');
            if ($tag === 'button' && !isset($this->toggleButton['type'])) {
                $this->toggleButton['type'] = 'button';
            }
            if ($tag === 'div') {
                Html::addCssClass($this->toggleButton, 'ui');
                Html::addCssClass($this->toggleButton, 'button');
            }
            $view = $this->getView();
            DosAmigosAsset::register($view);
            $view->registerJs('dosamigos.semantic.init();');

            return Html::tag($tag, $label, $this->toggleButton);
        } else {
            return null;
        }
    }

    /**
     * Renders the close button.
     * @return string the rendering result
     */
    protected function renderCloseButton()
    {
        if ($this->closeButton !== false) {
            return Html::tag('i', '', $this->closeButton);
        } else {
            return null;
        }
    }

    /**
     * Initializes the widget options.
     * This method sets the default values for various options.
     */
    protected function initOptions()
    {
        $this->options = array_merge(
            [
                'tabindex' => -1,
            ],
            $this->options
        );

        Html::addCssClass($this->options, 'modal');
        if ($this->size !== null) {
            Html::addCssClass($this->options, $this->size);
        }
        if ($this->type !== null) {
            Html::addCssClass($this->options, $this->type);
        }

        if ($this->closeButton !== false) {
            Html::addCssClass($this->closeButton, 'icon');
            Html::addCssClass($this->closeButton, 'close');
        }
        if ($this->toggleButton !== false && is_array($this->toggleButton)) {
            $this->toggleButton = array_merge(
                [
                    'data-toggle' => 'semantic-modal',
                ],
                $this->toggleButton
            );
            if (!isset($this->toggleButton['data-target']) && !isset($this->toggleButton['href'])) {
                $this->toggleButton['data-target'] = '#' . $this->options['id'];
            }
        }
    }
}


<?php
/**
 * @link https://github.com/2amigos/yii2-semantic-ui
 * @copyright Copyright (c) 2013-2015 2amigOS! Consulting Group LLC
 * @license http://opensource.org/licenses/BSD-3-Clause
 */
namespace dosamigos\semantic\modules;

use dosamigos\semantic\helpers\Ui;
use dosamigos\semantic\InputWidget;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;

/**
 * Checkbox renders a semantic ui checkbox
 *
 * For example:
 *
 * ```php
 * echo Checkbox::widget([
 *  'label' => 'Make my profile visible',
 *  'name' => 'terms',
 *  'options' => [
 *      'class' => 'slider'
 *  ]
 * ]);
 *
 * ```
 *
 * @see http://semantic-ui.com/modules/checkbox.html
 * @author Antonio Ramirez <amigo.cobos@gmail.com>
 * @link http://www.ramirezcobos.com/
 * @link http://www.2amigos.us/
 * @package dosamigos\semantic\modules
 */
class Checkbox extends InputWidget
{
    /**
     * @var string the checkbox label
     */
    public $label;
    /**
     * @var bool whether to encode the label or not. Defaults to true.
     */
    public $encodeLabel = true;
    /**
     * @var bool whether to display the checkbox on its "checked" state.
     */
    public $checked = false;
    /**
     * @var array the label tag HTML attributes as name-value pairs.
     */
    public $labelOptions = [];
    /**
     * @var array the wrapper tag HTML attributes as name-value pairs.
     */
    public $wrapperOptions = [];

    /**
     * @inheritdoc
     * @throws \yii\base\InvalidConfigException
     */
    public function init()
    {
        parent::init();
        if ($this->label === null) {
            $this->label = $this->hasModel()
                ? $this->model->getAttributeLabel($this->attribute)
                : ArrayHelper::getValue($this->options, 'label', false);
        }
        Html::removeCssClass($this->options, 'ui');
        Ui::addCssClasses($this->wrapperOptions, ['ui', 'checkbox']);
        $this->wrapperOptions['id'] = $this->options['id'] . '-wrapper';
        $this->selector = $this->selector ?: '#' . $this->wrapperOptions['id'];
    }

    /**
     * @inheritdoc
     */
    public function run()
    {
        $lines = [];
        $lines[] = $this->renderInput();

        if ($this->label !== false) {
            $lines[] = $this->renderLabel();
        }

        echo Html::tag('div', implode("\n", $lines), $this->wrapperOptions);
        $this->registerPlugin('checkbox');
    }

    /**
     * Renders the checkbox input
     *
     * @return string the generated checkbox input
     */
    protected function renderInput()
    {
        return $this->hasModel()
            ? Html::activeCheckbox($this->model, $this->attribute, $this->options)
            : Html::checkbox($this->name, $this->checked, $this->options);
    }

    /**
     * Renders checkbox label
     *
     * @return string the generated label
     */
    protected function renderLabel()
    {
        $label = $this->encodeLabel ? Html::encode($this->label) : $this->label;
        return $this->hasModel()
            ? Html::activeLabel($this->model, $this->attribute, $this->labelOptions)
            : Html::label($label, $this->getId(), $this->labelOptions);
    }
}