<?php

/*
 * This file is part of the Ivory Google Map package.
 *
 * (c) Eric GELOEN <geloen.eric@gmail.com>
 *
 * For the full copyright and license information, please read the LICENSE
 * file that was distributed with this source code.
 */

namespace Ivory\GoogleMap\Overlays;

use Ivory\GoogleMap\Assets\AbstractOptionsAsset;
use Ivory\GoogleMap\Base\Coordinate;
use Ivory\GoogleMap\Exception\OverlayException;

/**
 * Marker which describes a google map marker.
 *
 * @see http://code.google.com/apis/maps/documentation/javascript/reference.html#Marker
 * @author GeLo <geloen.eric@gmail.com>
 */
class Marker extends AbstractOptionsAsset implements ExtendableInterface
{
    /** @var \Ivory\GoogleMap\Base\Coordinate */
    protected $position;

    /** @var string */
    protected $animation;

    /** @var \Ivory\GoogleMap\Overlays\MarkerImage */
    protected $icon;

    /** @var \Ivory\GoogleMap\Overlays\MarkerImage */
    protected $shadow;

    /** @var \Ivory\GoogleMap\Overlays\MarkerShape */
    protected $shape;

    /** @var \Ivory\GoogleMap\Overlays\InfoWindow */
    protected $infoWindow;

    /**
     * Creates a marker.
     *
     * @param \Ivory\GoogleMap\Base\Coordinate      $position   The marker position.
     * @param string                                $animation  The marker animation.
     * @param \Ivory\GoogleMap\Overlays\MarkerImage $icon       The marker icon.
     * @param \Ivory\GoogleMap\Overlays\MarkerImage $shadow     The marker shadow.
     * @param \Ivory\GoogleMap\Overlays\MarkerShape $shape      The marker shape.
     * @param \Ivory\GoogleMap\Overlays\InfoWindow  $infoWindow The marker info window.
     */
    public function __construct(
        Coordinate $position = null,
        $animation = null,
        MarkerImage $icon = null,
        MarkerImage $shadow = null,
        MarkerShape $shape = null,
        InfoWindow $infoWindow = null
    ) {
        parent::__construct();

        $this->setPrefixJavascriptVariable('marker_');

        if ($position === null) {
            $position = new Coordinate();
        }

        $this->setPosition($position);

        if ($animation !== null) {
            $this->setAnimation($animation);
        }

        if ($icon !== null) {
            $this->setIcon($icon);
        }

        if ($shadow !== null) {
            $this->setShadow($shadow);
        }

        if ($shape !== null) {
            $this->setShape($shape);
        }

        if ($infoWindow !== null) {
            $this->setInfoWindow($infoWindow);
        }
    }

    /**
     * Gets the marker position.
     *
     * @return \Ivory\GoogleMap\Base\Coordinate The marker position.
     */
    public function getPosition()
    {
        return $this->position;
    }

    /**
     * Sets the marker position.
     *
     * Available prototypes:
     * - function setPosition(Ivory\GoogleMap\Base\Coordinate $position = null)
     * - function setPosition(double $latitude, double $longitude, boolean $noWrap = true)
     *
     * @throws \Ivory\GoogleMap\Exception\OverlayException If the position is not valid.
     */
    public function setPosition()
    {
        $args = func_get_args();

        if (isset($args[0]) && ($args[0] instanceof Coordinate)) {
            $this->position = $args[0];
        } elseif ((isset($args[0]) && is_numeric($args[0])) && (isset($args[1]) && is_numeric($args[1]))) {
            $this->position->setLatitude($args[0]);
            $this->position->setLongitude($args[1]);

            if (isset($args[2]) && is_bool($args[2])) {
                $this->position->setNoWrap($args[2]);
            }
        } elseif (!isset($args[0])) {
            $this->position = null;
        } else {
            throw OverlayException::invalidMarkerPosition();
        }
    }

    /**
     * Checks if the marker has an animation.
     *
     * @return boolean TRUE if the marker has an animation else FALSE.
     */
    public function hasAnimation()
    {
        return $this->animation !== null;
    }

    /**
     * Gets the marker animation.
     *
     * @return string The marker animation.
     */
    public function getAnimation()
    {
        return $this->animation;
    }

    /**
     * Sets the marker animation.
     *
     * @param string $animation The marker animation.
     *
     * @throws \Ivory\GoogleMap\Exception\OverlayException If the animation is not valid.
     */
    public function setAnimation($animation = null)
    {
        if (!in_array($animation, Animation::getAnimations()) && ($animation !== null)) {
            throw OverlayException::invalidMarkerAnimation();
        }

        $this->animation = $animation;
    }

    /**
     * Checks if the marker has an icon.
     *
     * @return boolean TRUE if the marker has an icon else FALSE.
     */
    public function hasIcon()
    {
        return $this->icon !== null;
    }

    /**
     * Gets the marker icon.
     *
     * @return \Ivory\GoogleMap\Overlays\MarkerImage The marker image.
     */
    public function getIcon()
    {
        return $this->icon;
    }

    /**
     * Sets the marker icon.
     *
     * Available prototypes:
     *  - function setIcon(Ivory\GoogleMap\Overlays\MarkerImage $markerImage = null)
     *  - function setIcon(string $url = null)
     *
     * @throws \Ivory\GoogleMap\Exception\OverlayException If the icon is not valid.
     */
    public function setIcon()
    {
        $args = func_get_args();

        if (isset($args[0]) && ($args[0] instanceof MarkerImage)) {
            if ($args[0]->getUrl() === null) {
                throw OverlayException::invalidMarkerIconUrl();
            }

            $this->icon = $args[0];
        } elseif (isset($args[0]) && is_string($args[0])) {
            if ($this->icon === null) {
                $this->icon = new MarkerImage();
            }

            $this->icon->setUrl($args[0]);
        } elseif (!isset($args[0])) {
            $this->icon = null;
        } else {
            throw OverlayException::invalidMarkerIcon();
        }
    }

    /**
     * Checks if the marker has a shadow.
     *
     * @return boolean TRUE if the marker has a shadow else FALSE.
     */
    public function hasShadow()
    {
        return $this->shadow !== null;
    }

    /**
     * Gets the marker shadow.
     *
     * @return \Ivory\GoogleMap\Overlays\MarkerImage The marker shadow.
     */
    public function getShadow()
    {
        return $this->shadow;
    }

    /**
     * Sets the marker shadow.
     *
     * Available prototypes:
     *  - function setShadow(Ivory\GoogleMap\Overlays\MarkerImage $markerImage = null)
     *  - function setShadow(string $url = null)
     *
     * @throws \Ivory\GoogleMap\Exception\OverlayException If the marker shadow is not valid.
     */
    public function setShadow()
    {
        $args = func_get_args();

        if (isset($args[0]) && ($args[0] instanceof MarkerImage)) {
            if ($args[0]->getUrl() === null) {
                throw OverlayException::invalidMarkerShadowUrl();
            }

            $this->shadow = $args[0];
        } elseif (isset($args[0]) && is_string($args[0])) {
            if ($this->shadow === null) {
                $this->shadow = new MarkerImage();
            }

            $this->shadow->setUrl($args[0]);
        } elseif (!isset($args[0])) {
            $this->shadow = null;
        } else {
            throw OverlayException::invalidMarkerShadow();
        }
    }

    /**
     * Checks if the marker has a shape.
     *
     * @return boolean TRUE if the marker has a shape else FALSE.
     */
    public function hasShape()
    {
        return $this->shape !== null;
    }

    /**
     * Gets the marker shape.
     *
     * @return \Ivory\GoogleMap\Overlays\MarkerShape The marker shape.
     */
    public function getShape()
    {
        return $this->shape;
    }

    /**
     * Sets the marker shape.
     *
     * Available prototypes:
     *  - function setShape(Ivory\GoogleMap\Overlays\MarkerShape $shape = null)
     *  - function setShape(string $type, array $coordinates)
     *
     * @throws \Ivory\GoogleMap\Exception\OverlayException If the shape is not valid.
     */
    public function setShape()
    {
        $args = func_get_args();

        if (isset($args[0]) && ($args[0] instanceof MarkerShape)) {
            if (!$args[0]->hasCoordinates()) {
                throw OverlayException::invalidMarkerShapeCoordinates();
            }

            $this->shape = $args[0];
        } elseif ((isset($args[0]) && is_string($args[0])) && (isset($args[1]) && is_array($args[1]))) {
            if ($this->shape === null) {
                $this->shape = new MarkerShape();
            }

            $this->shape->setType($args[0]);
            $this->shape->setCoordinates($args[1]);
        } elseif (!isset($args[0])) {
            $this->shape = null;
        } else {
            throw OverlayException::invalidMarkerShape();
        }
    }

    /**
     * Check if the marker has an info window.
     *
     * @return boolean TRUE if the marker has an info window else FALSE.
     */
    public function hasInfoWindow()
    {
        return $this->infoWindow !== null;
    }

    /**
     * Gets the info window.
     *
     * @return \Ivory\GoogleMap\Overlays\InfoWindow The info window.
     */
    public function getInfoWindow()
    {
        return $this->infoWindow;
    }

    /**
     * Sets the info window.
     *
     * @param \Ivory\GoogleMap\Overlays\InfoWindow $infoWindow The info window.
     */
    public function setInfoWindow(InfoWindow $infoWindow)
    {
        $this->infoWindow = $infoWindow;
    }
}


<?php
/**
 * Markdown utilities.
 *
 * @author @jaswrks
 * @copyright WebSharks™
 */
declare(strict_types=1);
namespace WebSharks\Core\Classes\Core\Utils;

use WebSharks\Core\Classes;
use WebSharks\Core\Interfaces;
use WebSharks\Core\Traits;
#
use WebSharks\Core\Classes\Core\Error;
use WebSharks\Core\Classes\Core\Base\Exception;
#
use function assert as debug;
use function get_defined_vars as vars;
#
use Michelf\MarkdownExtra;
use Michelf\SmartyPants;

/**
 * Markdown utilities.
 *
 * @since 150424 Initial release.
 */
class Markdown extends Classes\Core\Base\Core
{
    /**
     * Header ID counter.
     *
     * @since 170623.50532 Enhancing headers.
     *
     * @type array Counter.
     */
    protected $header_id_counter = [];

