<commit_before><?php namespace Digbang\Security;

use Digbang\Doctrine\Metadata\DecoupledMappingDriver;
use Digbang\Doctrine\Metadata\EntityMapping;
use Digbang\Security\Configurations\SecurityContextConfiguration;
use Digbang\Security\Contracts\SecurityApi;
use Digbang\Security\Factories\SecurityFactory;
use Digbang\Security\Mappings\CustomTableMapping;
use Digbang\Security\Permissions\PermissionStrategyEventListener;
use Digbang\Security\Urls\PermissionAwareUrlGeneratorExtension;
use Doctrine\ORM\EntityManagerInterface;
use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Routing\UrlGenerator as UrlGeneratorContract;
use Illuminate\Routing\UrlGenerator;
use Illuminate\Http\Request;

class SecurityContext
{
	/**
	 * @type Container
	 */
	private $container;

	/**
	 * Configured contexts
	 * @type array
	 */
	private $contexts = [];

	/**
	 * Flyweight Security instances.
	 * @type array
	 */
	private $instances = [];

	/**
	 * Flyweight dependencies.
	 * @type array
	 */
	private $dependencies = [];

	/**
	 * SecurityContext constructor.
	 *
	 * @param Container $container
	 */
	public function __construct(Container $container)
	{
		$this->container = $container;
	}

	/**
	 * Add a security context.
	 *
	 * @param SecurityContextConfiguration $configuration
	 * @throws \BadMethodCallException
	 */
	public function add(SecurityContextConfiguration $configuration)
	{
		$this->contexts[$configuration->getName()] = $configuration;

		$this->updateMappings($configuration);
	}

	/**
	 * Bind the given security context to the Request and Container.
	 *
	 * @param string  $context
	 * @param Request $request
	 */
	public function bindContext($context, Request $request)
	{
		$security = $this->getSecurity($context);

		$this->container->instance(SecurityApi::class, $security);

	    $this->container->bind(UrlGeneratorContract::class, function() use ($security){
		    return $security->url();
	    });

	    $this->container->bind([UrlGenerator::class => 'url'], function(Container $container) use ($security){
		    /** @type PermissionAwareUrlGeneratorExtension $url */
		    $url = $container->make(PermissionAwareUrlGeneratorExtension::class);
		    $url->setUrlGenerator($security->url());

		    return $url;
	    });

		$request->setUserResolver(function() use ($security){
            return $security->getUser();
        });

		$this->addPermissionsFactoryListener($context);
	}

	/**
	 * Get the Security instance for the given context.
	 *
	 * @param string $context
	 * @return Security
	 */
	public function getSecurity($context)
	{
		if (array_key_exists($context, $this->instances))
		{
			return $this->instances[$context];
		}

		$configuration = $this->getConfigurationFor($context);

		return $this->instances[$context] = $this->getSecurityFactory()->create($context, $configuration);
	}

	/**
	 * @param $context
	 * @return SecurityContextConfiguration
	 */
	public function getConfigurationFor($context)
	{
		if (! array_key_exists($context, $this->contexts))
		{
			throw new \InvalidArgumentException("Context [$context] is not configured.");
		}

		return $this->contexts[$context];
	}

	/**
	 * @param SecurityContextConfiguration $configuration
	 * @throws \BadMethodCallException
	 */
	private function updateMappings(SecurityContextConfiguration $configuration)
	{
		$mappings = $configuration->getMappings();

		if (! $configuration->isRolesEnabled())
		{
			$this->validateAndCall($mappings['user'], 'disableRoles');
		}<commit_msg>Prevent races between binding the event listener and obtaining the security API<commit_after><?php namespace Digbang\Security;

use Digbang\Doctrine\Metadata\DecoupledMappingDriver;
use Digbang\Doctrine\Metadata\EntityMapping;
use Digbang\Security\Configurations\SecurityContextConfiguration;
use Digbang\Security\Contracts\SecurityApi;
use Digbang\Security\Factories\SecurityFactory;
use Digbang\Security\Mappings\CustomTableMapping;
use Digbang\Security\Permissions\PermissionStrategyEventListener;
use Digbang\Security\Urls\PermissionAwareUrlGeneratorExtension;
use Doctrine\ORM\EntityManagerInterface;
use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Routing\UrlGenerator as UrlGeneratorContract;
use Illuminate\Routing\UrlGenerator;
use Illuminate\Http\Request;

class SecurityContext
{
	/**
	 * @type Container
	 */
	private $container;

	/**
	 * Configured contexts
	 * @type array
	 */
	private $contexts = [];

	/**
	 * Flyweight Security instances.
	 * @type array
	 */
	private $instances = [];

	/**
	 * Flyweight dependencies.
	 * @type array
	 */
	private $dependencies = [];

	/**
	 * SecurityContext constructor.
	 *
	 * @param Container $container
	 */
	public function __construct(Container $container)
	{
		$this->container = $container;
	}

	/**
	 * Add a security context.
	 *
	 * @param SecurityContextConfiguration $configuration
	 * @throws \BadMethodCallException
	 */
	public function add(SecurityContextConfiguration $configuration)
	{
		$this->contexts[$configuration->getName()] = $configuration;

		$this->updateMappings($configuration);
	}

	/**
	 * Bind the given security context to the Request and Container.
	 *
	 * @param string  $context
	 * @param Request $request
	 */
	public function bindContext($context, Request $request)
	{
		$security = $this->getSecurity($context);

		$this->container->instance(SecurityApi::class, $security);

	    $this->container->bind(UrlGeneratorContract::class, function() use ($security){
		    return $security->url();
	    });

	    $this->container->bind([UrlGenerator::class => 'url'], function(Container $container) use ($security){
		    /** @type PermissionAwareUrlGeneratorExtension $url */
		    $url = $container->make(PermissionAwareUrlGeneratorExtension::class);
		    $url->setUrlGenerator($security->url());

		    return $url;
	    });

		$request->setUserResolver(function() use ($security){
            return $security->getUser();
        });
	}

	/**
	 * Get the Security instance for the given context.
	 *
	 * @param string $context
	 * @return Security
	 */
	public function getSecurity($context)
	{
		if (array_key_exists($context, $this->instances))
		{
			return $this->instances[$context];
		}

		$configuration = $this->getConfigurationFor($context);
		$this->addPermissionsFactoryListener($context);
		
		return $this->instances[$context] = $this->getSecurityFactory()->create($context, $configuration);
	}

	/**
	 * @param $context
	 * @return SecurityContextConfiguration
	 */
	public function getConfigurationFor($context)
	{
		if (! array_key_exists($context, $this->contexts))
		{
			throw new \InvalidArgumentException("Context [$context] is not configured.");
		}

		return $this->contexts[$context];
	}

	/**
	 * @param SecurityContextConfiguration $configuration
	 * @throws \BadMethodCallException
	 */
	private function updateMappings(SecurityContextConfiguration $configuration)
	{
		$mappings = $configuration->getMappings();

		if (! $configuration->isRolesEnabled())
		{
			$this->validateAndCall($mappings['user'], 'disableRoles');
		}
{'fraction_non_alphanumeric': 0.1331072488342518, 'fraction_numerical': 0.0, 'mean_word_length': 4.630867143993636, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 63, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3792899', 'n_tokens_mistral': 2106, 'n_tokens_neox': 1929, 'n_words': 401}