    /**
     * A very simple markdown parser.
     *
     * @since 150424 Initial release.
     * @since 170211.63148 Removing `parsedown-extra`.
     * @deprecated 170131 Use `hard_wrap` instead of `breaks`.
     * @deprecated 170604 `flavor` no longer available.
     *
     * @param mixed $value Any input value.
     * @param array $args  Any additional behavioral args.
     *
     * @return string|array|object Html markup value(s).
     */
    public function __invoke($value, array $args = [])
    {
        if (is_array($value) || is_object($value)) {
            foreach ($value as $_key => &$_value) {
                $_value = $this->__invoke($_value, $args);
            } //unset($_key, $_value);
            return $value;
        }
        if (!($string = $this->c::mbTrim((string) $value))) {
            return $string; // Nothing to do.
        }
        $default_args = [ // Defaults.
            'cache'               => false,
            'cache_expires_after' => '30 days',

            'code_attr_on_pre'  => false,
            'code_class_prefix' => 'lang-',

            'header_id_func'    => null,
            'fn_id_prefix'      => '',

            'no_p'      => false,
            'hard_wrap' => true,
            'breaks'    => true,

            'anchorize'   => false,
            'anchor_rels' => [],

            'smartypants'   => true,
        ];
        $args = array_merge($default_args, $args);
        $args = array_intersect_key($args, $default_args);

        $cache               = (bool) $args['cache'];
        $cache_expires_after = (string) $args['cache_expires_after'];

        $code_attr_on_pre  = (bool) $args['code_attr_on_pre'];
        $code_class_prefix = (string) $args['code_class_prefix'];

        $header_id_func = $args['header_id_func'] ?: [$this, 'headerIdCallback'];
        $fn_id_prefix   = (string) $args['fn_id_prefix'];

        $no_p      = (bool) $args['no_p'];
        $hard_wrap = (bool) ($args['hard_wrap'] || $args['breaks']);

        $anchorize   = (bool) $args['anchorize'];
        $anchor_rels = (array) $args['anchor_rels'];

        $smartypants = (bool) $args['smartypants'];

        if ($cache) { // Cache?
            $cache_args = $args;
            // Cannot serialize closures.
            unset($cache_args['header_id_func']);

            $cache_sha1          = sha1($string.$post_id.serialize($cache_args));
            $cache_sha1_shard_id = $this->c::sha1ModShardId($cache_sha1, true);

            $cache_dir             = $this->App->Config->©fs_paths['©cache_dir'].'/markdown/'.$cache_sha1_shard_id;
            $cache_dir_permissions = $this->App->Config->©fs_permissions['©transient_dirs'];
            $cache_file            = $cache_dir.'/'.$cache_sha1.'.html';

            if (is_file($cache_file) && filemtime($cache_file) >= strtotime('-'.$cache_expires_after)) {
                return (string) file_get_contents($cache_file);
            } // Use the already-cached HTML markup.
        }
        if (!($MarkdownExtra = &$this->cacheKey(__FUNCTION__.'extra'))) {
            $MarkdownExtra = new MarkdownExtra(); // New instance.
        }
        if (!($SmartyPants = &$this->cacheKey(__FUNCTION__, 'smartypants'))) {
            $SmartyPants               = new SmartyPants(2); // Match JS libs.
            $SmartyPants->tags_to_skip = 'pre|code|samp|kbd|tt|math|script|style';
            $SmartyPants->decodeEntitiesInConfiguration(); // Use UTF-8 symbols.
        }
        $this->header_id_counter = []; // Reset counter.

        $MarkdownExtra->code_attr_on_pre  = $code_attr_on_pre;
        $MarkdownExtra->code_class_prefix = $code_class_prefix;
        $MarkdownExtra->header_id_func    = $header_id_func;
        $MarkdownExtra->fn_id_prefix      = $fn_id_prefix;
        $MarkdownExtra->hard_wrap         = $hard_wrap;

        $string = $MarkdownExtra->transform($string);
        $string = $anchorize ? $this->c::htmlAnchorize($string) : $string;
        $string = $anchor_rels ? $this->c::htmlAnchorRels($string, $anchor_rels) : $string;
        $string = $smartypants ? $SmartyPants->transform($string) : $string;

        if ($no_p) { // Strip ` ^<p>|</p>$ ` tags?
            $string = preg_replace('/^\s*(?:\<p(?:\s[^>]*)?\>)+|(?:\<\/p\>)+\s*$/ui', '', $string);
        }
        if ($cache && isset($cache_dir, $cache_dir_permissions, $cache_file)) {
            if (!is_dir($cache_dir)) {
                mkdir($cache_dir, $cache_dir_permissions, true);

                if (!is_dir($cache_dir)) {
                    debug(0, c::issue(vars(), 'Unable to create cache directory.'));
                    return $string; // Soft failure.
                }
            } // Cache directory exists.
            file_put_contents($cache_file, $string);
        }
        return $string; // HTML markup now.
    }

    /**
     * Default header `id=""` callback.
     *
     * @since 170211.63148 ID callback.
     *
     * @param string $raw Header text value.
     *
     * @return string The `id=""` attribute value.
     */
    public function headerIdCallback(string $raw): string
    {
        $id = mb_strtolower($raw);
        $id = preg_replace('/[^\w]+/u', '-', $id);
        $id = 'j2h.'.$this->c::mbTrim($id, '', '-');

        $this->header_id_counter[$id] = $this->header_id_counter[$id] ?? 0;
        ++$this->header_id_counter[$id]; // Increment counter.

        if ($this->header_id_counter[$id] > 1) {
            $id .= '-'.$this->header_id_counter[$id];
        }
        return $id; // `id=""` attribute value.
    }

    /**
     * First image URL.
     *
     * @since 170124.74961 Initial release.
     *
     * @param string $markdown Markdown.
     *
     * @return string First image URL.
     */
    public function firstImageUrl(string $markdown): string
    {
        $regex      = '/(?<=^|[\s;,])\!\[[^\v[\]]*\]\((?<url>https?\:\/\/[^\s()]+?\.(?:png|jpeg|jpg|gif))\)(?=$|[\s.!?;,])/ui';
        return $url = $markdown && preg_match($regex, $markdown, $_m) ? $_m['url'] : '';
    }

    /**
     * Markdown stripper. @TODO.
     *
     * @since 151029 Markdown stripper.
     *
     * @param mixed $value Any input value.
     * @param array $args  Any additional behavioral args.
     *
     * @return string|array|object Stripped markdown value(s).
     */
    public function strip($value, array $args = [])
    {
        if (is_array($value) || is_object($value)) {
            foreach ($value as $_key => &$_value) {
                $_value = $this->strip($_value, $args);
            } // unset($_key, $_value);
            return $value;
        }
        if (!($string = (string) $value)) {
            return $string; // Nothing to do.
        }
        $default_args = []; // None at this time.

        $args = array_merge($default_args, $args);
        $args = array_intersect_key($args, $default_args);

        // Strip bold, italic, and strikethrough markers.
        $string = preg_replace('/(\*+)([^*]*)\\1/u', '${2}', $string);
        $string = preg_replace('/(_+)([^_]*)\\1/u', '${2}', $string);
        $string = preg_replace('/(~+)([^~]*)\\1/u', '${2}', $string);

        // Strip inline code and/or code blocks.
        $string = preg_replace('/(`+)(?:\w+'."[\r\n]".')?([^`]*)\\1'."[\r\n]".'?/u', '${2}', $string);

        // Strip blockquotes.
        $string = preg_replace('/^\s*\>\s+/um', '', $string);

        // Strip ATX-style headings.
        $string = preg_replace('/^\s*#+\s+([^#]*)#*$/um', '${1}', $string);

        // Strip line-based decorative headings.
        $string = preg_replace('/^\s*[=\-]+\s*$/um', '', $string);

        // Strip images and links.
        $string = preg_replace('/!?\[([^[\]]*)\]\([^()]*\)/u', '${1}', $string);

        return $string;
    }
}


<?php

/**
 * This file is part of the Ivory Google Map package.
 *
 * (c) Eric GELOEN <geloen.eric@gmail.com>
 *
 * For the full copyright and license information, please read the LICENSE
 * file that was distributed with this source code.
 */

namespace Ivory\GoogleMap\Helper\Overlays\MarkerCluster;

use Ivory\GoogleMap\Map;
use Ivory\GoogleMap\Overlays\Marker;
use Ivory\GoogleMap\Overlays\MarkerCluster;

/**
 * Javascript marker cluster helper.
 *
 * @author GeLo <geloen.eric@gmail.com>
 */
class JsMarkerClusterHelper extends DefaultMarkerClusterHelper
{
    /**
     * {@inheritdoc}
     */
    public function render(MarkerCluster $markerCluster, Map $map)
    {
        $this->jsonBuilder
            ->reset()
            ->setValues($markerCluster->getOptions());

        return sprintf('%s = new MarkerClusterer(%s, %s, %s);'.PHP_EOL,
            $markerCluster->getJavascriptVariable(),
            $map->getJavascriptVariable(),
            sprintf(
                '%s.functions.to_array(%s.markers)',
                $this->getJsContainerName($map),
                $this->getJsContainerName($map)
            ),
            $this->jsonBuilder->build()
        );
    }

    /**
     * {@inheritdoc}
     */
    public function renderLibraries(MarkerCluster $markerCluster, Map $map)
    {
        $url = '//cdn.rawgit.com/googlemaps/js-marker-clusterer/gh-pages/src/markerclusterer.js';

        return sprintf('<script type="text/javascript" src="%s"></script>'.PHP_EOL, $url);
    }

    /**
     * Renders a marker with the js map container.
     *
     * @param \Ivory\GoogleMap\Overlays\Marker $marker The marker.
     * @param \Ivory\GoogleMap\Map             $map    The map.
     *
     * @return string The JS output.
     */
    protected function renderMarker(Marker $marker, Map $map)
    {
        return sprintf(
            '%s.markers.%s = %s',
            $this->getJsContainerName($map),
            $marker->getJavascriptVariable(),
            $this->markerHelper->render($marker)
        );
    }
}


<?php
/**
 * CLI options.
 *
 * @author @jaswrks
 * @copyright WebSharks™
 */
declare (strict_types = 1);
namespace WebSharks\Core\Classes\Core;

use WebSharks\Core\Classes;
use WebSharks\Core\Interfaces;
use WebSharks\Core\Traits;
#
use WebSharks\Core\Classes\Core\Error;
use WebSharks\Core\Classes\Core\Base\Exception;
#
use function assert as debug;
use function get_defined_vars as vars;
#
use GetOptionKit\Option;
use GetOptionKit\OptionParser;
use GetOptionKit\OptionResult;
use GetOptionKit\OptionCollection;
use GetOptionKit\OptionPrinter\ConsoleOptionPrinter;

/**
 * CLI options.
 *
 * @since 150424 Initial release.
 */
class CliOpts extends Classes\Core\Base\Core
{
    /**
     * Options.
     *
     * @since 150424
     *
     * @var OptionCollection
     */
    protected $OptionCollection;

    /**
     * Class constructor.
     *
     * @since 150424 Initial release.
     *
     * @param Classes\App $App Instance of App.
     */
    public function __construct(Classes\App $App)
    {
        parent::__construct($App);

        if (!$this->c::isCli()) {
            throw $this->c::issue('Requires CLI mode.');
        }
        $this->OptionCollection = new OptionCollection();
    }

    /**
     * Get options.
     *
     * @since 150424 Initial release.
     *
     * @param array $specs An array of option specs.
     *
     * @link https://github.com/c9s/GetOptionKit
     */
    public function add(array $specs)
    {
        foreach ($specs as $_spec => $_data) {
            if ($_spec && is_string($_spec) && !empty($_data['desc'])) {
                $_Option = $this->OptionCollection->add($_spec, $_data['desc']);

                if (!empty($_data['type'])) {
                    $_Option->isa($_data['type']);
                }
                if (isset($_data['default'])) {
                    $_Option->defaultValue($_data['default']);
                }
                if (isset($_data['valid_values'])) {
                    $_Option->validValues($_data['valid_values']);
                }
            }
        } // unset($_spec, $_data, $_Option);
    }

    /**
     * Get options.
     *
     * @since 150424 Initial release.
     *
     * @param bool       $extract Extract into an array after parsing?
     * @param array|null $args    Args to parse; default is `$GLOBALS['argv']`.
     *
     * @return array|OptionResult|Option[] Associative array, or the result set of Option objs.
     */
    public function parse(bool $extract = true, array $args = null)
    {
        $Parser = new OptionParser($this->OptionCollection);

        $OptionResult = $Options = $Parser->parse($args ?? $GLOBALS['argv']);

        if (!$extract) { // This contains some additional information for each option.
            return $OptionResult = $Options; // OptionResult|Option[]
        } else {
            $options = []; // Associative array (default behavior).

            foreach ($Options as $_key => $_Option) {
                $_key           = preg_replace('/[^a-z0-9]/ui', '_', $_key);
                $_value         = $_Option->getValue();
                $options[$_key] = $_value;
            } // unset($_key, $_value, $_Option);

            return $options; // Suitable for `extract()` now.
        }
    }

    /**
     * Print option specs.
     *
     * @since 150424 Initial release.
     *
     * @return string Specs as a string.
     */
    public function specs(): string
    {
        $Printer = new ConsoleOptionPrinter();

        return $Printer->render($this->OptionCollection);
    }
}


<?php
/**
 * HTML strip utilities.
 *
 * @author @jaswrks
 * @copyright WebSharks™
 */
declare(strict_types=1);
namespace WebSharks\Core\Classes\Core\Utils;

use WebSharks\Core\Classes;
use WebSharks\Core\Interfaces;
use WebSharks\Core\Traits;
#
use WebSharks\Core\Classes\Core\Error;
use WebSharks\Core\Classes\Core\Base\Exception;
#
use function assert as debug;
use function get_defined_vars as vars;

/**
 * HTML strip utilities.
 *
 * @since 150424 Initial release.
 */
class HtmlStrip extends Classes\Core\Base\Core
{
    /**
     * Strips HTML attributes deeply.
     *
     * @since 150424 Initial release.
     *
     * @param mixed $value Any input value.
     * @param array $args  Any additional behavioral args.
     *
     * @return string|array|object String w/ HTML attributes stripped.
     */
    public function attributes($value, array $args = [])
    {
        if (is_array($value) || is_object($value)) {
            foreach ($value as $_key => &$_value) {
                $_value = $this->attributes($_value, $args);
            } // unset($_key, $_value);
            return $value;
        }
        if (!($string = (string) $value)) {
            return $string; // Nothing to do.
        }
        $default_args = [
            'allowed_attributes' => [],
        ];
        $args = array_merge($default_args, $args);
        $args = array_intersect_key($args, $default_args);

        $allowed_attributes = // Force lowercase.
            array_map('mb_strtolower', (array) $args['allowed_attributes']);

        $regex_tags  = '/(?<open>\<[\w\-]+)(?<attrs>[^>]+)(?<close>\>)/ui';
        $regex_attrs = '/\s+(?<attr>[\w\-]+)(?:\s*\=\s*(["\']).*?\\2|\s*\=[^\s]*)?/uis';

        return preg_replace_callback($regex_tags, function ($m) use ($allowed_attributes, $regex_attrs) {
            return $m['open'].preg_replace_callback($regex_attrs, function ($m) use ($allowed_attributes) {
                return in_array(mb_strtolower($m['attr']), $allowed_attributes, true) ? $m[0] : '';
            }, $m['attrs']).$m['close']; // With modified attributes.
        }, $string); // Removes attributes; leaving only those allowed explicitly.
    }
}


<?php

/*
 * This file is part of the Ivory Google Map package.
 *
 * (c) Eric GELOEN <geloen.eric@gmail.com>
 *
 * For the full copyright and license information, please read the LICENSE
 * file that was distributed with this source code.
 */

namespace Ivory\GoogleMap\Overlays;

use Ivory\GoogleMap\Assets\AbstractOptionsAsset;
use Ivory\GoogleMap\Base\Bound;
use Ivory\GoogleMap\Base\Coordinate;
use Ivory\GoogleMap\Exception\OverlayException;

/**
 * Rectangle which describes a google map rectangle.
 *
 * @author GeLo <geloen.eric@gmail.com>
 */
class Rectangle extends AbstractOptionsAsset implements ExtendableInterface
{
    /** @var \Ivory\GoogleMap\Base\Bound */
    protected $bound;

    /**
     * Creates a rectangle.
     */
    public function __construct(Bound $bound = null)
    {
        parent::__construct();

        $this->setPrefixJavascriptVariable('rectangle_');

        if ($bound === null) {
            $bound = new Bound(new Coordinate(-1, -1), new Coordinate(1, 1));
        }

        $this->setBound($bound);
    }

    /**
     * Gets the rectangle bound.
     *
     * @return \Ivory\GoogleMap\Base\Bound The rectangle bound.
     */
    public function getBound()
    {
        return $this->bound;
    }

    /**
     * Sets the rectangle bound.
     *
     * Available prototypes:
     *  - function setBound(Ivory\GoogleMap\Base\Bound $bound)
     *  - function setBount(Ivory\GoogleMap\Base\Coordinate $southWest, Ivory\GoogleMap\Base\Coordinate $northEast)
     *  - function setBound(
     *     double $southWestLatitude,
     *     double $southWestLongitude,
     *     double $northEastLatitude,
     *     double $northEastLongitude,
     *     boolean southWestNoWrap = true,
     *     boolean $northEastNoWrap = true
     * )
     *
     * @throws \Ivory\GoogleMap\Exception\OverlayException If the bound is not valid.
     */
    public function setBound()
    {
        $args = func_get_args();

        if (isset($args[0]) && ($args[0] instanceof Bound)) {
            if (!$args[0]->hasCoordinates()) {
                throw OverlayException::invalidRectangleBoundCoordinates();
            }

            $this->bound = $args[0];
        } elseif ((isset($args[0]) && ($args[0] instanceof Coordinate))
            && (isset($args[1]) && ($args[1] instanceof Coordinate))
        ) {
            $this->bound->setSouthWest($args[0]);
            $this->bound->setNorthEast($args[1]);
        } elseif ((isset($args[0]) && is_numeric($args[0]))
            && (isset($args[1]) && is_numeric($args[1]))
            && (isset($args[2]) && is_numeric($args[2]))
            && (isset($args[3]) && is_numeric($args[3]))
        ) {
            $this->bound->setSouthWest(new Coordinate($args[0], $args[1]));
            $this->bound->setNorthEast(new Coordinate($args[2], $args[3]));

            if (isset($args[4]) && is_bool($args[4])) {
                $this->bound->getSouthWest()->setNoWrap($args[4]);
            }

            if (isset($args[5]) && is_bool($args[5])) {
                $this->bound->getNorthEast()->setNoWrap($args[5]);
            }
        } else {
            throw OverlayException::invalidRectangleBound();
        }
    }
}


<?php
declare(strict_types = 1);
namespace RabbitCMS\Modules\Console;

use Illuminate\Console\Command;
use RabbitCMS\Modules\Managers\Modules;

/**
 * Class ScanCommand.
 * @package RabbitCMS\Modules
 */
class ScanCommand extends Command
{
    use ShowModulesTrait;

    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'modules:scan {--pretend : Only show found modules.}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Rescan available modules';

    /**
     * @var Modules
     */
    protected $modules;

    /**
     * ScanCommand constructor.
     *
     * @param Modules $modules
     */
    public function __construct(Modules $modules)
    {
        parent::__construct();
        $this->modules = $modules;
    }

    /**
     * Execute the console command.
     *
     * @return void
     */
    public function handle()
    {
        $this->modules->scan(!$this->option('pretend'));
        $this->showModules($this->modules->all());
    }
}


<?php
/**
 * Error.
 *
 * @author @jaswrks
 * @copyright WebSharks™
 */
declare(strict_types=1);
namespace WebSharks\Core\Classes\Core;

use WebSharks\Core\Classes;
use WebSharks\Core\Interfaces;
use WebSharks\Core\Traits;
#
use WebSharks\Core\Classes\Core\Base\Exception;
#
use function assert as debug;
use function get_defined_vars as vars;

/**
 * Error.
 *
 * @since 160710 Error utils.
 */
class Error extends Classes\Core\Base\Core
{
    /**
     * Errors.
     *
     * @since 160710
     *
     * @var array[]
     */
    protected $errors;

    /**
     * Error data.
     *
     * @since 160710
     *
     * @var array
     */
    protected $error_data;

    /**
     * Default slug.
     *
     * @since 160710
     *
     * @var array
     */
    protected $default_slug;

    /**
     * Default message.
     *
     * @since 160710
     *
     * @var array
     */
    protected $default_message;

    /**
     * Class constructor.
     *
     * @since 160710 Error utils.
     *
     * @param Classes\App $App     Instance of App.
     * @param string      $slug    Error slug.
     * @param string      $message Error message.
     * @param mixed       $data    Error data.
     */
    public function __construct(Classes\App $App, string $slug = '', string $message = '', $data = null)
    {
        parent::__construct($App);

        $this->errors          = [];
        $this->error_data      = [];
        $this->default_slug    = 'error';
        $this->default_message = __('Unknown error.');

        if ($slug || $message || isset($data)) {
            $this->add($slug, $message, $data);
        }
    }

    /**
     * Errors exists.
     *
     * @since 161002 Error utils.
     *
     * @return bool Errors exist?
     */
    public function exists(): bool
    {
        return !empty($this->errors);
    }

    /**
     * Errors exist (alias).
     *
     * @since 160710 Error utils.
     *
     * @return bool Errors exist?
     *
     * @deprecated 161002 Use `exists()` please.
     */
    public function exist(): bool
    {
        return !empty($this->errors);
    }

    /**
     * Get error slug.
     *
     * @since 160710 Error utils.
     *
     * @return string Error slug.
     */
    public function slug(): string
    {
        $slugs = $this->slugs();
        return $slugs[0] ?? $this->default_slug;
    }

    /**
     * Get error slug.
     *
     * @since 160710 Error utils.
     *
     * @param string $slug Error slug.
     *
     * @return string Error message.
     */
    public function message(string $slug = ''): string
    {
        $slug     = $slug ?: $this->slug();
        $messages = $this->messages($slug);
        return $messages[0] ?? $this->default_message;
    }

    /**
     * Get error slugs.
     *
     * @since 160710 Error utils.
     *
     * @return string[] Error slugs.
     */
    public function slugs(): array
    {
        $slugs = array_keys($this->errors);
        return $slugs ?: [$this->default_slug];
    }

    /**
     * Get error messages.
     *
     * @since 160710 Error utils.
     *
     * @param string $slug    Error slug.
     * @param bool   $by_slug All errors by slug?
     *
     * @return string[] An array of error messages.
     */
    public function messages(string $slug = '', bool $by_slug = false): array
    {
        if (!$slug) { // All messages (i.e., for all slugs)?
            //
            if ($by_slug) { // All messages keyed by slug?
                return $this->errors ?: [$this->default_slug => $this->default_message];
                //
            } else { // Merge all messages into a single array.
                $messages = []; // Initialize array.

                foreach ($this->errors as $_slug => $_messages) {
                    $messages = array_merge($messages, $_messages);
                } // unset($_slug, $_messages); // Housekeeping.

                return $messages ?: [$this->default_message];
            }
        } else { // For a specific slug.
            $messages = $this->errors[$slug] ?? [];
            return $messages ?: [$this->default_message];
        }
    }

    /**
     * Get error data.
     *
     * @since 160710 Error utils.
     *
     * @param string $slug    Error slug.
     * @param bool   $by_slug All data by slug?
     *
     * @return array|mixed|null Error data.
     */
    public function data(string $slug = '', bool $by_slug = false)
    {
        if (!$slug) { // All data (i.e., for all slugs)?
            //
            if ($by_slug) { // All data keyed by slug?
                return $this->error_data ?: [$this->default_slug => null];
                //
            } else { // Data for the first slug.
                // NOTE: Different than `messages()`.
                $slug = $this->slug(); // First slug.
                return $this->error_data[$slug] ?? null;
            }
        } else {
            return $this->error_data[$slug] ?? null;
        }
    }

    /**
     * Add error.
     *
     * @since 160710 Error utils.
     *
     * @param string $slug    Error slug.
     * @param string $message Error message.
     * @param mixed  $data    Error data.
     */
    public function add(string $slug, string $message = '', $data = null)
    {
        $slug = $slug ?: $this->default_slug;

        if (!$message && $slug === $this->default_slug) {
            $message = $this->default_message;
        } elseif (!$message) { // If empty, base it on slug.
            $message = mb_strtolower($this->c::slugToName($slug));
            $message = $this->c::mbUcFirst($message).'.';
        }
        $this->errors[$slug][] = $message;

        if (isset($data) || !array_key_exists($slug, $this->error_data)) {
            $this->error_data[$slug] = $data;
        }
    }

    /**
     * Remove error(s).
     *
     * @since 160710 Error utils.
     *
     * @param string $slug Error slug.
     */
    public function remove(string $slug = '')
    {
        if (!$slug) {
            $this->errors     = [];
            $this->error_data = [];
        } else {
            unset($this->errors[$slug]);
            unset($this->error_data[$slug]);
        }
    }
}


<?php

/*
 * This file is part of the Ivory Google Map package.
 *
 * (c) Eric GELOEN <geloen.eric@gmail.com>
 *
 * For the full copyright and license information, please read the LICENSE
 * file that was distributed with this source code.
 */

namespace Ivory\GoogleMap\Overlays;

use Ivory\GoogleMap\Assets\AbstractOptionsAsset;
use Ivory\GoogleMap\Base\Coordinate;
use Ivory\GoogleMap\Exception\OverlayException;

/**
 * Polygon which describes a google map polygon.
 *
 * @see http://code.google.com/apis/maps/documentation/javascript/reference.html#Polygon
 * @author GeLo <geloen.eric@gmail.com>
 */
class Polygon extends AbstractOptionsAsset implements ExtendableInterface
{
    /** @var array */
    protected $coordinates;

    /**
     * Creates a polygon.
     *
     * @param array $coordinates The polygon coordinates.
     */
    public function __construct(array $coordinates = array())
    {
        parent::__construct();

        $this->setPrefixJavascriptVariable('polygon_');
        $this->setCoordinates($coordinates);
    }

    /**
     * Checks if polygon has coordinates.
     *
     * @return boolean TRUE if the polygon has coordinates else FALSE.
     */
    public function hasCoordinates()
    {
        return !empty($this->coordinates);
    }

    /**
     * Gets the polygon coordinates.
     *
     * @return array The polygon coordinates.
     */
    public function getCoordinates()
    {
        return $this->coordinates;
    }

    /**
     * Sets the polygon coordinates.
     *
     * @param array $coordinates The polygon coordinates.
     */
    public function setCoordinates($coordinates)
    {
        $this->coordinates = array();

        foreach ($coordinates as $coordinate) {
            $this->addCoordinate($coordinate);
        }
    }

    /**
     * Adds a coordinate to the polygon.
     *
     * Available prototypes:
     *  - function addCoordinate(Ivory\GoogleMap\Base\Coordinate $coordinate)
     *  - function addCoordinate(double $latitude, double $longitude, boolean $noWrap = true)
     *
     * @throws \Ivory\GoogleMap\Exception\OverlayException If the coordinate is not valid.
     */
    public function addCoordinate()
    {
        $args = func_get_args();

        if (isset($args[0]) && ($args[0] instanceof Coordinate)) {
            $this->coordinates[] = $args[0];
        } elseif ((isset($args[0]) && is_numeric($args[0])) && (isset($args[1]) && is_numeric($args[1]))) {
            $coordinate = new Coordinate($args[0], $args[1]);

            if (isset($args[2]) && is_bool($args[2])) {
                $coordinate->setNoWrap($args[2]);
            }

            $this->coordinates[] = $coordinate;
        } else {
            throw OverlayException::invalidPolygonCoordinate();
        }
    }
}


<?php
namespace Perry\Representation\Eve\v1;

use \Perry\Representation\Reference as Reference;
use \Perry\Representation\Uri as Uri;
use \Perry\Representation\Base as Base;

class ItemGroup extends Base
{
    public $category;

    public $description;

    public $name;

    public $types = [];

    public $published;

    // by Warringer\Types\Reference
    public function setCategory($category)
    {
        $this->category = new Reference($category);
    }

    // by Warringer\Types\String
    public function setDescription($description)
    {
        $this->description = $description;
    }

    // by Warringer\Types\String
    public function setName($name)
    {
        $this->name = $name;
    }

    // by Warringer\Types\ArrayType
    public function setTypes($types)
    {
        // by Warringer\Types\Reference
        $func = function ($value) { return new Reference($value); };

        foreach ($types as $key => $value) {
            $this->types[$key] = $func($value);
        }
    }

    // by Warringer\Types\Base
    public function setPublished($published)
    {
        $this->published = $published;
    }

}


<?php
namespace Wa72\HtmlPrettymin;

use JSMin\JSMin;
use tubalmartin\CssMin\Minifier as CSSmin;
use Symfony\Component\OptionsResolver\OptionsResolver;

/**
 * PrettyMin is a HTML minifier and code formatter that works directly on the DOM tree
 *
 */
class PrettyMin
{
    /**
     * @var \DOMDocument
     */
    protected $doc;

    /**
     * @var array
     */
    protected $options;

    /**
     * @param array $options
     */
    public function __construct(array $options = [])
    {
        $resolver = new OptionsResolver();
        $this->configureOptions($resolver);
        $this->options = $resolver->resolve($options);
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'minify_js' => true,
            'minify_css' => true,
            'remove_comments' => true,
            'remove_comments_exeptions' => ['/^\[if /'],
            'keep_whitespace_around' => [
                // keep whitespace around inline elements
                'b', 'big', 'i', 'small', 'tt',
                'abbr', 'acronym', 'cite', 'code', 'dfn', 'em', 'kbd', 'strong', 'samp', 'var',
                'a', 'bdo', 'br', 'img', 'map', 'object', 'q', 'span', 'sub', 'sup',
                'button', 'input', 'label', 'select', 'textarea'
            ],
            'keep_whitespace_in' => ['script', 'style', 'pre'],
            'remove_empty_attributes' => ['style', 'class'],
            'indent_characters' => "\t"
        ]);
    }

    /**
     * Load an HTML document
     *
     * @param \DOMDocument|\DOMElement|\SplFileInfo|string $html
     * @return PrettyMin
     */
    public function load($html) {
        if ($html instanceof \DOMDocument) {
            $d = $html;
        } elseif ($html instanceof \DOMElement) {
            $d = $html->ownerDocument;
        } elseif ($html instanceof \SplFileInfo) {
            $d = new \DOMDocument();
            $d->preserveWhiteSpace = false;
            $d->validateOnParse = true;
            $d->loadHTMLFile($html->getPathname());
        } else {
            $d = new \DOMDocument();
            $d->preserveWhiteSpace = false;
            $d->validateOnParse = true;
            $d->loadHTML($html);
        }
        $d->formatOutput = false;
        $d->normalizeDocument();
        $this->doc = $d;
        return $this;
    }

    /**
     * Minify the loaded HTML document
     *
     * @param array $options
     * @return PrettyMin
     */
    public function minify($options = [])
    {
        $resolver = new OptionsResolver();
        $resolver->setDefaults([
            'minify_js' => $this->options['minify_js'],
            'minify_css' => $this->options['minify_css'],
            'remove_comments' => $this->options['remove_comments'],
            'remove_empty_attributes' => $this->options['remove_empty_attributes']
        ]);
        $options = $resolver->resolve($options);

        if ($options['minify_js']) {
            $this->minifyJavascript();
        }
        if ($options['minify_css']) {
            $this->minifyCss();
        }
        if ($options['remove_comments']) {
            $this->removeComments();
        }

        if ($options['remove_empty_attributes']) {
            $this->removeEmptyAttributes();
        }

        $this->removeWhitespace();

        return $this;
    }

    /**
     * nicely indent HTML code
     *
     * @return PrettyMin
     */
    public function indent()
    {
        $this->removeWhitespace();
        $this->indentRecursive($this->doc->documentElement, 0);
        return $this;
    }

    /**
     * Get the DOMDocument
     *
     * @return \DOMDocument
     */
    public function getDomDocument()
    {
        return $this->doc;
    }

    /**
     * Get the HTML code as string
     *
     * This is a shortcut for calling $this->getDomDocument()->saveHTML()
     *
     * @return string
     */
    public function saveHtml()
    {
        return $this->doc->saveHTML();
    }

    protected function minifyJavascript()
    {
        $elements = $this->doc->getElementsByTagName('script');

        $to_be_removed = [];
        /** @var \DOMElement $element */
        foreach ($elements as $element) {
            $code = $element->textContent;
            $element->nodeValue = '';
            if (trim($code)) {
                $code = JSMin::minify($code);
                $ct = $this->doc->createCDATASection($code);
                $element->appendChild($ct);
            } elseif (!$element->hasAttribute('src')) {
                // script tag has neither content nor a src attribute, remove it completely
                array_push($to_be_removed, $element);
            }
        }
        foreach ($to_be_removed as $element) {
            $element->parentNode->removeChild($element);
        }
    }

    protected function minifyCss()
    {
        $elements = $this->doc->getElementsByTagName('style');
        $to_be_removed = [];
        /** @var \DOMElement $element */
        foreach ($elements as $element) {
            $code = $element->nodeValue;
            $element->nodeValue = '';
            if (trim($code)) {
                $min = new CSSmin();
                if (trim($code)) {
                    $code = trim($min->run($code));
                }
                $ct = $this->doc->createCDATASection($code);
                $element->appendChild($ct);
            } else {
                // Style tag is empty, remove it completely
                array_push($to_be_removed, $element);
            }
        }
        foreach ($to_be_removed as $element) {
            $element->parentNode->removeChild($element);
        }
    }

    protected function removeEmptyAttributes()
    {
        if (!$this->options['remove_empty_attributes']) return;
        if (is_string($this->options['remove_empty_attributes'])) {
            $this->options['remove_empty_attributes'] = [$this->options['remove_empty_attributes']];
        }
        if (is_array($this->options['remove_empty_attributes'])) {
            $xpath = new \DOMXPath($this->doc);
            foreach ($this->options['remove_empty_attributes'] as $attr) {
                /** @var \DOMElement $el */
                foreach ($xpath->query('//*[@' . $attr . ']') as $el) {
                    if (trim($el->getAttribute($attr)) == '') {
                        $el->removeAttribute($attr);
                    }
                }
            }
        }
    }

    protected function removeComments($exception_patterns = null)
    {
        if ($exception_patterns === null) {
            $exception_patterns = $this->options['remove_comments_exeptions'];
        }
        $xpath = new \DOMXPath($this->doc);
        foreach ($xpath->query('//comment()') as $comment) {
            /** @var \DOMNode $comment */
            $remove = true;
            foreach ($exception_patterns as $exception) {
                if (preg_match($exception, $comment->textContent)) {
                    $remove = false;
                    break;
                }
            }
            if ($remove) $comment->parentNode->removeChild($comment);
        }
    }

    /**
     * originally based on http://stackoverflow.com/a/18260955
     */
    protected function removeWhitespace() {
        // Retrieve all text nodes using XPath
        $x = new \DOMXPath($this->doc);
        $nodeList = $x->query("//text()");
        foreach($nodeList as $node) {
            /** @var \DOMNode $node */

            if (in_array($node->parentNode->nodeName, $this->options['keep_whitespace_in'])) {
                continue;
            };

            $node->nodeValue = str_replace(["\r", "\n", "\t"], ' ', $node->nodeValue);
            //$node->nodeValue = preg_replace('/ {2,}/', ' ', $node->nodeValue);
            while (strpos($node->nodeValue, '  ') !== false) {
                $node->nodeValue = str_replace('  ', ' ', $node->nodeValue);
            }

            if (!in_array($node->parentNode->nodeName, $this->options['keep_whitespace_around'])) {
                if (!($node->previousSibling && in_array($node->previousSibling->nodeName,
                        $this->options['keep_whitespace_around']))
                ) {
                    $node->nodeValue = ltrim($node->nodeValue);
                }

                if (!($node->nextSibling && in_array($node->nextSibling->nodeName,
                        $this->options['keep_whitespace_around']))
                ) {
                    $node->nodeValue = rtrim($node->nodeValue);
                }
            }

            if((strlen($node->nodeValue) == 0)) {
                $node->parentNode->removeChild($node);
            }
        }
    }

    /**
     * indent HTML code
     *
     * originally based on http://stackoverflow.com/a/18260955
     *
     * @param \DOMNode $currentNode
     * @param int $depth
     * @return bool
     */
    protected function indentRecursive(\DOMNode $currentNode, $depth) {
        $indent_characters = $this->options['indent_characters'];

        $indentCurrent = true;
        $indentChildren = true;
        $indentClosingTag = false;
        if(($currentNode->nodeType == XML_TEXT_NODE)) {
            $indentCurrent = false;
        }

        if (in_array($currentNode->nodeName, $this->options['keep_whitespace_in'])) {
            $indentCurrent = true;
            $indentChildren = false;
            $indentClosingTag = (strpos($currentNode->nodeValue, "\n") !== false);
        }

        if (in_array($currentNode->nodeName, $this->options['keep_whitespace_around'])) {
            $indentCurrent = false;
        }
        if($indentCurrent && $depth > 0) {
            // Indenting a node consists of inserting before it a new text node
            // containing a newline followed by a number of tabs corresponding
            // to the node depth.
            $textNode = $currentNode->ownerDocument->createTextNode("\n" . str_repeat($indent_characters, $depth));
            $currentNode->parentNode->insertBefore($textNode, $currentNode);
        }
        if($indentCurrent && $currentNode->childNodes && $indentChildren) {
            foreach($currentNode->childNodes as $childNode) {
                $indentClosingTag = $this->indentRecursive($childNode, $depth + 1);
            }
        }
        if($indentClosingTag) {
            // If children have been indented, then the closing tag
            // of the current node must also be indented.
            if ($currentNode->lastChild && ($currentNode->lastChild->nodeType == XML_CDATA_SECTION_NODE || $currentNode->lastChild->nodeType == XML_TEXT_NODE) && preg_match('/\n\s?$/', $currentNode->lastChild->textContent)) {
                $currentNode->lastChild->nodeValue = preg_replace('/\n\s?$/', "\n" . str_repeat("\t", $depth), $currentNode->lastChild->nodeValue);
            } else {
                $textNode = $currentNode->ownerDocument->createTextNode("\n" . str_repeat("\t", $depth));
                $currentNode->appendChild($textNode);
            }
        }
        return $indentCurrent;
    }
}


<?php

/**
 * YAWIK
 *
 * @filesource
 * @license MIT
 * @copyright  2013 - 2017 Cross Solution <http://cross-solution.de>
 */

namespace Organizations\Controller;

use Auth\Exception\UnauthorizedAccessException;
use Core\Entity\Exception\NotFoundException;
use Jobs\Repository\Job as JobRepository;
use Organizations\Entity\Organization;
use Organizations\Repository\Organization as OrganizationRepository;
use Zend\Http\Response;
use Zend\I18n\Translator\TranslatorInterface;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Organizations\ImageFileCache\Manager as ImageFileCacheManager;

/**
 * Class ProfileController
 *
 * @author Anthonius Munthi <me@itstoni.com>
 * @package Organizations\Controller
 * @since 0.30.1
 */
class ProfileController extends AbstractActionController
{
    /**
     * @var OrganizationRepository
     */
    private $repo;

    /**
     * @var JobRepository
     */
    private $jobRepo;

    /**
     * @var TranslatorInterface
     */
    private $translator;

    /**
     * @var ImageFileCacheManager
     */
    private $imageFileCacheManager;

    /**
     * @var array
     */
    private $options = [
        'count' => 10,
    ];

    public function __construct(
        OrganizationRepository $repo,
        JobRepository $jobRepository,
        TranslatorInterface $translator,
        ImageFileCacheManager $imageFileCacheManager,
        $options
    ) {
        $this->repo = $repo;
        $this->translator = $translator;
        $this->imageFileCacheManager = $imageFileCacheManager;
        $this->jobRepo = $jobRepository;
        $this->options = $options;
    }

    /**
     * List organization
     *
     * @return ViewModel
     */
    public function indexAction()
    {
        $result = $this->pagination([
            'params' => ['Organizations_Profile',[
                    'q',
                    'count' => $this->options['count'],
                    'page' => 1,
                ]
            ],
            'paginator' => [
                'Organizations/Organization',
                'as' => 'organizations',
                'params' => [
                    'type' => 'profile',
                ]
            ],
            'form' => [
                'Core/Search',
                'as' => 'form',
            ]
        ]);

        $organizationImageCache = $this->imageFileCacheManager;
        $result['organizationImageCache'] = $organizationImageCache;

        return new ViewModel($result);
    }

    /**
     * @return array|ViewModel
     */
    public function detailAction()
    {
        $translator      = $this->translator;
        $repo            = $this->repo;
        $id              = $this->params('id');

        if (is_null($id)) {
            $this->getResponse()->setStatusCode(Response::STATUS_CODE_404);
            return [
                'message' => $translator->translate('Can not access profile page without id'),
                'exception' => new \InvalidArgumentException('Null Organization Profile Id')
            ];
        }

        $organization = $repo->find($id);
        if (!$organization instanceof Organization) {
            throw new NotFoundException($id);
        }

        if (
            Organization::PROFILE_DISABLED == $organization->getProfileSetting()
            || is_null($organization->getProfileSetting())
        ) {
            return $this->disabledProfileViewModel($organization);
        }

        $result = $this->pagination([
            'params' => [
                'Organization_Jobs',[
                    'q',
                    'organization_id' => $id,
                    'count' => $this->options['count'],
                    'page' => 1,
                ],
            ],
            'paginator' => [
                'as' => 'jobs',
                'Organizations/ListJob',
            ],
        ]);

        if (
            Organization::PROFILE_ACTIVE_JOBS == $organization->getProfileSetting()
        ) {
            /* @var \Zend\Paginator\Paginator $paginator */
            $paginator = $result['jobs'];
            $count = $paginator->getTotalItemCount();
            if (0===$count) {
                return $this->disabledProfileViewModel($organization);
            }
        }
        $result['organization'] = $organization;
        $result['organizationImageCache'] = $this->imageFileCacheManager;

        /* @var \Zend\Mvc\Controller\Plugin\Url $url */
        $result['paginationControlRoute'] = 'lang/organizations/profileDetail';
        return new ViewModel($result);
    }

    private function disabledProfileViewModel($organization)
    {
        $model = new ViewModel([
            'organizationImageCache' => $this->imageFileCacheManager,
            'organization' => $organization,
        ]);
        $model->setTemplate('organizations/profile/disabled');

        return $model;
    }
}


<?php
/**
 * YAWIK
 *
 * @filesource
 * @license MIT
 * @copyright  2013 - 2016 Cross Solution <http://cross-solution.de>
 */

/** */
namespace Organizations\Repository\Event;

use Auth\Entity\UserInterface;
use Doctrine\Common\EventSubscriber;
use Doctrine\ODM\MongoDB\Event\LifecycleEventArgs;
use Doctrine\ODM\MongoDB\Events;
use Organizations\Entity\OrganizationReference;

/**
 * This listener creates and injects organization references to user entities.
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @since 0.18
 */
class InjectOrganizationReferenceListener implements EventSubscriber
{
    public function getSubscribedEvents()
    {
        return array(Events::postLoad);
    }

    /**
     * Creates and injects the organization reference to an user entity.
     *
     * @param LifecycleEventArgs $args
     */
    public function postLoad(LifecycleEventArgs $args)
    {
        $document = $args->getDocument();

        if ($document instanceof UserInterface) {
            $repository = $args->getDocumentManager()->getRepository('Organizations\Entity\Organization');
            $userId  = $document->getId();
            $reference = new OrganizationReference($userId, $repository);

            $document->setOrganization($reference);
        }
    }
}


<?php
/**
 * YAWIK
 *
 * @filesource
 * @license    MIT
 * @copyright  2013 - 2016 Cross Solution <http://cross-solution.de>
 */

/** */
namespace Organizations\Controller;

use Organizations\Controller\Plugin\AcceptInvitationHandler;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\JsonModel;
use Zend\View\Model\ViewModel;
use Organizations\Repository\Organization as OrganizationRepository;

/**
 * This controller is responsible for the user invitation process.
 *
 * Which consists on these tasks:
 * - Create temporary users if necessary or find the existent one for an email address.
 * - Send an invitation mail.
 * - Handles the acceptance of such an invitation.
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @author Anthonius Munthi <me@itstoni.com>
 * @since  0.19
 */
class InviteEmployeeController extends AbstractActionController
{
    /**
     * @var OrganizationRepository
     */
    private $orgRepo;

    public function __construct(
        OrganizationRepository $orgRepo
    ) {
        $this->orgRepo = $orgRepo;
    }

    /**
     * Invitation first step: Create or find user and send mail.
     *
     * @return JsonModel
     */
    public function inviteAction()
    {
        $email   = $this->params()->fromQuery('email');
        $handler = $this->plugin('Organizations/InvitationHandler');
        $result  = $handler->process($email);

        return new JsonModel($result);
    }

    /**
     * Invitation second step: Acceptance of the invitation.
     *
     * @return ViewModel
     */
    public function acceptAction()
    {
        /* @var $request \Zend\Http\PhpEnvironment\Request */
        $request = $this->getRequest();

        if ($request->isPost()) {
            return $this->createSetPasswordViewModel();
        }

        $token        = $this->params()->fromQuery('token');
        $organization = $this->params()->fromQuery('organization');

        /* @var $handler \Organizations\Controller\Plugin\AcceptInvitationHandler */
        $handler = $this->plugin('Organizations/AcceptInvitationHandler');
        $result  = $handler->process($token, $organization);

        switch ($result) {
            default:
            case AcceptInvitationHandler::OK:
                $model = $this->createSuccessViewModel();
                break;

            case AcceptInvitationHandler::OK_SET_PW:
                $model = $this->createSetPasswordViewModel();
                break;

            case AcceptInvitationHandler::ERROR_ORGANIZATION_NOT_FOUND:
                $model = $this->createErrorViewModel(
                    /*@translate*/ 'The organization referenced in your request could not be found.'
                );
                break;

            case AcceptInvitationHandler::ERROR_TOKEN_INVALID:
                $model = $this->createErrorViewModel(
                    /*@translate*/ 'The access token you provided seems to have expired.'
                );
                break;
        }

        return $model;
    }

    /**
     * Creates a view model for success view script with set password form.
     *
     * @return ViewModel
     */
    protected function createSetPasswordViewModel()
    {
        $organization = $this->getOrganizationEntity();
        $result       = $this->forward()->dispatch('Auth\Controller\Password', array('action' => 'index'));
        $model        = new ViewModel(
            array(
                'organization' => $organization->getOrganizationName()->getName()
            )
        );

        if (!$result->getVariable('valid', false)) {
            $model->setVariable('form', $result->getVariable('form'));
        }

        return $model;
    }

    /**
     * Gets the referenced organization entity.
     *
     * Retrieves the identifier from the requests' query params.
     *
     * @return \Organizations\Entity\OrganizationInterface
     */
    protected function getOrganizationEntity()
    {
        /* @var $orgRepo \Organizations\Repository\Organization */
        $orgRepo = $this->orgRepo;
        $organiationId = $this->params()->fromQuery('organization');

        $organization = $orgRepo->find($organiationId);

        return $organization;
    }

    /**
     * Creates the view model for the success view script.
     *
     * @return ViewModel
     */
    protected function createSuccessViewModel()
    {
        $organization = $this->getOrganizationEntity();

        return new ViewModel(
            array(
                'organization' => $organization->getOrganizationName()->getName()
            )
        );
    }

    /**
     * Creates a view model for the error page view script.
     *
     * Sets the response status code to 500 (indicating an internal error).
     *
     * @param string $message
     *
     * @return ViewModel
     */
    protected function createErrorViewModel($message)
    {
        /* @var $response \Zend\Http\Response */
        $response = $this->getResponse();
        $response->setStatusCode(500);

        $model = new ViewModel(array('message' => $message));
        $model->setTemplate('organizations/error/invite');

        return $model;
    }
}


<?php
/**
 * YAWIK
 *
 * @filesource
 * @copyright (c) 2013 - 2016 Cross Solution (http://cross-solution.de)
 * @license   MIT
 */

/** HttploadStrategy.php */
namespace Organizations\Entity\Hydrator\Strategy;

use Zend\Hydrator\Strategy\StrategyInterface;
use Zend\Http\Client as HttpClient;
use Doctrine\MongoDB\GridFSFile;
use Organizations\Entity\OrganizationImage as OrganizationImageEntity;

class HttploadStrategy implements StrategyInterface
{
    /**
     * @var $repository \Organizations\Repository\OrganizationImage
     */
    protected $repository;

    /**
     * @param $repository
     */
    public function __construct($repository = null)
    {
        $this->repository = $repository;
        return $this;
    }

    /**
     * @param mixed $value$organizationImageEntity
     *
     * @return mixed
     */
    public function extract($value)
    {
        return $value;
    }

    /**
     * @param mixed $value
     * @param null  $data
     * @param null  $object
     *
     * @return mixed
     */
    public function hydrate($value, $data = null, $object = null)
    {
        $organizationImageEntity = $value;
        // @TODO: has the Object already an Image, than take this

        if (is_string($value)) {
            $client = new HttpClient($value, array('sslverifypeer' => false));
            $response = $client->send();
            $file = new GridFSFile();
            $file->setBytes($response->getBody());

            /* @var OrganizationImageEntity $organizationImageEntity */
            $organizationImageEntity = $this->repository->create();
            $organizationImageEntity->setType($response->getHeaders()->get('Content-Type')->getFieldValue());

            $organizationImageEntity->setFile($file);
        }

        return $organizationImageEntity;
    }
}


<?php

namespace HnhDigital\LaravelFrontendAssetLoader;

use Roumen\Asset\Asset as RoumenAsset;
use Html;

class FrontendAsset
{
    private static $containers = [];

    /**
     * Meta entries.
     *
     * @var array
     */
    private static $meta = [];

    /**
     * The domain for assets.
     *
     * @var string
     */
    protected static $domain;

    /**
     * Set the domain.
     *
     * @param string $domain
     *
     * @return $this
     */
    public function setDomain($domain)
    {
        self::$domain = rtrim($domain, '/');

        return $this;
    }

    /**
     * Get the domain.
     *
     * @return string
     */
    public function getDomain()
    {
        return self::$domain;
    }

    /**
     * Get the version of the given resource.
     *
     * @return string
     */
    public function version($name, $version = false)
    {
        return (empty($version)) ? config('frontend-assets.'.$name.'.1') : $version;
    }

    /**
     * Track loaded inline files.
     *
     * @var array
     */
    private $loaded_inline = [];

    /**
     * Add the asset using our version of the exlixer loader.
     *
     * @param string $file
     * @param string $params
     * @param bool   $onUnknownExtension
     *
     * @return void
     */
    public function add($file, $params = 'footer', $onUnknownExtension = false)
    {
        RoumenAsset::add($this->elixir($file), $params, $onUnknownExtension);
    }

    /**
     * Add raw script to page.
     *
     * @param string $style
     * @param string $params
     *
     * @return void
     */
    public function addScript($script, $params = 'footer')
    {
        RoumenAsset::addScript($script, $params);
    }

    /**
     * Reverse the order of scripts.
     *
     * @param string $params
     *
     * @return void
     */
    public function reverseStylesOrder($params = 'footer')
    {
        if (isset(RoumenAsset::$scripts[$params])) {
            RoumenAsset::$scripts[$params] = array_reverse(RoumenAsset::$scripts[$params], true);
        }
    }

    /**
     * Add raw styling to page.
     *
     * @param string $style
     * @param string $params
     *
     * @return void
     */
    public function addStyle($style, $params = 'header')
    {
        RoumenAsset::addStyle($style, $params);
    }

    /**
     * Add the asset first using our version of the exliser loader.
     *
     * @param string $file
     * @param string $params
     * @param bool   $onUnknownExtension
     *
     * @return return string
     */
    public function addFirst($file, $params = 'footer', $onUnknownExtension = false)
    {
        RoumenAsset::addFirst($this->elixir($file), $params, $onUnknownExtension);
    }

    /**
     * Add new asset after another asset in its array.
     *
     * @param string       $file1
     * @param string       $file2
     * @param string|array $params
     * @param bool         $onUnknownExtension
     *
     * @return void
     */
    public function addAfter($file1, $file2, $params = 'footer', $onUnknownExtension = false)
    {
        RoumenAsset::addAfter($this->elixir($file1), $this->elixir($file2), $params, $onUnknownExtension);
    }

    /**
     * Add a meta attribute.
     *
     * @return void
     */
    public function addMeta($meta, $data = [])
    {
        if (is_string($meta)) {
            $meta = [$meta => $data];
        }

        foreach ($meta as $key => $data) {
            self::$meta[$key] = $data;
        }
    }

    /**
     * Return meta.
     *
     * @return array
     */
    public function meta()
    {
        foreach(self::$meta as $name => $attributes) {
            echo Html::meta()
                ->name(array_has($attributes, 'config.noname') ? false : $name)
                ->addAttributes(array_except($attributes, ['config']));
            echo "\n";
        }
    }

    /**
     * Return CSS.
     *
     * @param array $arguments
     *
     * @return void
     */
    public function css(...$arguments)
    {
        return RoumenAsset::css(...$arguments);
    }

    /**
     * Return LESS.
     *
     * @param array $arguments
     *
     * @return string
     */
    public function less(...$arguments)
    {
        return RoumenAsset::less(...$arguments);
    }

    /**
     * Return styles.
     *
     * @param array $arguments
     *
     * @return string
     */
    public function styles(...$arguments)
    {
        return RoumenAsset::styles(...$arguments);
    }

    /**
     * Return javascript.
     *
     * @param array $arguments
     *
     * @return string
     */
    public function js(...$arguments)
    {
        return RoumenAsset::js(...$arguments);
    }

    /**
     * Return scripts.
     *
     * @param array $arguments
     *
     * @return string
     */
    public function scripts(...$arguments)
    {
        return RoumenAsset::scripts(...$arguments);
    }

    /**
     * Add a package.
     *
     * @param array $container_settings
     * @param array $config
     *
     * @return void
     */
    public static function package($container_settings, $config = [])
    {
        self::loadContainer($container_settings, $config);
    }

    /**
     * Add new asset after another asset in its array.
     *
     * @param array $container_settings
     *
     * @return void
     */
    public static function container($container_settings, $config = [])
    {
        self::loadContainer($container_settings, $config);
    }

    /**
     * Load an assets container (it will load the individual files).
     *
     * @param array $arguments
     *
     * @return void
     */
    public function containers(...$arguments)
    {
        if (isset($arguments[0])) {
            $container_list = $arguments[0];
            foreach ($container_list as $container_settings) {
                $this->loadContainer($container_settings);
            }
        }
    }

    /**
     * Load an assets container (it will load the individual files).
     *
     * @param array $asset_settings
     *
     * @return void
     */
    private static function loadContainer($class_settings, $config = [])
    {
        if (is_array($class_settings)) {
            $asset_name = array_shift($class_settings);
        } else {
            $asset_name = $class_settings;
            $class_settings = [];
        }

        $class_name = false;

        if ($asset_details = config('frontend-assets.'.$asset_name, false)) {
            $class_name = array_get($asset_details, 0, false);
        }

        if ($class_name !== false && !isset(self::$containers[$class_name]) && class_exists($class_name)) {
            self::$containers[$class_name] = new $class_name(...$class_settings);
        }

        if (!empty($config) && method_exists(self::$containers[$class_name], 'config')) {
            if (!is_array($config)) {
                $config = [$config];
            }
            self::$containers[$class_name]->config(...$config);
        }
    }

    /**
     * Load local files for a given controller.
     *
     * @param array  $file_extensions
     * @param string $file
     *
     * @return void
     */
    public function controller($file_extensions, $file)
    {
        // Only look in a single file extension folder.
        if (!is_array($file_extensions)) {
            $file_extensions = [$file_extensions];
        }

        // Replace dots with slashes.
        $file = str_replace('.', '/', $file);

        if (substr($file, -1) === '*') {
            $folder = dirname(substr($file, 0, -1));
            $base_folder = basename(substr($file, 0, -1));

            foreach ($file_extensions as $extension) {
                $extension_folder = $folder.'/'.$extension.'/'.$base_folder;
                $folder_contents = scandir(resource_path().'/views/'.$extension_folder);

                foreach ($folder_contents as $folder_file) {
                    if ($folder_file == '.' || $folder_file == '..') {
                        continue;
                    }

                    $full_path = resource_path().'/views/'.$extension_folder.'/'.$folder_file;
                    $file_name = $extension_folder.'/'.$folder_file;

                    $this->loadFile($file_name, $extension, $full_path);
                }
            }

            return;
        }

        // Go through each file extension folder.
        foreach ($file_extensions as $extension) {
            $file_name = $file.'.'.$extension;

            $local_file_path = dirname(resource_path().'/views/'.$file_name);
            $local_file_path .= '/'.$extension.'/'.basename($file_name);

            $full_path = '';

            if (env('APP_ENV') == 'local') {
                if (file_exists($local_file_path)) {
                    $full_path = $local_file_path;
                } else {
                    $full_path = public_path().'/assets/'.$file_name;
                }
            }

            $this->loadFile($file_name, $extension, $full_path);
        }
    }

    /**
     * Load a file.
     *
     * @param string $file_name
     * @param string $extension
     * @param string $full_path
     *
     * @return void
     */
    public function loadFile($file_name, $extension, $full_path = '')
    {
        if (array_has(config('rev-manifest', []), $file_name) || (!empty($full_path) && file_exists($full_path))) {
            if (env('APP_ASSET_INLINE', false)) {
                if (!isset($this->loaded_inline[$full_path])) {
                    $contents = file_get_contents($full_path);
                    $contents = '/* '.$file_name." */ \n\n".$contents;
                    if ($extension == 'js') {
                        $this->addScript($contents, 'inline');
                    } else {
                        $this->addStyle($contents);
                    }
                    $this->loaded_inline[$full_path] = true;
                }
            } else {
                $this->add($file_name, 'ready');
            }
        }
    }

    /**
     * Override standard elixir to return standard url if
     * the exception is made (eg the file isn't versioned).
     *
     * @param string $file
     *
     * @return return string
     */
    public function elixir($file)
    {
        if (substr($file, 0, 4) === 'http') {
            return $file;
        }

        try {
            if (env('APP_ASSET_SOURCE', 'build') === 'build') {
                $elixir_path = elixir($file);

                return $elixir_path;
            }

            return '/'.env('APP_ASSET_SOURCE').'/'.$file;
        } catch (\InvalidArgumentException $e) {
            if (file_exists(public_path().'/'.$file)) {
                return $file;
            } elseif (file_exists(public_path().'/assets/'.$file)) {
                return '/assets/'.$file;
            }
        }

        return '';
    }

    public static function http2()
    {
        foreach (RoumenAsset::$css as $file) {
            header('Link: <'.$file.'>; rel=preload; as=style;', false);
        }
        foreach (RoumenAsset::$js as $section) {
            foreach ($section as $file) {
                header('Link: <'.$file.'>; rel=preload; as=script;', false);
            }
        }
    }
}


<?php
/**
 * YAWIK
 *
 * @copyright (c) 2013 - 2016 Cross Solution (http://cross-solution.de)
 * @license   MIT
 */

namespace Organizations\Repository\Filter;

use Auth\AuthenticationService;
use Auth\Entity\UserInterface;
use Core\Repository\Filter\AbstractPaginationQuery;
use Jobs\Entity\StatusInterface;
use Organizations\Entity\Organization;
use Jobs\Repository\Job as JobRepository;
use Zend\Stdlib\Parameters;

/**
 * maps query parameters to entity attributes
 *
 * @package Organizations
 * @author Mathias Weitz <weitz@cross-solution.de>
 * @author Anthonius Munthi <me@itstoni.com>
 */
class PaginationQuery extends AbstractPaginationQuery
{
    const PAGE_TYPE_PROFILE = 'profile';
    const PAGE_TYPE_LIST    = 'list';

    /**
     * Repository to query
     *
     * @var String
     */
    protected $repositoryName="Organizations/Organization";

    /**
     * Sortable fields
     *
     * @var array
     */
    protected $sortPropertiesMap = array(
        'date' => 'dateCreated.date',
    );

    /**
     * @var JobRepository
     */
    protected $jobRepository;

    /**
     * @var AuthenticationService
     */
    private $authService;

    /**
     * Constructs pagination query.
     *
     * @param JobRepository         $jobRepository
     * @param AuthenticationService $auth
     */
    public function __construct(
        JobRepository $jobRepository,
        AuthenticationService $auth
    ) {
        $this->jobRepository = $jobRepository;
        $this->authService = $auth;
    }

    /**
     * Creates a query for filtering organizations
     *
     * @see \Core\Repository\Filter\AbstractPaginationQuery::createQuery()
     * @param $params
     * @param \Doctrine\ODM\MongoDB\Query\Builder $queryBuilder
     * @return mixed
     */
    public function createQuery($params, $queryBuilder)
    {
        if ($params instanceof Parameters) {
            $value = $params->toArray();
        } else {
            $value = $params;
        }

        /*
         * if user is recruiter or admin
         * filter query based on permissions.view
         */
        $auth = $this->authService;
        $user = $auth->getUser();
        $ignored = [null,'guest',UserInterface::ROLE_USER];
        if (!in_array($user->getRole(), $ignored)) {
            $queryBuilder->field('permissions.view')->equals($user->getId());
        }

        if (isset($params['q']) && $params['q'] && $params['q'] != 'en/organizations/profile') {
            $queryBuilder->text($params['q'])->language('none');
        }

        if (!isset($value['sort'])) {
            $value['sort'] = '-date';
        }

        $queryBuilder->sort($this->filterSort($value['sort']));

        if (isset($params['type']) && $params['type'] === 'profile') {
            //@TODO: we should use aggregate query here
            $queryBuilder->field('profileSetting')
                ->in([Organization::PROFILE_ALWAYS_ENABLE,Organization::PROFILE_ACTIVE_JOBS])
            ;

            $filters = $this->getOrganizationProfileFilters($queryBuilder);
            if (count($filters) > 0) {
                $queryBuilder->field('id')->notIn($filters);
            }
        }

        return $queryBuilder;
    }

    /**
     * @param \Doctrine\ODM\MongoDB\Query\Builder $queryBuilder $queryBuilder
     * @return array
     */
    private function getOrganizationProfileFilters($queryBuilder)
    {
        /* @var \Organizations\Entity\Organization $organization */
        $jobRepository = $this->jobRepository;
        $results = $queryBuilder->getQuery()->execute();

        $filters = [];
        foreach ($results->toArray() as $organization) {
            if ($organization->getProfileSetting()==Organization::PROFILE_ACTIVE_JOBS) {
                $qb = $jobRepository->createQueryBuilder();
                $qb
                    ->field('organization')->equals($organization->getId())
                    ->field('status.name')->notIn([StatusInterface::EXPIRED, StatusInterface::INACTIVE])
                    ->field('isDraft')->notEqual(true)
                ;
                $count = $qb->getQuery()->execute()->count();
                if ($count == 0) {
                    $filters[] = $organization->getId();
                }
            }
        }

        return $filters;
    }
}


<?php

/**
 * YAWIK
 *
 * @filesource
 * @license MIT
 * @copyright  2013 - 2017 Cross Solution <http://cross-solution.de>
 */

namespace Organizations\Repository\Filter;

use Core\Repository\Filter\AbstractPaginationQuery;
use Doctrine\ODM\MongoDB\Query\Builder;
use Interop\Container\ContainerInterface;
use Jobs\Entity\Job;
use Jobs\Entity\Status;

/**
 * Class ListJobQuery
 *
 * @author Anthonius Munthi <me@itstoni.com>
 * @package Organizations\Repository\Filter
 * @since 0.30
 */
class ListJobQuery extends AbstractPaginationQuery
{
    protected $repositoryName = 'Jobs/Job';

    /**
     * @param   array   $params
     * @param   Builder $queryBuilder
     *
     * @return Builder|mixed
     */
    public function createQuery($params, $queryBuilder)
    {
        $queryBuilder
            ->field('organization')
            ->equals($params['organization_id'])
        ;
        $queryBuilder->field('status.name')->in([
            Status::ACTIVE,
            Status::PUBLISH
        ]);
        $queryBuilder->field('isDraft')->equals(false);
        return $queryBuilder;
    }
}


<?php
/**
 * YAWIK
 *
 * @filesource
 * @license    MIT
 * @copyright  2013 - 2016 Cross Solution <http://cross-solution.de>
 */

/** */
namespace Organizations\Controller\Plugin;

use Auth\Repository\User as UserRepository;
use Auth\Service\UserUniqueTokenGenerator;
use Core\Controller\Plugin\Mailer;
use Core\Exception\MissingDependencyException;
use Zend\I18n\Translator\Translator;
use Zend\Mvc\Controller\Plugin\AbstractPlugin;
use Zend\Validator\EmailAddress;

/**
 * Handles invitation of users / employees.
 *
 * - Creates a new user draft, if necessary.
 * - Sends the invitation mail.
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @since  0.19
 */
class InvitationHandler extends AbstractPlugin
{

    /**
     * Translator
     *
     * @var Translator
     */
    protected $translator;

    /**
     * Email address validator
     *
     * @var EmailAddress
     */
    protected $emailValidator;

    /**
     * User repository
     *
     * @var UserRepository
     */
    protected $userRepository;

    /**
     * User token generator
     *
     * @var UserUniqueTokenGenerator
     */
    protected $userTokenGenerator;

    /**
     * Mailer plugin
     *
     * @var Mailer
     */
    protected $mailerPlugin;

    /**
     * Gets the translator
     *
     * @return \Zend\I18n\Translator\Translator
     * @throws MissingDependencyException
     */
    public function getTranslator()
    {
        if (!$this->translator) {
            throw new MissingDependencyException('\Zend\I18n\Translator\Translator', $this);
        }

        return $this->translator;
    }

    /**
     * Sets the translator
     *
     * @param \Zend\I18n\Translator\Translator $translator
     *
     * @return self
     */
    public function setTranslator($translator)
    {
        $this->translator = $translator;

        return $this;
    }

    /**
     * Gets the email validator.
     *
     * @return \Zend\Validator\EmailAddress
     * @throws MissingDependencyException
     */
    public function getEmailValidator()
    {
        if (!$this->emailValidator) {
            throw new MissingDependencyException('\Zend\Validate\EmailAddress', $this);
        }

        return $this->emailValidator;
    }

    /**
     * Sets the email validator.
     *
     * @param \Zend\Validator\EmailAddress $emailValidator
     *
     * @return self
     */
    public function setEmailValidator($emailValidator)
    {
        $this->emailValidator = $emailValidator;

        return $this;
    }

    /**
     * Gets the user repository.
     *
     * @return \Auth\Repository\User
     * @throws MissingDependencyException
     */
    public function getUserRepository()
    {
        if (!$this->userRepository) {
            throw new MissingDependencyException('\Auth\Repository\User', $this);
        }

        return $this->userRepository;
    }

    /**
     * Sets the user repository.
     *
     * @param \Auth\Repository\User $userRepository
     *
     * @return self
     */
    public function setUserRepository($userRepository)
    {
        $this->userRepository = $userRepository;

        return $this;
    }

    /**
     * Gets the user token generator.
     *
     * @return \Auth\Service\UserUniqueTokenGenerator
     * @throws MissingDependencyException
     */
    public function getUserTokenGenerator()
    {
        if (!$this->userTokenGenerator) {
            throw new MissingDependencyException('\Auth\Service\UserUniqueTokenGenerator', $this);
        }

        return $this->userTokenGenerator;
    }

    /**
     * Sets the user token generator.
     *
     * @param \Auth\Service\UserUniqueTokenGenerator $userTokenGenerator
     *
     * @return self
     */
    public function setUserTokenGenerator($userTokenGenerator)
    {
        $this->userTokenGenerator = $userTokenGenerator;

        return $this;
    }

    /**
     * Gets the mailer plugin.
     *
     * @return \Core\Controller\Plugin\Mailer
     * @throws MissingDependencyException
     */
    public function getMailerPlugin()
    {
        if (!$this->mailerPlugin) {
            throw new MissingDependencyException('\Core\Controller\Plugin\Mailer', $this);
        }

        return $this->mailerPlugin;
    }

    /**
     * Sets the mailer plugin.
     *
     * @param \Core\Controller\Plugin\Mailer $mailerPlugin
     *
     * @return self
     */
    public function setMailerPlugin(Mailer $mailerPlugin)
    {
        $this->mailerPlugin = $mailerPlugin;

        return $this;
    }

    /**
     * Processes the invitation of an user by an organization owner.
     *
     * Validators the email address, loads or creates the user and finallly sends
     * the mail.
     *
     * The return value is meant to be used as an array of variables passed to a
     * ViewModelInterface instance.
     *
     * @param string $email
     *
     * @return array
     */
    public function process($email)
    {
        $translator = $this->getTranslator();

        if (!$this->validateEmail($email)) {
            return array(
                'ok'      => false,
                'message' => $translator->translate('Email address is invalid.')
            );
        }

        $userAndToken = $this->loadOrCreateUser($email);

        try {
            $mailer = $this->getMailerPlugin();
            $mailer('Organizations/InviteEmployee', $userAndToken, true);
        } catch (\Exception $e) {
            return array(
                'ok'      => false,
                'message' => $translator->translate(trim('Sending invitation mail failed. '.$e->getMessage()))
            );
        }

        $user = $userAndToken['user'];

        /* @var $user \Auth\Entity\User
         * @var $info \Auth\Entity\InfoInterface
         */

        $info = $user->getInfo();

        return array(
            'ok'     => true,
            'result' => array(
                'userId'    => $user->getId(),
                'userName'  => $info->getDisplayName(),
                'userEmail' => $email
            )
        );
    }

    /**
     * Validates an email address.
     *
     * @param string $email
     *
     * @return bool
     */
    protected function validateEmail($email)
    {
        if (!$email) {
            return false;
        }

        $validator = $this->getEmailValidator();

        return $validator->isValid($email);
    }

    /**
     * Loads or creates an user.
     *
     * Tries to load an user from the database, and creates a new
     * user draft, if no user was found.
     * A token will be generated to authenticate this user in further interactions
     * (with other parts of this application).
     *
     * @param string $email
     *
     * @return array An array with the keys 'user' and 'token', where 'user' is an UserInterface instance and
     *               'token' is the generated token.
     */
    protected function loadOrCreateUser($email)
    {
        $repository = $this->getUserRepository();
        $generator  = $this->getUserTokenGenerator();

        /* @var $user \Auth\Entity\User */
        $user = $repository->findByEmail(
            $email, /*do not check isDraft flag */
            null
        );

        if (!$user) {
            $user = $repository->create();
            $user->setEmail($email)
                 ->setLogin($email)
                 ->setRole(\Auth\Entity\User::ROLE_RECRUITER)
                 ->setIsDraft(true);
            $info = $user->getInfo();
            /* @var $info \Auth\Entity\InfoInterface */
            $info->setEmail($email);
        }

        $token = $generator->generate(
            $user, /* daysToLive */
            7
        ); // will store user!

        return array('user' => $user, 'token' => $token);
    }
}


<?php
/**
 * YAWIK
 *
 * @filesource
 * @license MIT
 * @copyright  2013 - 2016 Cross Solution <http://cross-solution.de>
 */

/** */
namespace Organizations\Entity;

use Auth\Entity\UserInterface;
use Core\Entity\EntityInterface;
use Core\Entity\PermissionsInterface;
use Doctrine\Common\Collections\Collection;
use Organizations\Repository\Organization as OrganizationRepository;
use Zend\Hydrator\HydratorInterface;

/**
 * Manages reference to an organization.
 *
 * As OrganizationInterface is also implemented (and all methods are proxied to the "real" organization
 * object), this class can be used as an organization.
 *
 * @author Mathias Gelhausen <gelhausen@cross-solution.de>
 * @todo update test
 */
class OrganizationReference implements
    OrganizationInterface,
    OrganizationReferenceInterface
{
    /*
     * Note: We start property names with an underscore to prevent
     * name collisions with the OrganizationInterface.
     */

    /**
     * The user id of the parent document.
     *
     * @var string
     */
    protected $_userId;

    /**
     * The organization repository.
     *
     * @var \Organizations\Repository\Organization
     */
    protected $_repository;

    /**
     * The organization
     *
     * @var Organization
     */
    protected $_organization;

    /**
     * Reference type.
     *
     * @internal
     *      Initial value is null, so we can determine in {@link load()} if it has already run once.
     *
     * @var string
     */
    protected $_type;

    /**
     * Creates an instance.
     *
     * @param string                 $userId
     * @param OrganizationRepository $repository
     */
    public function __construct($userId, OrganizationRepository $repository)
    {
        $this->_userId = $userId;
        $this->_repository = $repository;
    }

    public function isOwner()
    {
        $this->load();

        return self::TYPE_OWNER == $this->_type;
    }

    public function isEmployee()
    {
        $this->load();

        return self::TYPE_EMPLOYEE == $this->_type;
    }

    public function hasAssociation()
    {
        $this->load();

        return self::TYPE_NONE != $this->_type;
    }

    public function getOrganization()
    {
        $this->load();

        return $this->_organization;
    }

    /**
     * Loads the organization from the database and sets the reference type.
     */
    protected function load()
    {
        if (null !== $this->_type) {
            return;
        }

        // Is the user the owner of the referenced organization?
        $org = $this->_repository->findByUser($this->_userId);

        if ($org) {
            $this->_type = self::TYPE_OWNER;
            $this->_organization = $org;

            return;
        }

        // Is the user employed by the referenced organization?
        $org = $this->_repository->findByEmployee($this->_userId);

        if ($org) {
            $this->_type = self::TYPE_EMPLOYEE;
            $this->_organization = $org;

            return;
        }

        // It seems the user is not associated with an organization.
        $this->_type = self::TYPE_NONE;
    }

    /**
     * Executes a proxy call to the associated organization entity.
     *
     * Does nothing, if no organization is available.
     *
     * Call it like:
     * <pre>
     *   $this->proxy($method[, $arg1[, $arg2[, ...]]]);
     * </pre>
     *
     * @param $method
     *
     * @return self|mixed
     */
    protected function proxy($method)
    {
        if (!$this->hasAssociation()) {
            return $this;
        }

        $args = array_slice(func_get_args(), 1);

        $return = call_user_func_array(array($this->_organization, $method), $args);

        return ($return === $this->_organization) ? $this : $return;
    }

    /*
     * We need to implement each method of OrganizationInterface because we want to proxy
     * to a concrete instance of Organization and therefor cannot simply extend.
     */

    /**#@+
     * Proxies to the concrete Organization instance.
     *
     * {@inheritDoc}
     */

    public function __get($property)
    {
        return $this->proxy('__get', $property);
    }

    public function __set($property, $value)
    {
        return $this->proxy('__set', $property, $value);
    }

    public function __isset($property)
    {
        return $this->proxy('__isset', $property);
    }

    public function notEmpty($property, array $args=[])
    {
        return $this->proxy('notEmpty', $args);
    }

    public function hasProperty($property, $mode = self::PROPERTY_STRICT)
    {
        return $this->proxy('hasProperty', $mode);
    }

    public function setHydrator(HydratorInterface $hydrator)
    {
        return $this->proxy('setHydrator', $hydrator);
    }

    public function getHydrator()
    {
        return $this->proxy('getHydrator');
    }

    public function setId($id)
    {
        return $this->proxy('setId', $id);
    }

    public function getId()
    {
        return $this->proxy('getId');
    }

    public function setDateCreated($date)
    {
        return $this->proxy('setDateCreated', $date);
    }

    public function getDateCreated()
    {
        return $this->proxy('getDateCreated');
    }

    public function setDateModified($date)
    {
        return $this->proxy('setDateModified', $date);
    }

    public function getDateModified()
    {
        return $this->proxy('getDateModified');
    }

    public function setParent(OrganizationInterface $parent)
    {
        return $this->proxy('setParent', $parent);
    }

    public function getParent($returnSelf = false)
    {
        return $this->proxy('getParent', $returnSelf);
    }

    public function setContact(EntityInterface $contact = null)
    {
        return $this->proxy('setContact', $contact);
    }

    public function getContact()
    {
        return $this->proxy('getContact');
    }

    public function isHiringOrganization()
    {
        return $this->proxy('isHiringOrganization');
    }

    public function getHiringOrganizations()
    {
        return $this->proxy('getHiringOrganizations');
    }

    public function setImage(OrganizationImage $image)
    {
        return $this->proxy('setImage', $image);
    }

    public function getImage()
    {
        return $this->proxy('getImage');
    }

    public function getImages()
    {
        return $this->proxy('getImages');
    }

    public function setImages(\Core\Entity\ImageSet $images)
    {
        return $this->proxy('setImages', $images);
    }

    public function setOrganizationName(OrganizationName $organizationNames)
    {
        return $this->proxy('setOrganizationName', $organizationNames);
    }

    public function getOrganizationName()
    {
        return $this->proxy('getOrganizationName');
    }

    public function getDescription()
    {
        return $this->proxy('getDescription');
    }

    public function setDescription($description)
    {
        return $this->proxy('setDescription', $description);
    }

    public function setEmployees(Collection $employees)
    {
        return $this->proxy('setEmployees', $employees);
    }

    public function getEmployees()
    {
        return $this->proxy('getEmployees');
    }

    public function getEmployeesByRole($role)
    {
        return $this->proxy('getEmployeesByRole', $role);
    }

    public function getEmployee($userOrId)
    {
        return $this->proxy('getEmployee', $userOrId);
    }

    public function setExternalId($externalId)
    {
        return $this->proxy('setExternalId', $externalId);
    }

    public function getExternalId()
    {
        return $this->proxy('getExternalId');
    }

    public function getUser()
    {
        return $this->proxy('getUser');
    }

    public function setUser(UserInterface $user)
    {
        $this->_type = null; // force reload of references!
        return $this->proxy('setUser', $user);
    }

    public function getJobs()
    {
        return $this->proxy('getJobs');
    }

    public function getPermissions()
    {
        return $this->proxy('getPermissions');
    }

    public function setPermissions(PermissionsInterface $permissions)
    {
        return $this->proxy('setPermissions', $permissions);
    }

    public function getPermissionsResourceId()
    {
        return $this->proxy('getPermissionsResourceId');
    }

    public function getPermissionsUserIds($type = null)
    {
        return $this->proxy('getPermissionsUSerIds', $type);
    }

    public function getSearchableProperties()
    {
        return $this->proxy('getSearchableProperties');
    }

    public function setKeywords(array $keywords)
    {
        return $this->proxy('setKeywords', $keywords);
    }

    public function clearKeywords()
    {
        return $this->proxy('clearKeywords');
    }

    public function getTemplate()
    {
        return $this->proxy('getTemplate');
    }

    public function setTemplate(TemplateInterface $template)
    {
        return $this->proxy('setTemplate', $template);
    }

    public function getWorkflowSettings()
    {
        return $this->proxy('getWorkflowSettings');
    }

    public function setWorkflowSettings($workflowSettings)
    {
        return $this->proxy('setWorkflowSettings', $workflowSettings);
    }

    /**#@-*/
}