Server IP : 213.176.29.180 / Your IP : 18.191.103.29 Web Server : Apache System : Linux 213.176.29.180.hostiran.name 4.18.0-553.22.1.el8_10.x86_64 #1 SMP Tue Sep 24 05:16:59 EDT 2024 x86_64 User : webtaragh ( 1001) PHP Version : 7.4.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON Directory (0750) : /home/webtaragh/public_html/whmcs/feeds/../../ |
[ Home ] | [ C0mmand ] | [ Upload File ] |
---|
events/EventServiceProvider.php 0000644 00000001054 14736103231 0012676 0 ustar 00 <?php namespace Illuminate\Events; use Illuminate\Contracts\Queue\Factory as QueueFactoryContract; use Illuminate\Support\ServiceProvider; class EventServiceProvider extends ServiceProvider { /** * Register the service provider. * * @return void */ public function register() { $this->app->singleton('events', function ($app) { return (new Dispatcher($app))->setQueueResolver(function () use ($app) { return $app->make(QueueFactoryContract::class); }); }); } } events/CallQueuedListener.php 0000644 00000006543 14736103231 0012323 0 ustar 00 <?php namespace Illuminate\Events; use Illuminate\Container\Container; use Illuminate\Contracts\Queue\Job; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Queue\InteractsWithQueue; class CallQueuedListener implements ShouldQueue { use InteractsWithQueue; /** * The listener class name. * * @var string */ public $class; /** * The listener method. * * @var string */ public $method; /** * The data to be passed to the listener. * * @var array */ public $data; /** * The number of times the job may be attempted. * * @var int */ public $tries; /** * The number of seconds to wait before retrying the job. * * @var int */ public $retryAfter; /** * The timestamp indicating when the job should timeout. * * @var int */ public $timeoutAt; /** * The number of seconds the job can run before timing out. * * @var int */ public $timeout; /** * Create a new job instance. * * @param string $class * @param string $method * @param array $data * @return void */ public function __construct($class, $method, $data) { $this->data = $data; $this->class = $class; $this->method = $method; } /** * Handle the queued job. * * @param \Illuminate\Container\Container $container * @return void */ public function handle(Container $container) { $this->prepareData(); $handler = $this->setJobInstanceIfNecessary( $this->job, $container->make($this->class) ); call_user_func_array( [$handler, $this->method], $this->data ); } /** * Set the job instance of the given class if necessary. * * @param \Illuminate\Contracts\Queue\Job $job * @param mixed $instance * @return mixed */ protected function setJobInstanceIfNecessary(Job $job, $instance) { if (in_array(InteractsWithQueue::class, class_uses_recursive($instance))) { $instance->setJob($job); } return $instance; } /** * Call the failed method on the job instance. * * The event instance and the exception will be passed. * * @param \Throwable $e * @return void */ public function failed($e) { $this->prepareData(); $handler = Container::getInstance()->make($this->class); $parameters = array_merge($this->data, [$e]); if (method_exists($handler, 'failed')) { call_user_func_array([$handler, 'failed'], $parameters); } } /** * Unserialize the data if needed. * * @return void */ protected function prepareData() { if (is_string($this->data)) { $this->data = unserialize($this->data); } } /** * Get the display name for the queued job. * * @return string */ public function displayName() { return $this->class; } /** * Prepare the instance for cloning. * * @return void */ public function __clone() { $this->data = array_map(function ($data) { return is_object($data) ? clone $data : $data; }, $this->data); } } events/LICENSE.md 0000644 00000002063 14736103231 0007455 0 ustar 00 The MIT License (MIT) Copyright (c) Taylor Otwell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. events/CallQueuedHandler.php 0000644 00000003550 14736103231 0012106 0 ustar 00 <?php namespace Illuminate\Events; use Illuminate\Contracts\Queue\Job; use Illuminate\Contracts\Container\Container; class CallQueuedHandler { /** * The container instance. * * @var \Illuminate\Contracts\Container\Container */ protected $container; /** * Create a new job instance. * * @param \Illuminate\Contracts\Container\Container $container * @return void */ public function __construct(Container $container) { $this->container = $container; } /** * Handle the queued job. * * @param \Illuminate\Contracts\Queue\Job $job * @param array $data * @return void */ public function call(Job $job, array $data) { $handler = $this->setJobInstanceIfNecessary( $job, $this->container->make($data['class']) ); call_user_func_array( [$handler, $data['method']], unserialize($data['data']) ); if (! $job->isDeletedOrReleased()) { $job->delete(); } } /** * Set the job instance of the given class if necessary. * * @param \Illuminate\Contracts\Queue\Job $job * @param mixed $instance * @return mixed */ protected function setJobInstanceIfNecessary(Job $job, $instance) { if (in_array('Illuminate\Queue\InteractsWithQueue', class_uses_recursive(get_class($instance)))) { $instance->setJob($job); } return $instance; } /** * Call the failed method on the job instance. * * @param array $data * @return void */ public function failed(array $data) { $handler = $this->container->make($data['class']); if (method_exists($handler, 'failed')) { call_user_func_array([$handler, 'failed'], unserialize($data['data'])); } } } events/Dispatcher.php 0000644 00000036532 14736103231 0010660 0 ustar 00 <?php namespace Illuminate\Events; use Exception; use Illuminate\Container\Container; use Illuminate\Contracts\Broadcasting\Factory as BroadcastFactory; use Illuminate\Contracts\Broadcasting\ShouldBroadcast; use Illuminate\Contracts\Container\Container as ContainerContract; use Illuminate\Contracts\Events\Dispatcher as DispatcherContract; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Support\Arr; use Illuminate\Support\Str; use Illuminate\Support\Traits\Macroable; use ReflectionClass; class Dispatcher implements DispatcherContract { use Macroable; /** * The IoC container instance. * * @var \Illuminate\Contracts\Container\Container */ protected $container; /** * The registered event listeners. * * @var array */ protected $listeners = []; /** * The wildcard listeners. * * @var array */ protected $wildcards = []; /** * The cached wildcard listeners. * * @var array */ protected $wildcardsCache = []; /** * The queue resolver instance. * * @var callable */ protected $queueResolver; /** * Create a new event dispatcher instance. * * @param \Illuminate\Contracts\Container\Container|null $container * @return void */ public function __construct(ContainerContract $container = null) { $this->container = $container ?: new Container; } /** * Register an event listener with the dispatcher. * * @param string|array $events * @param \Closure|string $listener * @return void */ public function listen($events, $listener) { foreach ((array) $events as $event) { if (Str::contains($event, '*')) { $this->setupWildcardListen($event, $listener); } else { $this->listeners[$event][] = $this->makeListener($listener); } } } /** * Setup a wildcard listener callback. * * @param string $event * @param \Closure|string $listener * @return void */ protected function setupWildcardListen($event, $listener) { $this->wildcards[$event][] = $this->makeListener($listener, true); $this->wildcardsCache = []; } /** * Determine if a given event has listeners. * * @param string $eventName * @return bool */ public function hasListeners($eventName) { return isset($this->listeners[$eventName]) || isset($this->wildcards[$eventName]) || $this->hasWildcardListeners($eventName); } /** * Determine if the given event has any wildcard listeners. * * @param string $eventName * @return bool */ public function hasWildcardListeners($eventName) { foreach ($this->wildcards as $key => $listeners) { if (Str::is($key, $eventName)) { return true; } } return false; } /** * Register an event and payload to be fired later. * * @param string $event * @param array $payload * @return void */ public function push($event, $payload = []) { $this->listen($event.'_pushed', function () use ($event, $payload) { $this->dispatch($event, $payload); }); } /** * Flush a set of pushed events. * * @param string $event * @return void */ public function flush($event) { $this->dispatch($event.'_pushed'); } /** * Register an event subscriber with the dispatcher. * * @param object|string $subscriber * @return void */ public function subscribe($subscriber) { $subscriber = $this->resolveSubscriber($subscriber); $subscriber->subscribe($this); } /** * Resolve the subscriber instance. * * @param object|string $subscriber * @return mixed */ protected function resolveSubscriber($subscriber) { if (is_string($subscriber)) { return $this->container->make($subscriber); } return $subscriber; } /** * Fire an event until the first non-null response is returned. * * @param string|object $event * @param mixed $payload * @return array|null */ public function until($event, $payload = []) { return $this->dispatch($event, $payload, true); } /** * Fire an event and call the listeners. * * @param string|object $event * @param mixed $payload * @param bool $halt * @return array|null */ public function dispatch($event, $payload = [], $halt = false) { // When the given "event" is actually an object we will assume it is an event // object and use the class as the event name and this event itself as the // payload to the handler, which makes object based events quite simple. [$event, $payload] = $this->parseEventAndPayload( $event, $payload ); if ($this->shouldBroadcast($payload)) { $this->broadcastEvent($payload[0]); } $responses = []; foreach ($this->getListeners($event) as $listener) { $response = $listener($event, $payload); // If a response is returned from the listener and event halting is enabled // we will just return this response, and not call the rest of the event // listeners. Otherwise we will add the response on the response list. if ($halt && ! is_null($response)) { return $response; } // If a boolean false is returned from a listener, we will stop propagating // the event to any further listeners down in the chain, else we keep on // looping through the listeners and firing every one in our sequence. if ($response === false) { break; } $responses[] = $response; } return $halt ? null : $responses; } /** * Parse the given event and payload and prepare them for dispatching. * * @param mixed $event * @param mixed $payload * @return array */ protected function parseEventAndPayload($event, $payload) { if (is_object($event)) { [$payload, $event] = [[$event], get_class($event)]; } return [$event, Arr::wrap($payload)]; } /** * Determine if the payload has a broadcastable event. * * @param array $payload * @return bool */ protected function shouldBroadcast(array $payload) { return isset($payload[0]) && $payload[0] instanceof ShouldBroadcast && $this->broadcastWhen($payload[0]); } /** * Check if event should be broadcasted by condition. * * @param mixed $event * @return bool */ protected function broadcastWhen($event) { return method_exists($event, 'broadcastWhen') ? $event->broadcastWhen() : true; } /** * Broadcast the given event class. * * @param \Illuminate\Contracts\Broadcasting\ShouldBroadcast $event * @return void */ protected function broadcastEvent($event) { $this->container->make(BroadcastFactory::class)->queue($event); } /** * Get all of the listeners for a given event name. * * @param string $eventName * @return array */ public function getListeners($eventName) { $listeners = $this->listeners[$eventName] ?? []; $listeners = array_merge( $listeners, $this->wildcardsCache[$eventName] ?? $this->getWildcardListeners($eventName) ); return class_exists($eventName, false) ? $this->addInterfaceListeners($eventName, $listeners) : $listeners; } /** * Get the wildcard listeners for the event. * * @param string $eventName * @return array */ protected function getWildcardListeners($eventName) { $wildcards = []; foreach ($this->wildcards as $key => $listeners) { if (Str::is($key, $eventName)) { $wildcards = array_merge($wildcards, $listeners); } } return $this->wildcardsCache[$eventName] = $wildcards; } /** * Add the listeners for the event's interfaces to the given array. * * @param string $eventName * @param array $listeners * @return array */ protected function addInterfaceListeners($eventName, array $listeners = []) { foreach (class_implements($eventName) as $interface) { if (isset($this->listeners[$interface])) { foreach ($this->listeners[$interface] as $names) { $listeners = array_merge($listeners, (array) $names); } } } return $listeners; } /** * Register an event listener with the dispatcher. * * @param \Closure|string $listener * @param bool $wildcard * @return \Closure */ public function makeListener($listener, $wildcard = false) { if (is_string($listener)) { return $this->createClassListener($listener, $wildcard); } return function ($event, $payload) use ($listener, $wildcard) { if ($wildcard) { return $listener($event, $payload); } return $listener(...array_values($payload)); }; } /** * Create a class based listener using the IoC container. * * @param string $listener * @param bool $wildcard * @return \Closure */ public function createClassListener($listener, $wildcard = false) { return function ($event, $payload) use ($listener, $wildcard) { if ($wildcard) { return call_user_func($this->createClassCallable($listener), $event, $payload); } return call_user_func_array( $this->createClassCallable($listener), $payload ); }; } /** * Create the class based event callable. * * @param string $listener * @return callable */ protected function createClassCallable($listener) { [$class, $method] = $this->parseClassCallable($listener); if ($this->handlerShouldBeQueued($class)) { return $this->createQueuedHandlerCallable($class, $method); } return [$this->container->make($class), $method]; } /** * Parse the class listener into class and method. * * @param string $listener * @return array */ protected function parseClassCallable($listener) { return Str::parseCallback($listener, 'handle'); } /** * Determine if the event handler class should be queued. * * @param string $class * @return bool */ protected function handlerShouldBeQueued($class) { try { return (new ReflectionClass($class))->implementsInterface( ShouldQueue::class ); } catch (Exception $e) { return false; } } /** * Create a callable for putting an event handler on the queue. * * @param string $class * @param string $method * @return \Closure */ protected function createQueuedHandlerCallable($class, $method) { return function () use ($class, $method) { $arguments = array_map(function ($a) { return is_object($a) ? clone $a : $a; }, func_get_args()); if ($this->handlerWantsToBeQueued($class, $arguments)) { $this->queueHandler($class, $method, $arguments); } }; } /** * Determine if the event handler wants to be queued. * * @param string $class * @param array $arguments * @return bool */ protected function handlerWantsToBeQueued($class, $arguments) { $instance = $this->container->make($class); if (method_exists($instance, 'shouldQueue')) { return $instance->shouldQueue($arguments[0]); } return true; } /** * Queue the handler class. * * @param string $class * @param string $method * @param array $arguments * @return void */ protected function queueHandler($class, $method, $arguments) { [$listener, $job] = $this->createListenerAndJob($class, $method, $arguments); $connection = $this->resolveQueue()->connection( $listener->connection ?? null ); $queue = $listener->queue ?? null; isset($listener->delay) ? $connection->laterOn($queue, $listener->delay, $job) : $connection->pushOn($queue, $job); } /** * Create the listener and job for a queued listener. * * @param string $class * @param string $method * @param array $arguments * @return array */ protected function createListenerAndJob($class, $method, $arguments) { $listener = (new ReflectionClass($class))->newInstanceWithoutConstructor(); return [$listener, $this->propagateListenerOptions( $listener, new CallQueuedListener($class, $method, $arguments) )]; } /** * Propagate listener options to the job. * * @param mixed $listener * @param mixed $job * @return mixed */ protected function propagateListenerOptions($listener, $job) { return tap($job, function ($job) use ($listener) { $job->tries = $listener->tries ?? null; $job->retryAfter = method_exists($listener, 'retryAfter') ? $listener->retryAfter() : ($listener->retryAfter ?? null); $job->timeout = $listener->timeout ?? null; $job->timeoutAt = method_exists($listener, 'retryUntil') ? $listener->retryUntil() : null; }); } /** * Remove a set of listeners from the dispatcher. * * @param string $event * @return void */ public function forget($event) { if (Str::contains($event, '*')) { unset($this->wildcards[$event]); } else { unset($this->listeners[$event]); } foreach ($this->wildcardsCache as $key => $listeners) { if (Str::is($event, $key)) { unset($this->wildcardsCache[$key]); } } } /** * Forget all of the pushed listeners. * * @return void */ public function forgetPushed() { foreach ($this->listeners as $key => $value) { if (Str::endsWith($key, '_pushed')) { $this->forget($key); } } } /** * Get the queue implementation from the resolver. * * @return \Illuminate\Contracts\Queue\Queue */ protected function resolveQueue() { return call_user_func($this->queueResolver); } /** * Set the queue resolver implementation. * * @param callable $resolver * @return $this */ public function setQueueResolver(callable $resolver) { $this->queueResolver = $resolver; return $this; } } container/EntryNotFoundException.php 0000644 00000000306 14736103231 0013673 0 ustar 00 <?php namespace Illuminate\Container; use Exception; use Psr\Container\NotFoundExceptionInterface; class EntryNotFoundException extends Exception implements NotFoundExceptionInterface { // } container/Container.php 0000644 00000106634 14736103231 0011173 0 ustar 00 <?php namespace Illuminate\Container; use ArrayAccess; use Closure; use Exception; use Illuminate\Contracts\Container\BindingResolutionException; use Illuminate\Contracts\Container\Container as ContainerContract; use LogicException; use ReflectionClass; use ReflectionException; use ReflectionParameter; class Container implements ArrayAccess, ContainerContract { /** * The current globally available container (if any). * * @var static */ protected static $instance; /** * An array of the types that have been resolved. * * @var bool[] */ protected $resolved = []; /** * The container's bindings. * * @var array[] */ protected $bindings = []; /** * The container's method bindings. * * @var \Closure[] */ protected $methodBindings = []; /** * The container's shared instances. * * @var object[] */ protected $instances = []; /** * The registered type aliases. * * @var string[] */ protected $aliases = []; /** * The registered aliases keyed by the abstract name. * * @var array[] */ protected $abstractAliases = []; /** * The extension closures for services. * * @var array[] */ protected $extenders = []; /** * All of the registered tags. * * @var array[] */ protected $tags = []; /** * The stack of concretions currently being built. * * @var array[] */ protected $buildStack = []; /** * The parameter override stack. * * @var array[] */ protected $with = []; /** * The contextual binding map. * * @var array[] */ public $contextual = []; /** * All of the registered rebound callbacks. * * @var array[] */ protected $reboundCallbacks = []; /** * All of the global resolving callbacks. * * @var \Closure[] */ protected $globalResolvingCallbacks = []; /** * All of the global after resolving callbacks. * * @var \Closure[] */ protected $globalAfterResolvingCallbacks = []; /** * All of the resolving callbacks by class type. * * @var array[] */ protected $resolvingCallbacks = []; /** * All of the after resolving callbacks by class type. * * @var array[] */ protected $afterResolvingCallbacks = []; /** * Define a contextual binding. * * @param array|string $concrete * @return \Illuminate\Contracts\Container\ContextualBindingBuilder */ public function when($concrete) { $aliases = []; foreach (Util::arrayWrap($concrete) as $c) { $aliases[] = $this->getAlias($c); } return new ContextualBindingBuilder($this, $aliases); } /** * Determine if the given abstract type has been bound. * * @param string $abstract * @return bool */ public function bound($abstract) { return isset($this->bindings[$abstract]) || isset($this->instances[$abstract]) || $this->isAlias($abstract); } /** * {@inheritdoc} */ public function has($id) { return $this->bound($id); } /** * Determine if the given abstract type has been resolved. * * @param string $abstract * @return bool */ public function resolved($abstract) { if ($this->isAlias($abstract)) { $abstract = $this->getAlias($abstract); } return isset($this->resolved[$abstract]) || isset($this->instances[$abstract]); } /** * Determine if a given type is shared. * * @param string $abstract * @return bool */ public function isShared($abstract) { return isset($this->instances[$abstract]) || (isset($this->bindings[$abstract]['shared']) && $this->bindings[$abstract]['shared'] === true); } /** * Determine if a given string is an alias. * * @param string $name * @return bool */ public function isAlias($name) { return isset($this->aliases[$name]); } /** * Register a binding with the container. * * @param string $abstract * @param \Closure|string|null $concrete * @param bool $shared * @return void */ public function bind($abstract, $concrete = null, $shared = false) { $this->dropStaleInstances($abstract); // If no concrete type was given, we will simply set the concrete type to the // abstract type. After that, the concrete type to be registered as shared // without being forced to state their classes in both of the parameters. if (is_null($concrete)) { $concrete = $abstract; } // If the factory is not a Closure, it means it is just a class name which is // bound into this container to the abstract type and we will just wrap it // up inside its own Closure to give us more convenience when extending. if (! $concrete instanceof Closure) { $concrete = $this->getClosure($abstract, $concrete); } $this->bindings[$abstract] = compact('concrete', 'shared'); // If the abstract type was already resolved in this container we'll fire the // rebound listener so that any objects which have already gotten resolved // can have their copy of the object updated via the listener callbacks. if ($this->resolved($abstract)) { $this->rebound($abstract); } } /** * Get the Closure to be used when building a type. * * @param string $abstract * @param string $concrete * @return \Closure */ protected function getClosure($abstract, $concrete) { return function ($container, $parameters = []) use ($abstract, $concrete) { if ($abstract == $concrete) { return $container->build($concrete); } return $container->resolve( $concrete, $parameters, $raiseEvents = false ); }; } /** * Determine if the container has a method binding. * * @param string $method * @return bool */ public function hasMethodBinding($method) { return isset($this->methodBindings[$method]); } /** * Bind a callback to resolve with Container::call. * * @param array|string $method * @param \Closure $callback * @return void */ public function bindMethod($method, $callback) { $this->methodBindings[$this->parseBindMethod($method)] = $callback; } /** * Get the method to be bound in class@method format. * * @param array|string $method * @return string */ protected function parseBindMethod($method) { if (is_array($method)) { return $method[0].'@'.$method[1]; } return $method; } /** * Get the method binding for the given method. * * @param string $method * @param mixed $instance * @return mixed */ public function callMethodBinding($method, $instance) { return call_user_func($this->methodBindings[$method], $instance, $this); } /** * Add a contextual binding to the container. * * @param string $concrete * @param string $abstract * @param \Closure|string $implementation * @return void */ public function addContextualBinding($concrete, $abstract, $implementation) { $this->contextual[$concrete][$this->getAlias($abstract)] = $implementation; } /** * Register a binding if it hasn't already been registered. * * @param string $abstract * @param \Closure|string|null $concrete * @param bool $shared * @return void */ public function bindIf($abstract, $concrete = null, $shared = false) { if (! $this->bound($abstract)) { $this->bind($abstract, $concrete, $shared); } } /** * Register a shared binding in the container. * * @param string $abstract * @param \Closure|string|null $concrete * @return void */ public function singleton($abstract, $concrete = null) { $this->bind($abstract, $concrete, true); } /** * Register a shared binding if it hasn't already been registered. * * @param string $abstract * @param \Closure|string|null $concrete * @return void */ public function singletonIf($abstract, $concrete = null) { if (! $this->bound($abstract)) { $this->singleton($abstract, $concrete); } } /** * "Extend" an abstract type in the container. * * @param string $abstract * @param \Closure $closure * @return void * * @throws \InvalidArgumentException */ public function extend($abstract, Closure $closure) { $abstract = $this->getAlias($abstract); if (isset($this->instances[$abstract])) { $this->instances[$abstract] = $closure($this->instances[$abstract], $this); $this->rebound($abstract); } else { $this->extenders[$abstract][] = $closure; if ($this->resolved($abstract)) { $this->rebound($abstract); } } } /** * Register an existing instance as shared in the container. * * @param string $abstract * @param mixed $instance * @return mixed */ public function instance($abstract, $instance) { $this->removeAbstractAlias($abstract); $isBound = $this->bound($abstract); unset($this->aliases[$abstract]); // We'll check to determine if this type has been bound before, and if it has // we will fire the rebound callbacks registered with the container and it // can be updated with consuming classes that have gotten resolved here. $this->instances[$abstract] = $instance; if ($isBound) { $this->rebound($abstract); } return $instance; } /** * Remove an alias from the contextual binding alias cache. * * @param string $searched * @return void */ protected function removeAbstractAlias($searched) { if (! isset($this->aliases[$searched])) { return; } foreach ($this->abstractAliases as $abstract => $aliases) { foreach ($aliases as $index => $alias) { if ($alias == $searched) { unset($this->abstractAliases[$abstract][$index]); } } } } /** * Assign a set of tags to a given binding. * * @param array|string $abstracts * @param array|mixed ...$tags * @return void */ public function tag($abstracts, $tags) { $tags = is_array($tags) ? $tags : array_slice(func_get_args(), 1); foreach ($tags as $tag) { if (! isset($this->tags[$tag])) { $this->tags[$tag] = []; } foreach ((array) $abstracts as $abstract) { $this->tags[$tag][] = $abstract; } } } /** * Resolve all of the bindings for a given tag. * * @param string $tag * @return iterable */ public function tagged($tag) { if (! isset($this->tags[$tag])) { return []; } return new RewindableGenerator(function () use ($tag) { foreach ($this->tags[$tag] as $abstract) { yield $this->make($abstract); } }, count($this->tags[$tag])); } /** * Alias a type to a different name. * * @param string $abstract * @param string $alias * @return void * * @throws \LogicException */ public function alias($abstract, $alias) { if ($alias === $abstract) { throw new LogicException("[{$abstract}] is aliased to itself."); } $this->aliases[$alias] = $abstract; $this->abstractAliases[$abstract][] = $alias; } /** * Bind a new callback to an abstract's rebind event. * * @param string $abstract * @param \Closure $callback * @return mixed */ public function rebinding($abstract, Closure $callback) { $this->reboundCallbacks[$abstract = $this->getAlias($abstract)][] = $callback; if ($this->bound($abstract)) { return $this->make($abstract); } } /** * Refresh an instance on the given target and method. * * @param string $abstract * @param mixed $target * @param string $method * @return mixed */ public function refresh($abstract, $target, $method) { return $this->rebinding($abstract, function ($app, $instance) use ($target, $method) { $target->{$method}($instance); }); } /** * Fire the "rebound" callbacks for the given abstract type. * * @param string $abstract * @return void */ protected function rebound($abstract) { $instance = $this->make($abstract); foreach ($this->getReboundCallbacks($abstract) as $callback) { call_user_func($callback, $this, $instance); } } /** * Get the rebound callbacks for a given type. * * @param string $abstract * @return array */ protected function getReboundCallbacks($abstract) { return $this->reboundCallbacks[$abstract] ?? []; } /** * Wrap the given closure such that its dependencies will be injected when executed. * * @param \Closure $callback * @param array $parameters * @return \Closure */ public function wrap(Closure $callback, array $parameters = []) { return function () use ($callback, $parameters) { return $this->call($callback, $parameters); }; } /** * Call the given Closure / class@method and inject its dependencies. * * @param callable|string $callback * @param array<string, mixed> $parameters * @param string|null $defaultMethod * @return mixed * * @throws \InvalidArgumentException */ public function call($callback, array $parameters = [], $defaultMethod = null) { return BoundMethod::call($this, $callback, $parameters, $defaultMethod); } /** * Get a closure to resolve the given type from the container. * * @param string $abstract * @return \Closure */ public function factory($abstract) { return function () use ($abstract) { return $this->make($abstract); }; } /** * An alias function name for make(). * * @param string $abstract * @param array $parameters * @return mixed * * @throws \Illuminate\Contracts\Container\BindingResolutionException */ public function makeWith($abstract, array $parameters = []) { return $this->make($abstract, $parameters); } /** * Resolve the given type from the container. * * @param string $abstract * @param array $parameters * @return mixed * * @throws \Illuminate\Contracts\Container\BindingResolutionException */ public function make($abstract, array $parameters = []) { return $this->resolve($abstract, $parameters); } /** * {@inheritdoc} */ public function get($id) { try { return $this->resolve($id); } catch (Exception $e) { if ($this->has($id)) { throw $e; } throw new EntryNotFoundException($id, $e->getCode(), $e); } } /** * Resolve the given type from the container. * * @param string $abstract * @param array $parameters * @param bool $raiseEvents * @return mixed * * @throws \Illuminate\Contracts\Container\BindingResolutionException */ protected function resolve($abstract, $parameters = [], $raiseEvents = true) { $abstract = $this->getAlias($abstract); $concrete = $this->getContextualConcrete($abstract); $needsContextualBuild = ! empty($parameters) || ! is_null($concrete); // If an instance of the type is currently being managed as a singleton we'll // just return an existing instance instead of instantiating new instances // so the developer can keep using the same objects instance every time. if (isset($this->instances[$abstract]) && ! $needsContextualBuild) { return $this->instances[$abstract]; } $this->with[] = $parameters; if (is_null($concrete)) { $concrete = $this->getConcrete($abstract); } // We're ready to instantiate an instance of the concrete type registered for // the binding. This will instantiate the types, as well as resolve any of // its "nested" dependencies recursively until all have gotten resolved. if ($this->isBuildable($concrete, $abstract)) { $object = $this->build($concrete); } else { $object = $this->make($concrete); } // If we defined any extenders for this type, we'll need to spin through them // and apply them to the object being built. This allows for the extension // of services, such as changing configuration or decorating the object. foreach ($this->getExtenders($abstract) as $extender) { $object = $extender($object, $this); } // If the requested type is registered as a singleton we'll want to cache off // the instances in "memory" so we can return it later without creating an // entirely new instance of an object on each subsequent request for it. if ($this->isShared($abstract) && ! $needsContextualBuild) { $this->instances[$abstract] = $object; } if ($raiseEvents) { $this->fireResolvingCallbacks($abstract, $object); } // Before returning, we will also set the resolved flag to "true" and pop off // the parameter overrides for this build. After those two things are done // we will be ready to return back the fully constructed class instance. $this->resolved[$abstract] = true; array_pop($this->with); return $object; } /** * Get the concrete type for a given abstract. * * @param string $abstract * @return mixed */ protected function getConcrete($abstract) { // If we don't have a registered resolver or concrete for the type, we'll just // assume each type is a concrete name and will attempt to resolve it as is // since the container should be able to resolve concretes automatically. if (isset($this->bindings[$abstract])) { return $this->bindings[$abstract]['concrete']; } return $abstract; } /** * Get the contextual concrete binding for the given abstract. * * @param string $abstract * @return \Closure|string|array|null */ protected function getContextualConcrete($abstract) { if (! is_null($binding = $this->findInContextualBindings($abstract))) { return $binding; } // Next we need to see if a contextual binding might be bound under an alias of the // given abstract type. So, we will need to check if any aliases exist with this // type and then spin through them and check for contextual bindings on these. if (empty($this->abstractAliases[$abstract])) { return; } foreach ($this->abstractAliases[$abstract] as $alias) { if (! is_null($binding = $this->findInContextualBindings($alias))) { return $binding; } } } /** * Find the concrete binding for the given abstract in the contextual binding array. * * @param string $abstract * @return \Closure|string|null */ protected function findInContextualBindings($abstract) { return $this->contextual[end($this->buildStack)][$abstract] ?? null; } /** * Determine if the given concrete is buildable. * * @param mixed $concrete * @param string $abstract * @return bool */ protected function isBuildable($concrete, $abstract) { return $concrete === $abstract || $concrete instanceof Closure; } /** * Instantiate a concrete instance of the given type. * * @param \Closure|string $concrete * @return mixed * * @throws \Illuminate\Contracts\Container\BindingResolutionException */ public function build($concrete) { // If the concrete type is actually a Closure, we will just execute it and // hand back the results of the functions, which allows functions to be // used as resolvers for more fine-tuned resolution of these objects. if ($concrete instanceof Closure) { return $concrete($this, $this->getLastParameterOverride()); } try { $reflector = new ReflectionClass($concrete); } catch (ReflectionException $e) { throw new BindingResolutionException("Target class [$concrete] does not exist.", 0, $e); } // If the type is not instantiable, the developer is attempting to resolve // an abstract type such as an Interface or Abstract Class and there is // no binding registered for the abstractions so we need to bail out. if (! $reflector->isInstantiable()) { return $this->notInstantiable($concrete); } $this->buildStack[] = $concrete; $constructor = $reflector->getConstructor(); // If there are no constructors, that means there are no dependencies then // we can just resolve the instances of the objects right away, without // resolving any other types or dependencies out of these containers. if (is_null($constructor)) { array_pop($this->buildStack); return new $concrete; } $dependencies = $constructor->getParameters(); // Once we have all the constructor's parameters we can create each of the // dependency instances and then use the reflection instances to make a // new instance of this class, injecting the created dependencies in. try { $instances = $this->resolveDependencies($dependencies); } catch (BindingResolutionException $e) { array_pop($this->buildStack); throw $e; } array_pop($this->buildStack); return $reflector->newInstanceArgs($instances); } /** * Resolve all of the dependencies from the ReflectionParameters. * * @param array $dependencies * @return array * * @throws \Illuminate\Contracts\Container\BindingResolutionException */ protected function resolveDependencies(array $dependencies) { $results = []; foreach ($dependencies as $dependency) { // If this dependency has a override for this particular build we will use // that instead as the value. Otherwise, we will continue with this run // of resolutions and let reflection attempt to determine the result. if ($this->hasParameterOverride($dependency)) { $results[] = $this->getParameterOverride($dependency); continue; } // If the class is null, it means the dependency is a string or some other // primitive type which we can not resolve since it is not a class and // we will just bomb out with an error since we have no-where to go. $result = is_null($dependency->getClass()) ? $this->resolvePrimitive($dependency) : $this->resolveClass($dependency); if ($dependency->isVariadic()) { $results = array_merge($results, $result); } else { $results[] = $result; } } return $results; } /** * Determine if the given dependency has a parameter override. * * @param \ReflectionParameter $dependency * @return bool */ protected function hasParameterOverride($dependency) { return array_key_exists( $dependency->name, $this->getLastParameterOverride() ); } /** * Get a parameter override for a dependency. * * @param \ReflectionParameter $dependency * @return mixed */ protected function getParameterOverride($dependency) { return $this->getLastParameterOverride()[$dependency->name]; } /** * Get the last parameter override. * * @return array */ protected function getLastParameterOverride() { return count($this->with) ? end($this->with) : []; } /** * Resolve a non-class hinted primitive dependency. * * @param \ReflectionParameter $parameter * @return mixed * * @throws \Illuminate\Contracts\Container\BindingResolutionException */ protected function resolvePrimitive(ReflectionParameter $parameter) { if (! is_null($concrete = $this->getContextualConcrete('$'.$parameter->name))) { return $concrete instanceof Closure ? $concrete($this) : $concrete; } if ($parameter->isDefaultValueAvailable()) { return $parameter->getDefaultValue(); } $this->unresolvablePrimitive($parameter); } /** * Resolve a class based dependency from the container. * * @param \ReflectionParameter $parameter * @return mixed * * @throws \Illuminate\Contracts\Container\BindingResolutionException */ protected function resolveClass(ReflectionParameter $parameter) { try { return $parameter->isVariadic() ? $this->resolveVariadicClass($parameter) : $this->make($parameter->getClass()->name); } // If we can not resolve the class instance, we will check to see if the value // is optional, and if it is we will return the optional parameter value as // the value of the dependency, similarly to how we do this with scalars. catch (BindingResolutionException $e) { if ($parameter->isDefaultValueAvailable()) { return $parameter->getDefaultValue(); } if ($parameter->isVariadic()) { return []; } throw $e; } } /** * Resolve a class based variadic dependency from the container. * * @param \ReflectionParameter $parameter * @return mixed */ protected function resolveVariadicClass(ReflectionParameter $parameter) { $abstract = $this->getAlias($parameter->getClass()->name); if (! is_array($concrete = $this->getContextualConcrete($abstract))) { return $this->make($parameter->getClass()->name); } return array_map(function ($abstract) { return $this->resolve($abstract); }, $concrete); } /** * Throw an exception that the concrete is not instantiable. * * @param string $concrete * @return void * * @throws \Illuminate\Contracts\Container\BindingResolutionException */ protected function notInstantiable($concrete) { if (! empty($this->buildStack)) { $previous = implode(', ', $this->buildStack); $message = "Target [$concrete] is not instantiable while building [$previous]."; } else { $message = "Target [$concrete] is not instantiable."; } throw new BindingResolutionException($message); } /** * Throw an exception for an unresolvable primitive. * * @param \ReflectionParameter $parameter * @return void * * @throws \Illuminate\Contracts\Container\BindingResolutionException */ protected function unresolvablePrimitive(ReflectionParameter $parameter) { $message = "Unresolvable dependency resolving [$parameter] in class {$parameter->getDeclaringClass()->getName()}"; throw new BindingResolutionException($message); } /** * Register a new resolving callback. * * @param \Closure|string $abstract * @param \Closure|null $callback * @return void */ public function resolving($abstract, Closure $callback = null) { if (is_string($abstract)) { $abstract = $this->getAlias($abstract); } if (is_null($callback) && $abstract instanceof Closure) { $this->globalResolvingCallbacks[] = $abstract; } else { $this->resolvingCallbacks[$abstract][] = $callback; } } /** * Register a new after resolving callback for all types. * * @param \Closure|string $abstract * @param \Closure|null $callback * @return void */ public function afterResolving($abstract, Closure $callback = null) { if (is_string($abstract)) { $abstract = $this->getAlias($abstract); } if ($abstract instanceof Closure && is_null($callback)) { $this->globalAfterResolvingCallbacks[] = $abstract; } else { $this->afterResolvingCallbacks[$abstract][] = $callback; } } /** * Fire all of the resolving callbacks. * * @param string $abstract * @param mixed $object * @return void */ protected function fireResolvingCallbacks($abstract, $object) { $this->fireCallbackArray($object, $this->globalResolvingCallbacks); $this->fireCallbackArray( $object, $this->getCallbacksForType($abstract, $object, $this->resolvingCallbacks) ); $this->fireAfterResolvingCallbacks($abstract, $object); } /** * Fire all of the after resolving callbacks. * * @param string $abstract * @param mixed $object * @return void */ protected function fireAfterResolvingCallbacks($abstract, $object) { $this->fireCallbackArray($object, $this->globalAfterResolvingCallbacks); $this->fireCallbackArray( $object, $this->getCallbacksForType($abstract, $object, $this->afterResolvingCallbacks) ); } /** * Get all callbacks for a given type. * * @param string $abstract * @param object $object * @param array $callbacksPerType * * @return array */ protected function getCallbacksForType($abstract, $object, array $callbacksPerType) { $results = []; foreach ($callbacksPerType as $type => $callbacks) { if ($type === $abstract || $object instanceof $type) { $results = array_merge($results, $callbacks); } } return $results; } /** * Fire an array of callbacks with an object. * * @param mixed $object * @param array $callbacks * @return void */ protected function fireCallbackArray($object, array $callbacks) { foreach ($callbacks as $callback) { $callback($object, $this); } } /** * Get the container's bindings. * * @return array */ public function getBindings() { return $this->bindings; } /** * Get the alias for an abstract if available. * * @param string $abstract * @return string */ public function getAlias($abstract) { if (! isset($this->aliases[$abstract])) { return $abstract; } return $this->getAlias($this->aliases[$abstract]); } /** * Get the extender callbacks for a given type. * * @param string $abstract * @return array */ protected function getExtenders($abstract) { $abstract = $this->getAlias($abstract); return $this->extenders[$abstract] ?? []; } /** * Remove all of the extender callbacks for a given type. * * @param string $abstract * @return void */ public function forgetExtenders($abstract) { unset($this->extenders[$this->getAlias($abstract)]); } /** * Drop all of the stale instances and aliases. * * @param string $abstract * @return void */ protected function dropStaleInstances($abstract) { unset($this->instances[$abstract], $this->aliases[$abstract]); } /** * Remove a resolved instance from the instance cache. * * @param string $abstract * @return void */ public function forgetInstance($abstract) { unset($this->instances[$abstract]); } /** * Clear all of the instances from the container. * * @return void */ public function forgetInstances() { $this->instances = []; } /** * Flush the container of all bindings and resolved instances. * * @return void */ public function flush() { $this->aliases = []; $this->resolved = []; $this->bindings = []; $this->instances = []; $this->abstractAliases = []; } /** * Get the globally available instance of the container. * * @return static */ public static function getInstance() { if (is_null(static::$instance)) { static::$instance = new static; } return static::$instance; } /** * Set the shared instance of the container. * * @param \Illuminate\Contracts\Container\Container|null $container * @return \Illuminate\Contracts\Container\Container|static */ public static function setInstance(ContainerContract $container = null) { return static::$instance = $container; } /** * Determine if a given offset exists. * * @param string $key * @return bool */ #[\ReturnTypeWillChange] public function offsetExists($key) { return $this->bound($key); } /** * Get the value at a given offset. * * @param string $key * @return mixed */ #[\ReturnTypeWillChange] public function offsetGet($key) { return $this->make($key); } /** * Set the value at a given offset. * * @param string $key * @param mixed $value * @return void */ #[\ReturnTypeWillChange] public function offsetSet($key, $value) { $this->bind($key, $value instanceof Closure ? $value : function () use ($value) { return $value; }); } /** * Unset the value at a given offset. * * @param string $key * @return void */ #[\ReturnTypeWillChange] public function offsetUnset($key) { unset($this->bindings[$key], $this->instances[$key], $this->resolved[$key]); } /** * Dynamically access container services. * * @param string $key * @return mixed */ public function __get($key) { return $this[$key]; } /** * Dynamically set container services. * * @param string $key * @param mixed $value * @return void */ public function __set($key, $value) { $this[$key] = $value; } } container/ContextualBindingBuilder.php 0000644 00000003751 14736103231 0014175 0 ustar 00 <?php namespace Illuminate\Container; use Illuminate\Contracts\Container\Container; use Illuminate\Contracts\Container\ContextualBindingBuilder as ContextualBindingBuilderContract; class ContextualBindingBuilder implements ContextualBindingBuilderContract { /** * The underlying container instance. * * @var \Illuminate\Contracts\Container\Container */ protected $container; /** * The concrete instance. * * @var string|array */ protected $concrete; /** * The abstract target. * * @var string */ protected $needs; /** * Create a new contextual binding builder. * * @param \Illuminate\Contracts\Container\Container $container * @param string|array $concrete * @return void */ public function __construct(Container $container, $concrete) { $this->concrete = $concrete; $this->container = $container; } /** * Define the abstract target that depends on the context. * * @param string $abstract * @return $this */ public function needs($abstract) { $this->needs = $abstract; return $this; } /** * Define the implementation for the contextual binding. * * @param \Closure|string|array $implementation * @return void */ public function give($implementation) { foreach (Util::arrayWrap($this->concrete) as $concrete) { $this->container->addContextualBinding($concrete, $this->needs, $implementation); } } /** * Define tagged services to be used as the implementation for the contextual binding. * * @param string $tag * @return void */ public function giveTagged($tag) { $this->give(function ($container) use ($tag) { $taggedServices = $container->tagged($tag); return is_array($taggedServices) ? $taggedServices : iterator_to_array($taggedServices); }); } } container/RewindableGenerator.php 0000644 00000002077 14736103231 0013170 0 ustar 00 <?php namespace Illuminate\Container; use Countable; use IteratorAggregate; class RewindableGenerator implements Countable, IteratorAggregate { /** * The generator callback. * * @var callable */ protected $generator; /** * The number of tagged services. * * @var callable|int */ protected $count; /** * Create a new generator instance. * * @param callable $generator * @param callable|int $count * @return void */ public function __construct(callable $generator, $count) { $this->count = $count; $this->generator = $generator; } /** * Get an iterator from the generator. * * @return mixed */ public function getIterator() { return ($this->generator)(); } /** * Get the total number of tagged services. * * @return int */ public function count() { if (is_callable($count = $this->count)) { $this->count = $count(); } return $this->count; } } container/LICENSE.md 0000644 00000002063 14736103231 0010133 0 ustar 00 The MIT License (MIT) Copyright (c) Taylor Otwell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. container/Util.php 0000644 00000001366 14736103231 0010162 0 ustar 00 <?php namespace Illuminate\Container; use Closure; class Util { /** * If the given value is not an array and not null, wrap it in one. * * From Arr::wrap() in Illuminate\Support. * * @param mixed $value * @return array */ public static function arrayWrap($value) { if (is_null($value)) { return []; } return is_array($value) ? $value : [$value]; } /** * Return the default value of the given value. * * From global value() helper in Illuminate\Support. * * @param mixed $value * @return mixed */ public static function unwrapIfClosure($value) { return $value instanceof Closure ? $value() : $value; } } container/BoundMethod.php 0000644 00000014713 14736103231 0011455 0 ustar 00 <?php namespace Illuminate\Container; use Closure; use Illuminate\Contracts\Container\BindingResolutionException; use InvalidArgumentException; use ReflectionFunction; use ReflectionMethod; class BoundMethod { /** * Call the given Closure / class@method and inject its dependencies. * * @param \Illuminate\Container\Container $container * @param callable|string $callback * @param array $parameters * @param string|null $defaultMethod * @return mixed * * @throws \ReflectionException * @throws \InvalidArgumentException */ public static function call($container, $callback, array $parameters = [], $defaultMethod = null) { if (static::isCallableWithAtSign($callback) || $defaultMethod) { return static::callClass($container, $callback, $parameters, $defaultMethod); } return static::callBoundMethod($container, $callback, function () use ($container, $callback, $parameters) { return call_user_func_array( $callback, static::getMethodDependencies($container, $callback, $parameters) ); }); } /** * Call a string reference to a class using Class@method syntax. * * @param \Illuminate\Container\Container $container * @param string $target * @param array $parameters * @param string|null $defaultMethod * @return mixed * * @throws \InvalidArgumentException */ protected static function callClass($container, $target, array $parameters = [], $defaultMethod = null) { $segments = explode('@', $target); // We will assume an @ sign is used to delimit the class name from the method // name. We will split on this @ sign and then build a callable array that // we can pass right back into the "call" method for dependency binding. $method = count($segments) === 2 ? $segments[1] : $defaultMethod; if (is_null($method)) { throw new InvalidArgumentException('Method not provided.'); } return static::call( $container, [$container->make($segments[0]), $method], $parameters ); } /** * Call a method that has been bound to the container. * * @param \Illuminate\Container\Container $container * @param callable $callback * @param mixed $default * @return mixed */ protected static function callBoundMethod($container, $callback, $default) { if (! is_array($callback)) { return Util::unwrapIfClosure($default); } // Here we need to turn the array callable into a Class@method string we can use to // examine the container and see if there are any method bindings for this given // method. If there are, we can call this method binding callback immediately. $method = static::normalizeMethod($callback); if ($container->hasMethodBinding($method)) { return $container->callMethodBinding($method, $callback[0]); } return Util::unwrapIfClosure($default); } /** * Normalize the given callback into a Class@method string. * * @param callable $callback * @return string */ protected static function normalizeMethod($callback) { $class = is_string($callback[0]) ? $callback[0] : get_class($callback[0]); return "{$class}@{$callback[1]}"; } /** * Get all dependencies for a given method. * * @param \Illuminate\Container\Container $container * @param callable|string $callback * @param array $parameters * @return array * * @throws \ReflectionException */ protected static function getMethodDependencies($container, $callback, array $parameters = []) { $dependencies = []; foreach (static::getCallReflector($callback)->getParameters() as $parameter) { static::addDependencyForCallParameter($container, $parameter, $parameters, $dependencies); } return array_merge($dependencies, $parameters); } /** * Get the proper reflection instance for the given callback. * * @param callable|string $callback * @return \ReflectionFunctionAbstract * * @throws \ReflectionException */ protected static function getCallReflector($callback) { if (is_string($callback) && strpos($callback, '::') !== false) { $callback = explode('::', $callback); } elseif (is_object($callback) && ! $callback instanceof Closure) { $callback = [$callback, '__invoke']; } return is_array($callback) ? new ReflectionMethod($callback[0], $callback[1]) : new ReflectionFunction($callback); } /** * Get the dependency for the given call parameter. * * @param \Illuminate\Container\Container $container * @param \ReflectionParameter $parameter * @param array $parameters * @param array $dependencies * @return void */ protected static function addDependencyForCallParameter($container, $parameter, array &$parameters, &$dependencies) { if (array_key_exists($parameter->name, $parameters)) { $dependencies[] = $parameters[$parameter->name]; unset($parameters[$parameter->name]); } elseif ($parameter->getClass() && array_key_exists($parameter->getClass()->name, $parameters)) { $dependencies[] = $parameters[$parameter->getClass()->name]; unset($parameters[$parameter->getClass()->name]); } elseif ($parameter->getClass()) { $dependencies[] = $container->make($parameter->getClass()->name); } elseif ($parameter->isDefaultValueAvailable()) { $dependencies[] = $parameter->getDefaultValue(); } elseif (! $parameter->isOptional() && ! array_key_exists($parameter->name, $parameters)) { $message = "Unable to resolve dependency [{$parameter}] in class {$parameter->getDeclaringClass()->getName()}"; throw new BindingResolutionException($message); } } /** * Determine if the given string is in Class@method syntax. * * @param mixed $callback * @return bool */ protected static function isCallableWithAtSign($callback) { return is_string($callback) && strpos($callback, '@') !== false; } } contracts/Session/Session.php 0000644 00000006064 14736103231 0012331 0 ustar 00 <?php namespace Illuminate\Contracts\Session; interface Session { /** * Get the name of the session. * * @return string */ public function getName(); /** * Get the current session ID. * * @return string */ public function getId(); /** * Set the session ID. * * @param string $id * @return void */ public function setId($id); /** * Start the session, reading the data from a handler. * * @return bool */ public function start(); /** * Save the session data to storage. * * @return void */ public function save(); /** * Get all of the session data. * * @return array */ public function all(); /** * Checks if a key exists. * * @param string|array $key * @return bool */ public function exists($key); /** * Checks if an a key is present and not null. * * @param string|array $key * @return bool */ public function has($key); /** * Get an item from the session. * * @param string $key * @param mixed $default * @return mixed */ public function get($key, $default = null); /** * Put a key / value pair or array of key / value pairs in the session. * * @param string|array $key * @param mixed $value * @return void */ public function put($key, $value = null); /** * Get the CSRF token value. * * @return string */ public function token(); /** * Remove an item from the session, returning its value. * * @param string $key * @return mixed */ public function remove($key); /** * Remove one or many items from the session. * * @param string|array $keys * @return void */ public function forget($keys); /** * Remove all of the items from the session. * * @return void */ public function flush(); /** * Generate a new session ID for the session. * * @param bool $destroy * @return bool */ public function migrate($destroy = false); /** * Determine if the session has been started. * * @return bool */ public function isStarted(); /** * Get the previous URL from the session. * * @return string|null */ public function previousUrl(); /** * Set the "previous" URL in the session. * * @param string $url * @return void */ public function setPreviousUrl($url); /** * Get the session handler instance. * * @return \SessionHandlerInterface */ public function getHandler(); /** * Determine if the session handler needs a request. * * @return bool */ public function handlerNeedsRequest(); /** * Set the request on the handler instance. * * @param \Illuminate\Http\Request $request * @return void */ public function setRequestOnHandler($request); } contracts/Filesystem/Cloud.php 0000644 00000000367 14736103231 0012455 0 ustar 00 <?php namespace Illuminate\Contracts\Filesystem; interface Cloud extends Filesystem { /** * Get the URL for the file at the given path. * * @param string $path * @return string */ public function url($path); } contracts/Filesystem/FileExistsException.php 0000644 00000000172 14736103231 0015337 0 ustar 00 <?php namespace Illuminate\Contracts\Filesystem; use Exception; class FileExistsException extends Exception { // } contracts/Filesystem/Filesystem.php 0000644 00000010344 14736103231 0013527 0 ustar 00 <?php namespace Illuminate\Contracts\Filesystem; interface Filesystem { /** * The public visibility setting. * * @var string */ const VISIBILITY_PUBLIC = 'public'; /** * The private visibility setting. * * @var string */ const VISIBILITY_PRIVATE = 'private'; /** * Determine if a file exists. * * @param string $path * @return bool */ public function exists($path); /** * Get the contents of a file. * * @param string $path * @return string * * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException */ public function get($path); /** * Get a resource to read the file. * * @param string $path * @return resource|null The path resource or null on failure. * * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException */ public function readStream($path); /** * Write the contents of a file. * * @param string $path * @param string|resource $contents * @param mixed $options * @return bool */ public function put($path, $contents, $options = []); /** * Write a new file using a stream. * * @param string $path * @param resource $resource * @param array $options * @return bool * * @throws \InvalidArgumentException If $resource is not a file handle. * @throws \Illuminate\Contracts\Filesystem\FileExistsException */ public function writeStream($path, $resource, array $options = []); /** * Get the visibility for the given path. * * @param string $path * @return string */ public function getVisibility($path); /** * Set the visibility for the given path. * * @param string $path * @param string $visibility * @return bool */ public function setVisibility($path, $visibility); /** * Prepend to a file. * * @param string $path * @param string $data * @return bool */ public function prepend($path, $data); /** * Append to a file. * * @param string $path * @param string $data * @return bool */ public function append($path, $data); /** * Delete the file at a given path. * * @param string|array $paths * @return bool */ public function delete($paths); /** * Copy a file to a new location. * * @param string $from * @param string $to * @return bool */ public function copy($from, $to); /** * Move a file to a new location. * * @param string $from * @param string $to * @return bool */ public function move($from, $to); /** * Get the file size of a given file. * * @param string $path * @return int */ public function size($path); /** * Get the file's last modification time. * * @param string $path * @return int */ public function lastModified($path); /** * Get an array of all files in a directory. * * @param string|null $directory * @param bool $recursive * @return array */ public function files($directory = null, $recursive = false); /** * Get all of the files from the given directory (recursive). * * @param string|null $directory * @return array */ public function allFiles($directory = null); /** * Get all of the directories within a given directory. * * @param string|null $directory * @param bool $recursive * @return array */ public function directories($directory = null, $recursive = false); /** * Get all (recursive) of the directories within a given directory. * * @param string|null $directory * @return array */ public function allDirectories($directory = null); /** * Create a directory. * * @param string $path * @return bool */ public function makeDirectory($path); /** * Recursively delete a directory. * * @param string $directory * @return bool */ public function deleteDirectory($directory); } contracts/Filesystem/FileNotFoundException.php 0000644 00000000174 14736103231 0015616 0 ustar 00 <?php namespace Illuminate\Contracts\Filesystem; use Exception; class FileNotFoundException extends Exception { // } contracts/Filesystem/Factory.php 0000644 00000000415 14736103231 0013010 0 ustar 00 <?php namespace Illuminate\Contracts\Filesystem; interface Factory { /** * Get a filesystem implementation. * * @param string|null $name * @return \Illuminate\Contracts\Filesystem\Filesystem */ public function disk($name = null); } contracts/Pagination/Paginator.php 0000644 00000004611 14736103231 0013274 0 ustar 00 <?php namespace Illuminate\Contracts\Pagination; interface Paginator { /** * Get the URL for a given page. * * @param int $page * @return string */ public function url($page); /** * Add a set of query string values to the paginator. * * @param array|string $key * @param string|null $value * @return $this */ public function appends($key, $value = null); /** * Get / set the URL fragment to be appended to URLs. * * @param string|null $fragment * @return $this|string */ public function fragment($fragment = null); /** * The URL for the next page, or null. * * @return string|null */ public function nextPageUrl(); /** * Get the URL for the previous page, or null. * * @return string|null */ public function previousPageUrl(); /** * Get all of the items being paginated. * * @return array */ public function items(); /** * Get the "index" of the first item being paginated. * * @return int */ public function firstItem(); /** * Get the "index" of the last item being paginated. * * @return int */ public function lastItem(); /** * Determine how many items are being shown per page. * * @return int */ public function perPage(); /** * Determine the current page being paginated. * * @return int */ public function currentPage(); /** * Determine if there are enough items to split into multiple pages. * * @return bool */ public function hasPages(); /** * Determine if there is more items in the data store. * * @return bool */ public function hasMorePages(); /** * Get the base path for paginator generated URLs. * * @return string|null */ public function path(); /** * Determine if the list of items is empty or not. * * @return bool */ public function isEmpty(); /** * Determine if the list of items is not empty. * * @return bool */ public function isNotEmpty(); /** * Render the paginator using a given view. * * @param string|null $view * @param array $data * @return string */ public function render($view = null, $data = []); } contracts/Pagination/LengthAwarePaginator.php 0000644 00000001051 14736103231 0015411 0 ustar 00 <?php namespace Illuminate\Contracts\Pagination; interface LengthAwarePaginator extends Paginator { /** * Create a range of pagination URLs. * * @param int $start * @param int $end * @return array */ public function getUrlRange($start, $end); /** * Determine the total number of items in the data store. * * @return int */ public function total(); /** * Get the page number of the last available page. * * @return int */ public function lastPage(); } contracts/Pagination/Presenter.php 0000644 00000000574 14736103231 0013323 0 ustar 00 <?php namespace Illuminate\Contracts\Pagination; interface Presenter { /** * Render the given paginator. * * @return \Illuminate\Contracts\Support\Htmlable|string */ public function render(); /** * Determine if the underlying paginator being presented has pages to show. * * @return bool */ public function hasPages(); } contracts/Auth/Registrar.php 0000644 00000000760 14736103231 0012123 0 ustar 00 <?php namespace Illuminate\Contracts\Auth; interface Registrar { /** * Get a validator for an incoming registration request. * * @param array $data * @return \Illuminate\Contracts\Validation\Validator */ public function validator(array $data); /** * Create a new user instance after a valid registration. * * @param array $data * @return \Illuminate\Contracts\Auth\Authenticatable */ public function create(array $data); } contracts/Auth/PasswordBrokerFactory.php 0000644 00000000370 14736103231 0014455 0 ustar 00 <?php namespace Illuminate\Contracts\Auth; interface PasswordBrokerFactory { /** * Get a password broker instance by name. * * @param string|null $name * @return mixed */ public function broker($name = null); } contracts/Auth/SupportsBasicAuth.php 0000644 00000001173 14736103231 0013603 0 ustar 00 <?php namespace Illuminate\Contracts\Auth; interface SupportsBasicAuth { /** * Attempt to authenticate using HTTP Basic Auth. * * @param string $field * @param array $extraConditions * @return \Symfony\Component\HttpFoundation\Response|null */ public function basic($field = 'email', $extraConditions = []); /** * Perform a stateless HTTP Basic login attempt. * * @param string $field * @param array $extraConditions * @return \Symfony\Component\HttpFoundation\Response|null */ public function onceBasic($field = 'email', $extraConditions = []); } contracts/Auth/Authenticatable.php 0000644 00000001664 14736103231 0013262 0 ustar 00 <?php namespace Illuminate\Contracts\Auth; interface Authenticatable { /** * Get the name of the unique identifier for the user. * * @return string */ public function getAuthIdentifierName(); /** * Get the unique identifier for the user. * * @return mixed */ public function getAuthIdentifier(); /** * Get the password for the user. * * @return string */ public function getAuthPassword(); /** * Get the token value for the "remember me" session. * * @return string */ public function getRememberToken(); /** * Set the token value for the "remember me" session. * * @param string $value * @return void */ public function setRememberToken($value); /** * Get the column name for the "remember me" token. * * @return string */ public function getRememberTokenName(); } contracts/Auth/StatefulGuard.php 0000644 00000002773 14736103231 0012741 0 ustar 00 <?php namespace Illuminate\Contracts\Auth; interface StatefulGuard extends Guard { /** * Attempt to authenticate a user using the given credentials. * * @param array $credentials * @param bool $remember * @return bool */ public function attempt(array $credentials = [], $remember = false); /** * Log a user into the application without sessions or cookies. * * @param array $credentials * @return bool */ public function once(array $credentials = []); /** * Log a user into the application. * * @param \Illuminate\Contracts\Auth\Authenticatable $user * @param bool $remember * @return void */ public function login(Authenticatable $user, $remember = false); /** * Log the given user ID into the application. * * @param mixed $id * @param bool $remember * @return \Illuminate\Contracts\Auth\Authenticatable */ public function loginUsingId($id, $remember = false); /** * Log the given user ID into the application without sessions or cookies. * * @param mixed $id * @return \Illuminate\Contracts\Auth\Authenticatable|bool */ public function onceUsingId($id); /** * Determine if the user was authenticated via "remember me" cookie. * * @return bool */ public function viaRemember(); /** * Log the user out of the application. * * @return void */ public function logout(); } contracts/Auth/CanResetPassword.php 0000644 00000000636 14736103231 0013412 0 ustar 00 <?php namespace Illuminate\Contracts\Auth; interface CanResetPassword { /** * Get the e-mail address where password reset links are sent. * * @return string */ public function getEmailForPasswordReset(); /** * Send the password reset notification. * * @param string $token * @return void */ public function sendPasswordResetNotification($token); } contracts/Auth/PasswordBroker.php 0000644 00000002306 14736103231 0013126 0 ustar 00 <?php namespace Illuminate\Contracts\Auth; use Closure; interface PasswordBroker { /** * Constant representing a successfully sent reminder. * * @var string */ const RESET_LINK_SENT = 'passwords.sent'; /** * Constant representing a successfully reset password. * * @var string */ const PASSWORD_RESET = 'passwords.reset'; /** * Constant representing the user not found response. * * @var string */ const INVALID_USER = 'passwords.user'; /** * Constant representing an invalid token. * * @var string */ const INVALID_TOKEN = 'passwords.token'; /** * Constant representing a throttled reset attempt. * * @var string */ const RESET_THROTTLED = 'passwords.throttled'; /** * Send a password reset link to a user. * * @param array $credentials * @return string */ public function sendResetLink(array $credentials); /** * Reset the password for the given token. * * @param array $credentials * @param \Closure $callback * @return mixed */ public function reset(array $credentials, Closure $callback); } contracts/Auth/UserProvider.php 0000644 00000002532 14736103231 0012611 0 ustar 00 <?php namespace Illuminate\Contracts\Auth; interface UserProvider { /** * Retrieve a user by their unique identifier. * * @param mixed $identifier * @return \Illuminate\Contracts\Auth\Authenticatable|null */ public function retrieveById($identifier); /** * Retrieve a user by their unique identifier and "remember me" token. * * @param mixed $identifier * @param string $token * @return \Illuminate\Contracts\Auth\Authenticatable|null */ public function retrieveByToken($identifier, $token); /** * Update the "remember me" token for the given user in storage. * * @param \Illuminate\Contracts\Auth\Authenticatable $user * @param string $token * @return void */ public function updateRememberToken(Authenticatable $user, $token); /** * Retrieve a user by the given credentials. * * @param array $credentials * @return \Illuminate\Contracts\Auth\Authenticatable|null */ public function retrieveByCredentials(array $credentials); /** * Validate a user against the given credentials. * * @param \Illuminate\Contracts\Auth\Authenticatable $user * @param array $credentials * @return bool */ public function validateCredentials(Authenticatable $user, array $credentials); } contracts/Auth/MustVerifyEmail.php 0000644 00000001232 14736103231 0013241 0 ustar 00 <?php namespace Illuminate\Contracts\Auth; interface MustVerifyEmail { /** * Determine if the user has verified their email address. * * @return bool */ public function hasVerifiedEmail(); /** * Mark the given user's email as verified. * * @return bool */ public function markEmailAsVerified(); /** * Send the email verification notification. * * @return void */ public function sendEmailVerificationNotification(); /** * Get the email address that should be used for verification. * * @return string */ public function getEmailForVerification(); } contracts/Auth/Middleware/AuthenticatesRequests.php 0000644 00000000143 14736103231 0016566 0 ustar 00 <?php namespace Illuminate\Contracts\Auth\Middleware; interface AuthenticatesRequests { // } contracts/Auth/Factory.php 0000644 00000000711 14736103231 0011564 0 ustar 00 <?php namespace Illuminate\Contracts\Auth; interface Factory { /** * Get a guard instance by name. * * @param string|null $name * @return \Illuminate\Contracts\Auth\Guard|\Illuminate\Contracts\Auth\StatefulGuard */ public function guard($name = null); /** * Set the default guard the factory should serve. * * @param string $name * @return void */ public function shouldUse($name); } contracts/Auth/Guard.php 0000644 00000001715 14736103231 0011224 0 ustar 00 <?php namespace Illuminate\Contracts\Auth; interface Guard { /** * Determine if the current user is authenticated. * * @return bool */ public function check(); /** * Determine if the current user is a guest. * * @return bool */ public function guest(); /** * Get the currently authenticated user. * * @return \Illuminate\Contracts\Auth\Authenticatable|null */ public function user(); /** * Get the ID for the currently authenticated user. * * @return int|string|null */ public function id(); /** * Validate a user's credentials. * * @param array $credentials * @return bool */ public function validate(array $credentials = []); /** * Set the current user. * * @param \Illuminate\Contracts\Auth\Authenticatable $user * @return void */ public function setUser(Authenticatable $user); } contracts/Auth/Access/Gate.php 0000644 00000007213 14736103231 0012242 0 ustar 00 <?php namespace Illuminate\Contracts\Auth\Access; interface Gate { /** * Determine if a given ability has been defined. * * @param string $ability * @return bool */ public function has($ability); /** * Define a new ability. * * @param string $ability * @param callable|string $callback * @return $this */ public function define($ability, $callback); /** * Define abilities for a resource. * * @param string $name * @param string $class * @param array|null $abilities * @return $this */ public function resource($name, $class, array $abilities = null); /** * Define a policy class for a given class type. * * @param string $class * @param string $policy * @return $this */ public function policy($class, $policy); /** * Register a callback to run before all Gate checks. * * @param callable $callback * @return $this */ public function before(callable $callback); /** * Register a callback to run after all Gate checks. * * @param callable $callback * @return $this */ public function after(callable $callback); /** * Determine if the given ability should be granted for the current user. * * @param string $ability * @param array|mixed $arguments * @return bool */ public function allows($ability, $arguments = []); /** * Determine if the given ability should be denied for the current user. * * @param string $ability * @param array|mixed $arguments * @return bool */ public function denies($ability, $arguments = []); /** * Determine if all of the given abilities should be granted for the current user. * * @param iterable|string $abilities * @param array|mixed $arguments * @return bool */ public function check($abilities, $arguments = []); /** * Determine if any one of the given abilities should be granted for the current user. * * @param iterable|string $abilities * @param array|mixed $arguments * @return bool */ public function any($abilities, $arguments = []); /** * Determine if the given ability should be granted for the current user. * * @param string $ability * @param array|mixed $arguments * @return \Illuminate\Auth\Access\Response * * @throws \Illuminate\Auth\Access\AuthorizationException */ public function authorize($ability, $arguments = []); /** * Inspect the user for the given ability. * * @param string $ability * @param array|mixed $arguments * @return \Illuminate\Auth\Access\Response */ public function inspect($ability, $arguments = []); /** * Get the raw result from the authorization callback. * * @param string $ability * @param array|mixed $arguments * @return mixed * * @throws \Illuminate\Auth\Access\AuthorizationException */ public function raw($ability, $arguments = []); /** * Get a policy instance for a given class. * * @param object|string $class * @return mixed * * @throws \InvalidArgumentException */ public function getPolicyFor($class); /** * Get a guard instance for the given user. * * @param \Illuminate\Contracts\Auth\Authenticatable|mixed $user * @return static */ public function forUser($user); /** * Get all of the defined abilities. * * @return array */ public function abilities(); } contracts/Auth/Access/Authorizable.php 0000644 00000000451 14736103231 0014010 0 ustar 00 <?php namespace Illuminate\Contracts\Auth\Access; interface Authorizable { /** * Determine if the entity has a given ability. * * @param string $ability * @param array|mixed $arguments * @return bool */ public function can($ability, $arguments = []); } contracts/Notifications/Factory.php 0000644 00000001402 14736103231 0013472 0 ustar 00 <?php namespace Illuminate\Contracts\Notifications; interface Factory { /** * Get a channel instance by name. * * @param string|null $name * @return mixed */ public function channel($name = null); /** * Send the given notification to the given notifiable entities. * * @param \Illuminate\Support\Collection|array|mixed $notifiables * @param mixed $notification * @return void */ public function send($notifiables, $notification); /** * Send the given notification immediately. * * @param \Illuminate\Support\Collection|array|mixed $notifiables * @param mixed $notification * @return void */ public function sendNow($notifiables, $notification); } contracts/Notifications/Dispatcher.php 0000644 00000001144 14736103231 0014154 0 ustar 00 <?php namespace Illuminate\Contracts\Notifications; interface Dispatcher { /** * Send the given notification to the given notifiable entities. * * @param \Illuminate\Support\Collection|array|mixed $notifiables * @param mixed $notification * @return void */ public function send($notifiables, $notification); /** * Send the given notification immediately. * * @param \Illuminate\Support\Collection|array|mixed $notifiables * @param mixed $notification * @return void */ public function sendNow($notifiables, $notification); } contracts/Events/Dispatcher.php 0000644 00000003412 14736103231 0012607 0 ustar 00 <?php namespace Illuminate\Contracts\Events; interface Dispatcher { /** * Register an event listener with the dispatcher. * * @param string|array $events * @param \Closure|string $listener * @return void */ public function listen($events, $listener); /** * Determine if a given event has listeners. * * @param string $eventName * @return bool */ public function hasListeners($eventName); /** * Register an event subscriber with the dispatcher. * * @param object|string $subscriber * @return void */ public function subscribe($subscriber); /** * Dispatch an event until the first non-null response is returned. * * @param string|object $event * @param mixed $payload * @return array|null */ public function until($event, $payload = []); /** * Dispatch an event and call the listeners. * * @param string|object $event * @param mixed $payload * @param bool $halt * @return array|null */ public function dispatch($event, $payload = [], $halt = false); /** * Register an event and payload to be fired later. * * @param string $event * @param array $payload * @return void */ public function push($event, $payload = []); /** * Flush a set of pushed events. * * @param string $event * @return void */ public function flush($event); /** * Remove a set of listeners from the dispatcher. * * @param string $event * @return void */ public function forget($event); /** * Forget all of the queued listeners. * * @return void */ public function forgetPushed(); } contracts/Encryption/Encrypter.php 0000644 00000001150 14736103231 0013357 0 ustar 00 <?php namespace Illuminate\Contracts\Encryption; interface Encrypter { /** * Encrypt the given value. * * @param mixed $value * @param bool $serialize * @return string * * @throws \Illuminate\Contracts\Encryption\EncryptException */ public function encrypt($value, $serialize = true); /** * Decrypt the given value. * * @param string $payload * @param bool $unserialize * @return mixed * * @throws \Illuminate\Contracts\Encryption\DecryptException */ public function decrypt($payload, $unserialize = true); } contracts/Encryption/EncryptException.php 0000644 00000000205 14736103231 0014707 0 ustar 00 <?php namespace Illuminate\Contracts\Encryption; use RuntimeException; class EncryptException extends RuntimeException { // } contracts/Encryption/DecryptException.php 0000644 00000000205 14736103231 0014675 0 ustar 00 <?php namespace Illuminate\Contracts\Encryption; use RuntimeException; class DecryptException extends RuntimeException { // } contracts/Broadcasting/ShouldBroadcastNow.php 0000644 00000000165 14736103231 0015424 0 ustar 00 <?php namespace Illuminate\Contracts\Broadcasting; interface ShouldBroadcastNow extends ShouldBroadcast { // } contracts/Broadcasting/Broadcaster.php 0000644 00000001371 14736103231 0014110 0 ustar 00 <?php namespace Illuminate\Contracts\Broadcasting; interface Broadcaster { /** * Authenticate the incoming request for a given channel. * * @param \Illuminate\Http\Request $request * @return mixed */ public function auth($request); /** * Return the valid authentication response. * * @param \Illuminate\Http\Request $request * @param mixed $result * @return mixed */ public function validAuthenticationResponse($request, $result); /** * Broadcast the given event. * * @param array $channels * @param string $event * @param array $payload * @return void */ public function broadcast(array $channels, $event, array $payload = []); } contracts/Broadcasting/Factory.php 0000644 00000000441 14736103231 0013263 0 ustar 00 <?php namespace Illuminate\Contracts\Broadcasting; interface Factory { /** * Get a broadcaster implementation by name. * * @param string|null $name * @return \Illuminate\Contracts\Broadcasting\Broadcaster */ public function connection($name = null); } contracts/Broadcasting/ShouldBroadcast.php 0000644 00000000427 14736103231 0014741 0 ustar 00 <?php namespace Illuminate\Contracts\Broadcasting; interface ShouldBroadcast { /** * Get the channels the event should broadcast on. * * @return \Illuminate\Broadcasting\Channel|\Illuminate\Broadcasting\Channel[] */ public function broadcastOn(); } contracts/Container/Container.php 0000644 00000010765 14736103231 0013132 0 ustar 00 <?php namespace Illuminate\Contracts\Container; use Closure; use Psr\Container\ContainerInterface; interface Container extends ContainerInterface { /** * Determine if the given abstract type has been bound. * * @param string $abstract * @return bool */ public function bound($abstract); /** * Alias a type to a different name. * * @param string $abstract * @param string $alias * @return void * * @throws \LogicException */ public function alias($abstract, $alias); /** * Assign a set of tags to a given binding. * * @param array|string $abstracts * @param array|mixed ...$tags * @return void */ public function tag($abstracts, $tags); /** * Resolve all of the bindings for a given tag. * * @param string $tag * @return iterable */ public function tagged($tag); /** * Register a binding with the container. * * @param string $abstract * @param \Closure|string|null $concrete * @param bool $shared * @return void */ public function bind($abstract, $concrete = null, $shared = false); /** * Register a binding if it hasn't already been registered. * * @param string $abstract * @param \Closure|string|null $concrete * @param bool $shared * @return void */ public function bindIf($abstract, $concrete = null, $shared = false); /** * Register a shared binding in the container. * * @param string $abstract * @param \Closure|string|null $concrete * @return void */ public function singleton($abstract, $concrete = null); /** * Register a shared binding if it hasn't already been registered. * * @param string $abstract * @param \Closure|string|null $concrete * @return void */ public function singletonIf($abstract, $concrete = null); /** * "Extend" an abstract type in the container. * * @param string $abstract * @param \Closure $closure * @return void * * @throws \InvalidArgumentException */ public function extend($abstract, Closure $closure); /** * Register an existing instance as shared in the container. * * @param string $abstract * @param mixed $instance * @return mixed */ public function instance($abstract, $instance); /** * Add a contextual binding to the container. * * @param string $concrete * @param string $abstract * @param \Closure|string $implementation * @return void */ public function addContextualBinding($concrete, $abstract, $implementation); /** * Define a contextual binding. * * @param string|array $concrete * @return \Illuminate\Contracts\Container\ContextualBindingBuilder */ public function when($concrete); /** * Get a closure to resolve the given type from the container. * * @param string $abstract * @return \Closure */ public function factory($abstract); /** * Flush the container of all bindings and resolved instances. * * @return void */ public function flush(); /** * Resolve the given type from the container. * * @param string $abstract * @param array $parameters * @return mixed * * @throws \Illuminate\Contracts\Container\BindingResolutionException */ public function make($abstract, array $parameters = []); /** * Call the given Closure / class@method and inject its dependencies. * * @param callable|string $callback * @param array $parameters * @param string|null $defaultMethod * @return mixed */ public function call($callback, array $parameters = [], $defaultMethod = null); /** * Determine if the given abstract type has been resolved. * * @param string $abstract * @return bool */ public function resolved($abstract); /** * Register a new resolving callback. * * @param \Closure|string $abstract * @param \Closure|null $callback * @return void */ public function resolving($abstract, Closure $callback = null); /** * Register a new after resolving callback. * * @param \Closure|string $abstract * @param \Closure|null $callback * @return void */ public function afterResolving($abstract, Closure $callback = null); } contracts/Container/BindingResolutionException.php 0000644 00000000326 14736103231 0016515 0 ustar 00 <?php namespace Illuminate\Contracts\Container; use Exception; use Psr\Container\ContainerExceptionInterface; class BindingResolutionException extends Exception implements ContainerExceptionInterface { // } contracts/Container/ContextualBindingBuilder.php 0000644 00000000717 14736103231 0016134 0 ustar 00 <?php namespace Illuminate\Contracts\Container; interface ContextualBindingBuilder { /** * Define the abstract target that depends on the context. * * @param string $abstract * @return $this */ public function needs($abstract); /** * Define the implementation for the contextual binding. * * @param \Closure|string $implementation * @return void */ public function give($implementation); } contracts/Foundation/Application.php 0000644 00000011301 14736103231 0013622 0 ustar 00 <?php namespace Illuminate\Contracts\Foundation; use Illuminate\Contracts\Container\Container; interface Application extends Container { /** * Get the version number of the application. * * @return string */ public function version(); /** * Get the base path of the Laravel installation. * * @param string $path * @return string */ public function basePath($path = ''); /** * Get the path to the bootstrap directory. * * @param string $path Optionally, a path to append to the bootstrap path * @return string */ public function bootstrapPath($path = ''); /** * Get the path to the application configuration files. * * @param string $path Optionally, a path to append to the config path * @return string */ public function configPath($path = ''); /** * Get the path to the database directory. * * @param string $path Optionally, a path to append to the database path * @return string */ public function databasePath($path = ''); /** * Get the path to the resources directory. * * @param string $path * @return string */ public function resourcePath($path = ''); /** * Get the path to the storage directory. * * @return string */ public function storagePath(); /** * Get or check the current application environment. * * @param string|array $environments * @return string|bool */ public function environment(...$environments); /** * Determine if the application is running in the console. * * @return bool */ public function runningInConsole(); /** * Determine if the application is running unit tests. * * @return bool */ public function runningUnitTests(); /** * Determine if the application is currently down for maintenance. * * @return bool */ public function isDownForMaintenance(); /** * Register all of the configured providers. * * @return void */ public function registerConfiguredProviders(); /** * Register a service provider with the application. * * @param \Illuminate\Support\ServiceProvider|string $provider * @param bool $force * @return \Illuminate\Support\ServiceProvider */ public function register($provider, $force = false); /** * Register a deferred provider and service. * * @param string $provider * @param string|null $service * @return void */ public function registerDeferredProvider($provider, $service = null); /** * Resolve a service provider instance from the class name. * * @param string $provider * @return \Illuminate\Support\ServiceProvider */ public function resolveProvider($provider); /** * Boot the application's service providers. * * @return void */ public function boot(); /** * Register a new boot listener. * * @param callable $callback * @return void */ public function booting($callback); /** * Register a new "booted" listener. * * @param callable $callback * @return void */ public function booted($callback); /** * Run the given array of bootstrap classes. * * @param array $bootstrappers * @return void */ public function bootstrapWith(array $bootstrappers); /** * Get the current application locale. * * @return string */ public function getLocale(); /** * Get the application namespace. * * @return string * * @throws \RuntimeException */ public function getNamespace(); /** * Get the registered service provider instances if any exist. * * @param \Illuminate\Support\ServiceProvider|string $provider * @return array */ public function getProviders($provider); /** * Determine if the application has been bootstrapped before. * * @return bool */ public function hasBeenBootstrapped(); /** * Load and boot all of the remaining deferred providers. * * @return void */ public function loadDeferredProviders(); /** * Set the current application locale. * * @param string $locale * @return void */ public function setLocale($locale); /** * Determine if middleware has been disabled for the application. * * @return bool */ public function shouldSkipMiddleware(); /** * Terminate the application. * * @return void */ public function terminate(); } contracts/Foundation/CachesConfiguration.php 0000644 00000001010 14736103231 0015271 0 ustar 00 <?php namespace Illuminate\Contracts\Foundation; interface CachesConfiguration { /** * Determine if the application configuration is cached. * * @return bool */ public function configurationIsCached(); /** * Get the path to the configuration cache file. * * @return string */ public function getCachedConfigPath(); /** * Get the path to the cached services.php file. * * @return string */ public function getCachedServicesPath(); } contracts/Foundation/CachesRoutes.php 0000644 00000000536 14736103231 0013757 0 ustar 00 <?php namespace Illuminate\Contracts\Foundation; interface CachesRoutes { /** * Determine if the application routes are cached. * * @return bool */ public function routesAreCached(); /** * Get the path to the routes cache file. * * @return string */ public function getCachedRoutesPath(); } contracts/Database/Events/MigrationEvent.php 0000644 00000000134 14736103231 0015156 0 ustar 00 <?php namespace Illuminate\Contracts\Database\Events; interface MigrationEvent { // } contracts/Database/ModelIdentifier.php 0000644 00000001737 14736103231 0014034 0 ustar 00 <?php namespace Illuminate\Contracts\Database; class ModelIdentifier { /** * The class name of the model. * * @var string */ public $class; /** * The unique identifier of the model. * * This may be either a single ID or an array of IDs. * * @var mixed */ public $id; /** * The relationships loaded on the model. * * @var array */ public $relations; /** * The connection name of the model. * * @var string|null */ public $connection; /** * Create a new model identifier. * * @param string $class * @param mixed $id * @param array $relations * @param mixed $connection * @return void */ public function __construct($class, $id, array $relations, $connection) { $this->id = $id; $this->class = $class; $this->relations = $relations; $this->connection = $connection; } } contracts/Database/Eloquent/CastsAttributes.php 0000644 00000001366 14736103231 0015707 0 ustar 00 <?php namespace Illuminate\Contracts\Database\Eloquent; interface CastsAttributes { /** * Transform the attribute from the underlying model values. * * @param \Illuminate\Database\Eloquent\Model $model * @param string $key * @param mixed $value * @param array $attributes * @return mixed */ public function get($model, string $key, $value, array $attributes); /** * Transform the attribute to its underlying model values. * * @param \Illuminate\Database\Eloquent\Model $model * @param string $key * @param mixed $value * @param array $attributes * @return array|string */ public function set($model, string $key, $value, array $attributes); } contracts/Database/Eloquent/CastsInboundAttributes.php 0000644 00000000651 14736103231 0017222 0 ustar 00 <?php namespace Illuminate\Contracts\Database\Eloquent; interface CastsInboundAttributes { /** * Transform the attribute to its underlying model values. * * @param \Illuminate\Database\Eloquent\Model $model * @param string $key * @param mixed $value * @param array $attributes * @return array */ public function set($model, string $key, $value, array $attributes); } contracts/Database/Eloquent/Castable.php 0000644 00000000565 14736103231 0014301 0 ustar 00 <?php namespace Illuminate\Contracts\Database\Eloquent; interface Castable { /** * Get the name of the caster class to use when casting from / to this cast target. * * @return string|\Illuminate\Contracts\Database\Eloquent\CastsAttributes|\Illuminate\Contracts\Database\Eloquent\CastsInboundAttributes */ public static function castUsing(); } contracts/Cookie/QueueingFactory.php 0000644 00000001150 14736103231 0013575 0 ustar 00 <?php namespace Illuminate\Contracts\Cookie; interface QueueingFactory extends Factory { /** * Queue a cookie to send with the next response. * * @param array $parameters * @return void */ public function queue(...$parameters); /** * Remove a cookie from the queue. * * @param string $name * @param string|null $path * @return void */ public function unqueue($name, $path = null); /** * Get the cookies which have been queued for the next request. * * @return array */ public function getQueuedCookies(); } contracts/Cookie/Factory.php 0000644 00000002633 14736103231 0012101 0 ustar 00 <?php namespace Illuminate\Contracts\Cookie; interface Factory { /** * Create a new cookie instance. * * @param string $name * @param string $value * @param int $minutes * @param string|null $path * @param string|null $domain * @param bool|null $secure * @param bool $httpOnly * @param bool $raw * @param string|null $sameSite * @return \Symfony\Component\HttpFoundation\Cookie */ public function make($name, $value, $minutes = 0, $path = null, $domain = null, $secure = null, $httpOnly = true, $raw = false, $sameSite = null); /** * Create a cookie that lasts "forever" (five years). * * @param string $name * @param string $value * @param string|null $path * @param string|null $domain * @param bool|null $secure * @param bool $httpOnly * @param bool $raw * @param string|null $sameSite * @return \Symfony\Component\HttpFoundation\Cookie */ public function forever($name, $value, $path = null, $domain = null, $secure = null, $httpOnly = true, $raw = false, $sameSite = null); /** * Expire the given cookie. * * @param string $name * @param string|null $path * @param string|null $domain * @return \Symfony\Component\HttpFoundation\Cookie */ public function forget($name, $path = null, $domain = null); } contracts/Console/Application.php 0000644 00000001005 14736103231 0013116 0 ustar 00 <?php namespace Illuminate\Contracts\Console; interface Application { /** * Run an Artisan console command by name. * * @param string $command * @param array $parameters * @param \Symfony\Component\Console\Output\OutputInterface|null $outputBuffer * @return int */ public function call($command, array $parameters = [], $outputBuffer = null); /** * Get the output from the last command. * * @return string */ public function output(); } contracts/Console/Kernel.php 0000644 00000002612 14736103231 0012100 0 ustar 00 <?php namespace Illuminate\Contracts\Console; interface Kernel { /** * Handle an incoming console command. * * @param \Symfony\Component\Console\Input\InputInterface $input * @param \Symfony\Component\Console\Output\OutputInterface|null $output * @return int */ public function handle($input, $output = null); /** * Run an Artisan console command by name. * * @param string $command * @param array $parameters * @param \Symfony\Component\Console\Output\OutputInterface|null $outputBuffer * @return int */ public function call($command, array $parameters = [], $outputBuffer = null); /** * Queue an Artisan console command by name. * * @param string $command * @param array $parameters * @return \Illuminate\Foundation\Bus\PendingDispatch */ public function queue($command, array $parameters = []); /** * Get all of the commands registered with the console. * * @return array */ public function all(); /** * Get the output for the last run command. * * @return string */ public function output(); /** * Terminate the application. * * @param \Symfony\Component\Console\Input\InputInterface $input * @param int $status * @return void */ public function terminate($input, $status); } contracts/Config/Repository.php 0000644 00000002212 14736103231 0012636 0 ustar 00 <?php namespace Illuminate\Contracts\Config; interface Repository { /** * Determine if the given configuration value exists. * * @param string $key * @return bool */ public function has($key); /** * Get the specified configuration value. * * @param array|string $key * @param mixed $default * @return mixed */ public function get($key, $default = null); /** * Get all of the configuration items for the application. * * @return array */ public function all(); /** * Set a given configuration value. * * @param array|string $key * @param mixed $value * @return void */ public function set($key, $value = null); /** * Prepend a value onto an array configuration value. * * @param string $key * @param mixed $value * @return void */ public function prepend($key, $value); /** * Push a value onto an array configuration value. * * @param string $key * @param mixed $value * @return void */ public function push($key, $value); } contracts/Debug/ExceptionHandler.php 0000644 00000001751 14736103231 0013543 0 ustar 00 <?php namespace Illuminate\Contracts\Debug; use Throwable; interface ExceptionHandler { /** * Report or log an exception. * * @param \Throwable $e * @return void * * @throws \Exception */ public function report(Throwable $e); /** * Determine if the exception should be reported. * * @param \Throwable $e * @return bool */ public function shouldReport(Throwable $e); /** * Render an exception into an HTTP response. * * @param \Illuminate\Http\Request $request * @param \Throwable $e * @return \Symfony\Component\HttpFoundation\Response * * @throws \Throwable */ public function render($request, Throwable $e); /** * Render an exception to the console. * * @param \Symfony\Component\Console\Output\OutputInterface $output * @param \Throwable $e * @return void */ public function renderForConsole($output, Throwable $e); } contracts/Mail/MailQueue.php 0000644 00000001210 14736103231 0012020 0 ustar 00 <?php namespace Illuminate\Contracts\Mail; interface MailQueue { /** * Queue a new e-mail message for sending. * * @param \Illuminate\Contracts\Mail\Mailable|string|array $view * @param string|null $queue * @return mixed */ public function queue($view, $queue = null); /** * Queue a new e-mail message for sending after (n) seconds. * * @param \DateTimeInterface|\DateInterval|int $delay * @param \Illuminate\Contracts\Mail\Mailable|string|array $view * @param string|null $queue * @return mixed */ public function later($delay, $view, $queue = null); } contracts/Mail/Mailable.php 0000644 00000003345 14736103231 0011652 0 ustar 00 <?php namespace Illuminate\Contracts\Mail; use Illuminate\Contracts\Queue\Factory as Queue; interface Mailable { /** * Send the message using the given mailer. * * @param \Illuminate\Contracts\Mail\Factory|\Illuminate\Contracts\Mail\Mailer $mailer * @return void */ public function send($mailer); /** * Queue the given message. * * @param \Illuminate\Contracts\Queue\Factory $queue * @return mixed */ public function queue(Queue $queue); /** * Deliver the queued message after the given delay. * * @param \DateTimeInterface|\DateInterval|int $delay * @param \Illuminate\Contracts\Queue\Factory $queue * @return mixed */ public function later($delay, Queue $queue); /** * Set the recipients of the message. * * @param object|array|string $address * @param string|null $name * @return self */ public function cc($address, $name = null); /** * Set the recipients of the message. * * @param object|array|string $address * @param string|null $name * @return $this */ public function bcc($address, $name = null); /** * Set the recipients of the message. * * @param object|array|string $address * @param string|null $name * @return $this */ public function to($address, $name = null); /** * Set the locale of the message. * * @param string $locale * @return $this */ public function locale($locale); /** * Set the name of the mailer that should be used to send the message. * * @param string $mailer * @return $this */ public function mailer($mailer); } contracts/Mail/Mailer.php 0000644 00000002056 14736103231 0011353 0 ustar 00 <?php namespace Illuminate\Contracts\Mail; interface Mailer { /** * Begin the process of mailing a mailable class instance. * * @param mixed $users * @return \Illuminate\Mail\PendingMail */ public function to($users); /** * Begin the process of mailing a mailable class instance. * * @param mixed $users * @return \Illuminate\Mail\PendingMail */ public function bcc($users); /** * Send a new message with only a raw text part. * * @param string $text * @param mixed $callback * @return void */ public function raw($text, $callback); /** * Send a new message using a view. * * @param \Illuminate\Contracts\Mail\Mailable|string|array $view * @param array $data * @param \Closure|string|null $callback * @return void */ public function send($view, array $data = [], $callback = null); /** * Get the array of failed recipients. * * @return array */ public function failures(); } contracts/Mail/Factory.php 0000644 00000000363 14736103231 0011550 0 ustar 00 <?php namespace Illuminate\Contracts\Mail; interface Factory { /** * Get a mailer instance by name. * * @param string|null $name * @return \Illuminate\Mail\Mailer */ public function mailer($name = null); } contracts/Cache/Store.php 0000644 00000003555 14736103231 0011364 0 ustar 00 <?php namespace Illuminate\Contracts\Cache; interface Store { /** * Retrieve an item from the cache by key. * * @param string|array $key * @return mixed */ public function get($key); /** * Retrieve multiple items from the cache by key. * * Items not found in the cache will have a null value. * * @param array $keys * @return array */ public function many(array $keys); /** * Store an item in the cache for a given number of seconds. * * @param string $key * @param mixed $value * @param int $seconds * @return bool */ public function put($key, $value, $seconds); /** * Store multiple items in the cache for a given number of seconds. * * @param array $values * @param int $seconds * @return bool */ public function putMany(array $values, $seconds); /** * Increment the value of an item in the cache. * * @param string $key * @param mixed $value * @return int|bool */ public function increment($key, $value = 1); /** * Decrement the value of an item in the cache. * * @param string $key * @param mixed $value * @return int|bool */ public function decrement($key, $value = 1); /** * Store an item in the cache indefinitely. * * @param string $key * @param mixed $value * @return bool */ public function forever($key, $value); /** * Remove an item from the cache. * * @param string $key * @return bool */ public function forget($key); /** * Remove all items from the cache. * * @return bool */ public function flush(); /** * Get the cache key prefix. * * @return string */ public function getPrefix(); } contracts/Cache/LockTimeoutException.php 0000644 00000000166 14736103231 0014401 0 ustar 00 <?php namespace Illuminate\Contracts\Cache; use Exception; class LockTimeoutException extends Exception { // } contracts/Cache/Repository.php 0000644 00000005061 14736103231 0012441 0 ustar 00 <?php namespace Illuminate\Contracts\Cache; use Closure; use Psr\SimpleCache\CacheInterface; interface Repository extends CacheInterface { /** * Retrieve an item from the cache and delete it. * * @param string $key * @param mixed $default * @return mixed */ public function pull($key, $default = null); /** * Store an item in the cache. * * @param string $key * @param mixed $value * @param \DateTimeInterface|\DateInterval|int|null $ttl * @return bool */ public function put($key, $value, $ttl = null); /** * Store an item in the cache if the key does not exist. * * @param string $key * @param mixed $value * @param \DateTimeInterface|\DateInterval|int|null $ttl * @return bool */ public function add($key, $value, $ttl = null); /** * Increment the value of an item in the cache. * * @param string $key * @param mixed $value * @return int|bool */ public function increment($key, $value = 1); /** * Decrement the value of an item in the cache. * * @param string $key * @param mixed $value * @return int|bool */ public function decrement($key, $value = 1); /** * Store an item in the cache indefinitely. * * @param string $key * @param mixed $value * @return bool */ public function forever($key, $value); /** * Get an item from the cache, or execute the given Closure and store the result. * * @param string $key * @param \DateTimeInterface|\DateInterval|int|null $ttl * @param \Closure $callback * @return mixed */ public function remember($key, $ttl, Closure $callback); /** * Get an item from the cache, or execute the given Closure and store the result forever. * * @param string $key * @param \Closure $callback * @return mixed */ public function sear($key, Closure $callback); /** * Get an item from the cache, or execute the given Closure and store the result forever. * * @param string $key * @param \Closure $callback * @return mixed */ public function rememberForever($key, Closure $callback); /** * Remove an item from the cache. * * @param string $key * @return bool */ public function forget($key); /** * Get the cache store implementation. * * @return \Illuminate\Contracts\Cache\Store */ public function getStore(); } contracts/Cache/Lock.php 0000644 00000001462 14736103231 0011153 0 ustar 00 <?php namespace Illuminate\Contracts\Cache; interface Lock { /** * Attempt to acquire the lock. * * @param callable|null $callback * @return mixed */ public function get($callback = null); /** * Attempt to acquire the lock for the given number of seconds. * * @param int $seconds * @param callable|null $callback * @return bool */ public function block($seconds, $callback = null); /** * Release the lock. * * @return void */ public function release(); /** * Returns the current owner of the lock. * * @return string */ public function owner(); /** * Releases this lock in disregard of ownership. * * @return void */ public function forceRelease(); } contracts/Cache/LockProvider.php 0000644 00000001065 14736103231 0012665 0 ustar 00 <?php namespace Illuminate\Contracts\Cache; interface LockProvider { /** * Get a lock instance. * * @param string $name * @param int $seconds * @param string|null $owner * @return \Illuminate\Contracts\Cache\Lock */ public function lock($name, $seconds = 0, $owner = null); /** * Restore a lock instance using the owner identifier. * * @param string $name * @param string $owner * @return \Illuminate\Contracts\Cache\Lock */ public function restoreLock($name, $owner); } contracts/Cache/Factory.php 0000644 00000000407 14736103231 0011670 0 ustar 00 <?php namespace Illuminate\Contracts\Cache; interface Factory { /** * Get a cache store instance by name. * * @param string|null $name * @return \Illuminate\Contracts\Cache\Repository */ public function store($name = null); } contracts/Redis/LimiterTimeoutException.php 0000644 00000000171 14736103231 0015155 0 ustar 00 <?php namespace Illuminate\Contracts\Redis; use Exception; class LimiterTimeoutException extends Exception { // } contracts/Redis/Database.php 0000644 00000000442 14736103231 0012027 0 ustar 00 <?php namespace Illuminate\Contracts\Redis; interface Database { /** * Run a command against the Redis database. * * @param string $method * @param array $parameters * @return mixed */ public function command($method, array $parameters = []); } contracts/Redis/Connector.php 0000644 00000001174 14736103231 0012260 0 ustar 00 <?php namespace Illuminate\Contracts\Redis; interface Connector { /** * Create a connection to a Redis cluster. * * @param array $config * @param array $options * @return \Illuminate\Redis\Connections\Connection */ public function connect(array $config, array $options); /** * Create a connection to a Redis instance. * * @param array $config * @param array $clusterOptions * @param array $options * @return \Illuminate\Redis\Connections\Connection */ public function connectToCluster(array $config, array $clusterOptions, array $options); } contracts/Redis/Factory.php 0000644 00000000412 14736103231 0011727 0 ustar 00 <?php namespace Illuminate\Contracts\Redis; interface Factory { /** * Get a Redis connection by name. * * @param string|null $name * @return \Illuminate\Redis\Connections\Connection */ public function connection($name = null); } contracts/Redis/Connection.php 0000644 00000001416 14736103231 0012424 0 ustar 00 <?php namespace Illuminate\Contracts\Redis; use Closure; interface Connection { /** * Subscribe to a set of given channels for messages. * * @param array|string $channels * @param \Closure $callback * @return void */ public function subscribe($channels, Closure $callback); /** * Subscribe to a set of given channels with wildcards. * * @param array|string $channels * @param \Closure $callback * @return void */ public function psubscribe($channels, Closure $callback); /** * Run a command against the Redis database. * * @param string $method * @param array $parameters * @return mixed */ public function command($method, array $parameters = []); } contracts/Pipeline/Pipeline.php 0000644 00000001367 14736103231 0012576 0 ustar 00 <?php namespace Illuminate\Contracts\Pipeline; use Closure; interface Pipeline { /** * Set the traveler object being sent on the pipeline. * * @param mixed $traveler * @return $this */ public function send($traveler); /** * Set the stops of the pipeline. * * @param dynamic|array $stops * @return $this */ public function through($stops); /** * Set the method to call on the stops. * * @param string $method * @return $this */ public function via($method); /** * Run the pipeline with a final destination callback. * * @param \Closure $destination * @return mixed */ public function then(Closure $destination); } contracts/Pipeline/Hub.php 0000644 00000000446 14736103231 0011544 0 ustar 00 <?php namespace Illuminate\Contracts\Pipeline; interface Hub { /** * Send an object through one of the available pipelines. * * @param mixed $object * @param string|null $pipeline * @return mixed */ public function pipe($object, $pipeline = null); } contracts/Queue/Queue.php 0000644 00000004415 14736103231 0011431 0 ustar 00 <?php namespace Illuminate\Contracts\Queue; interface Queue { /** * Get the size of the queue. * * @param string|null $queue * @return int */ public function size($queue = null); /** * Push a new job onto the queue. * * @param string|object $job * @param mixed $data * @param string|null $queue * @return mixed */ public function push($job, $data = '', $queue = null); /** * Push a new job onto the queue. * * @param string $queue * @param string|object $job * @param mixed $data * @return mixed */ public function pushOn($queue, $job, $data = ''); /** * Push a raw payload onto the queue. * * @param string $payload * @param string|null $queue * @param array $options * @return mixed */ public function pushRaw($payload, $queue = null, array $options = []); /** * Push a new job onto the queue after a delay. * * @param \DateTimeInterface|\DateInterval|int $delay * @param string|object $job * @param mixed $data * @param string|null $queue * @return mixed */ public function later($delay, $job, $data = '', $queue = null); /** * Push a new job onto the queue after a delay. * * @param string $queue * @param \DateTimeInterface|\DateInterval|int $delay * @param string|object $job * @param mixed $data * @return mixed */ public function laterOn($queue, $delay, $job, $data = ''); /** * Push an array of jobs onto the queue. * * @param array $jobs * @param mixed $data * @param string|null $queue * @return mixed */ public function bulk($jobs, $data = '', $queue = null); /** * Pop the next job off of the queue. * * @param string|null $queue * @return \Illuminate\Contracts\Queue\Job|null */ public function pop($queue = null); /** * Get the connection name for the queue. * * @return string */ public function getConnectionName(); /** * Set the connection name for the queue. * * @param string $name * @return $this */ public function setConnectionName($name); } contracts/Queue/Job.php 0000644 00000006036 14736103231 0011060 0 ustar 00 <?php namespace Illuminate\Contracts\Queue; interface Job { /** * Get the UUID of the job. * * @return string|null */ public function uuid(); /** * Get the job identifier. * * @return string */ public function getJobId(); /** * Get the decoded body of the job. * * @return array */ public function payload(); /** * Fire the job. * * @return void */ public function fire(); /** * Release the job back into the queue. * * Accepts a delay specified in seconds. * * @param int $delay * @return void */ public function release($delay = 0); /** * Determine if the job was released back into the queue. * * @return bool */ public function isReleased(); /** * Delete the job from the queue. * * @return void */ public function delete(); /** * Determine if the job has been deleted. * * @return bool */ public function isDeleted(); /** * Determine if the job has been deleted or released. * * @return bool */ public function isDeletedOrReleased(); /** * Get the number of times the job has been attempted. * * @return int */ public function attempts(); /** * Determine if the job has been marked as a failure. * * @return bool */ public function hasFailed(); /** * Mark the job as "failed". * * @return void */ public function markAsFailed(); /** * Delete the job, call the "failed" method, and raise the failed job event. * * @param \Throwable|null $e * @return void */ public function fail($e = null); /** * Get the number of times to attempt a job. * * @return int|null */ public function maxTries(); /** * Get the maximum number of exceptions allowed, regardless of attempts. * * @return int|null */ public function maxExceptions(); /** * Get the number of seconds the job can run. * * @return int|null */ public function timeout(); /** * Get the timestamp indicating when the job should timeout. * * @return int|null */ public function timeoutAt(); /** * Get the name of the queued job class. * * @return string */ public function getName(); /** * Get the resolved name of the queued job class. * * Resolves the name of "wrapped" jobs such as class-based handlers. * * @return string */ public function resolveName(); /** * Get the name of the connection the job belongs to. * * @return string */ public function getConnectionName(); /** * Get the name of the queue the job belongs to. * * @return string */ public function getQueue(); /** * Get the raw body string for the job. * * @return string */ public function getRawBody(); } contracts/Queue/Monitor.php 0000644 00000001240 14736103231 0011765 0 ustar 00 <?php namespace Illuminate\Contracts\Queue; interface Monitor { /** * Register a callback to be executed on every iteration through the queue loop. * * @param mixed $callback * @return void */ public function looping($callback); /** * Register a callback to be executed when a job fails after the maximum amount of retries. * * @param mixed $callback * @return void */ public function failing($callback); /** * Register a callback to be executed when a daemon queue is stopping. * * @param mixed $callback * @return void */ public function stopping($callback); } contracts/Queue/QueueableEntity.php 0000644 00000000741 14736103231 0013450 0 ustar 00 <?php namespace Illuminate\Contracts\Queue; interface QueueableEntity { /** * Get the queueable identity for the entity. * * @return mixed */ public function getQueueableId(); /** * Get the relationships for the entity. * * @return array */ public function getQueueableRelations(); /** * Get the connection of the entity. * * @return string|null */ public function getQueueableConnection(); } contracts/Queue/QueueableCollection.php 0000644 00000001223 14736103231 0014263 0 ustar 00 <?php namespace Illuminate\Contracts\Queue; interface QueueableCollection { /** * Get the type of the entities being queued. * * @return string|null */ public function getQueueableClass(); /** * Get the identifiers for all of the entities. * * @return array */ public function getQueueableIds(); /** * Get the relationships of the entities being queued. * * @return array */ public function getQueueableRelations(); /** * Get the connection of the entities being queued. * * @return string|null */ public function getQueueableConnection(); } contracts/Queue/ShouldQueue.php 0000644 00000000117 14736103231 0012603 0 ustar 00 <?php namespace Illuminate\Contracts\Queue; interface ShouldQueue { // } contracts/Queue/EntityResolver.php 0000644 00000000403 14736103231 0013334 0 ustar 00 <?php namespace Illuminate\Contracts\Queue; interface EntityResolver { /** * Resolve the entity for the given ID. * * @param string $type * @param mixed $id * @return mixed */ public function resolve($type, $id); } contracts/Queue/Factory.php 0000644 00000000410 14736103231 0011743 0 ustar 00 <?php namespace Illuminate\Contracts\Queue; interface Factory { /** * Resolve a queue connection instance. * * @param string|null $name * @return \Illuminate\Contracts\Queue\Queue */ public function connection($name = null); } contracts/Queue/EntityNotFoundException.php 0000644 00000000704 14736103231 0015152 0 ustar 00 <?php namespace Illuminate\Contracts\Queue; use InvalidArgumentException; class EntityNotFoundException extends InvalidArgumentException { /** * Create a new exception instance. * * @param string $type * @param mixed $id * @return void */ public function __construct($type, $id) { $id = (string) $id; parent::__construct("Queueable entity [{$type}] not found for ID [{$id}]."); } } contracts/Logging/Log.php 0000644 00000004214 14736103231 0011365 0 ustar 00 <?php namespace Illuminate\Contracts\Logging; interface Log { /** * Log an alert message to the logs. * * @param string $message * @param array $context * @return void */ public function alert($message, array $context = []); /** * Log a critical message to the logs. * * @param string $message * @param array $context * @return void */ public function critical($message, array $context = []); /** * Log an error message to the logs. * * @param string $message * @param array $context * @return void */ public function error($message, array $context = []); /** * Log a warning message to the logs. * * @param string $message * @param array $context * @return void */ public function warning($message, array $context = []); /** * Log a notice to the logs. * * @param string $message * @param array $context * @return void */ public function notice($message, array $context = []); /** * Log an informational message to the logs. * * @param string $message * @param array $context * @return void */ public function info($message, array $context = []); /** * Log a debug message to the logs. * * @param string $message * @param array $context * @return void */ public function debug($message, array $context = []); /** * Log a message to the logs. * * @param string $level * @param string $message * @param array $context * @return void */ public function log($level, $message, array $context = []); /** * Register a file log handler. * * @param string $path * @param string $level * @return void */ public function useFiles($path, $level = 'debug'); /** * Register a daily file log handler. * * @param string $path * @param int $days * @param string $level * @return void */ public function useDailyFiles($path, $days = 0, $level = 'debug'); } contracts/Http/Kernel.php 0000644 00000001560 14736103231 0011416 0 ustar 00 <?php namespace Illuminate\Contracts\Http; interface Kernel { /** * Bootstrap the application for HTTP requests. * * @return void */ public function bootstrap(); /** * Handle an incoming HTTP request. * * @param \Symfony\Component\HttpFoundation\Request $request * @return \Symfony\Component\HttpFoundation\Response */ public function handle($request); /** * Perform any final actions for the request lifecycle. * * @param \Symfony\Component\HttpFoundation\Request $request * @param \Symfony\Component\HttpFoundation\Response $response * @return void */ public function terminate($request, $response); /** * Get the Laravel application instance. * * @return \Illuminate\Contracts\Foundation\Application */ public function getApplication(); } contracts/Translation/Translator.php 0000644 00000001625 14736103231 0013710 0 ustar 00 <?php namespace Illuminate\Contracts\Translation; interface Translator { /** * Get the translation for a given key. * * @param string $key * @param array $replace * @param string|null $locale * @return mixed */ public function get($key, array $replace = [], $locale = null); /** * Get a translation according to an integer value. * * @param string $key * @param \Countable|int|array $number * @param array $replace * @param string|null $locale * @return string */ public function choice($key, $number, array $replace = [], $locale = null); /** * Get the default locale being used. * * @return string */ public function getLocale(); /** * Set the default locale. * * @param string $locale * @return void */ public function setLocale($locale); } contracts/Translation/HasLocalePreference.php 0000644 00000000336 14736103231 0015407 0 ustar 00 <?php namespace Illuminate\Contracts\Translation; interface HasLocalePreference { /** * Get the preferred locale of the entity. * * @return string|null */ public function preferredLocale(); } contracts/Translation/Loader.php 0000644 00000001460 14736103231 0012762 0 ustar 00 <?php namespace Illuminate\Contracts\Translation; interface Loader { /** * Load the messages for the given locale. * * @param string $locale * @param string $group * @param string|null $namespace * @return array */ public function load($locale, $group, $namespace = null); /** * Add a new namespace to the loader. * * @param string $namespace * @param string $hint * @return void */ public function addNamespace($namespace, $hint); /** * Add a new JSON path to the loader. * * @param string $path * @return void */ public function addJsonPath($path); /** * Get an array of all the registered namespaces. * * @return array */ public function namespaces(); } contracts/View/View.php 0000644 00000001035 14736103231 0011100 0 ustar 00 <?php namespace Illuminate\Contracts\View; use Illuminate\Contracts\Support\Renderable; interface View extends Renderable { /** * Get the name of the view. * * @return string */ public function name(); /** * Add a piece of data to the view. * * @param string|array $key * @param mixed $value * @return $this */ public function with($key, $value = null); /** * Get the array of view data. * * @return array */ public function getData(); } contracts/View/Factory.php 0000644 00000003615 14736103231 0011603 0 ustar 00 <?php namespace Illuminate\Contracts\View; interface Factory { /** * Determine if a given view exists. * * @param string $view * @return bool */ public function exists($view); /** * Get the evaluated view contents for the given path. * * @param string $path * @param \Illuminate\Contracts\Support\Arrayable|array $data * @param array $mergeData * @return \Illuminate\Contracts\View\View */ public function file($path, $data = [], $mergeData = []); /** * Get the evaluated view contents for the given view. * * @param string $view * @param \Illuminate\Contracts\Support\Arrayable|array $data * @param array $mergeData * @return \Illuminate\Contracts\View\View */ public function make($view, $data = [], $mergeData = []); /** * Add a piece of shared data to the environment. * * @param array|string $key * @param mixed $value * @return mixed */ public function share($key, $value = null); /** * Register a view composer event. * * @param array|string $views * @param \Closure|string $callback * @return array */ public function composer($views, $callback); /** * Register a view creator event. * * @param array|string $views * @param \Closure|string $callback * @return array */ public function creator($views, $callback); /** * Add a new namespace to the loader. * * @param string $namespace * @param string|array $hints * @return $this */ public function addNamespace($namespace, $hints); /** * Replace the namespace hints for the given namespace. * * @param string $namespace * @param string|array $hints * @return $this */ public function replaceNamespace($namespace, $hints); } contracts/View/Engine.php 0000644 00000000411 14736103231 0011370 0 ustar 00 <?php namespace Illuminate\Contracts\View; interface Engine { /** * Get the evaluated contents of the view. * * @param string $path * @param array $data * @return string */ public function get($path, array $data = []); } contracts/LICENSE.md 0000644 00000002063 14736103231 0010151 0 ustar 00 The MIT License (MIT) Copyright (c) Taylor Otwell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. contracts/Bus/SelfHandling.php 0000644 00000000251 14736103231 0012342 0 ustar 00 <?php namespace Illuminate\Contracts\Bus; /** * @deprecated since version 5.2. Remove from jobs since self-handling is default. */ interface SelfHandling { // } contracts/Bus/QueueingDispatcher.php 0000644 00000000437 14736103231 0013603 0 ustar 00 <?php namespace Illuminate\Contracts\Bus; interface QueueingDispatcher extends Dispatcher { /** * Dispatch a command to its appropriate handler behind a queue. * * @param mixed $command * @return mixed */ public function dispatchToQueue($command); } contracts/Bus/Dispatcher.php 0000644 00000002223 14736103231 0012073 0 ustar 00 <?php namespace Illuminate\Contracts\Bus; interface Dispatcher { /** * Dispatch a command to its appropriate handler. * * @param mixed $command * @return mixed */ public function dispatch($command); /** * Dispatch a command to its appropriate handler in the current process. * * @param mixed $command * @param mixed $handler * @return mixed */ public function dispatchNow($command, $handler = null); /** * Determine if the given command has a handler. * * @param mixed $command * @return bool */ public function hasCommandHandler($command); /** * Retrieve the handler for a command. * * @param mixed $command * @return bool|mixed */ public function getCommandHandler($command); /** * Set the pipes commands should be piped through before dispatching. * * @param array $pipes * @return $this */ public function pipeThrough(array $pipes); /** * Map a command to a handler. * * @param array $map * @return $this */ public function map(array $map); } contracts/Validation/Validator.php 0000644 00000002353 14736103231 0013277 0 ustar 00 <?php namespace Illuminate\Contracts\Validation; use Illuminate\Contracts\Support\MessageProvider; interface Validator extends MessageProvider { /** * Run the validator's rules against its data. * * @return array */ public function validate(); /** * Get the attributes and values that were validated. * * @return array */ public function validated(); /** * Determine if the data fails the validation rules. * * @return bool */ public function fails(); /** * Get the failed validation rules. * * @return array */ public function failed(); /** * Add conditions to a given field based on a Closure. * * @param string|array $attribute * @param string|array $rules * @param callable $callback * @return $this */ public function sometimes($attribute, $rules, callable $callback); /** * Add an after validation callback. * * @param callable|string $callback * @return $this */ public function after($callback); /** * Get all of the validation error messages. * * @return \Illuminate\Support\MessageBag */ public function errors(); } contracts/Validation/Rule.php 0000644 00000000614 14736103231 0012257 0 ustar 00 <?php namespace Illuminate\Contracts\Validation; interface Rule { /** * Determine if the validation rule passes. * * @param string $attribute * @param mixed $value * @return bool */ public function passes($attribute, $value); /** * Get the validation error message. * * @return string|array */ public function message(); } contracts/Validation/ValidationException.php 0000644 00000002024 14736103231 0015316 0 ustar 00 <?php namespace Illuminate\Contracts\Validation; use RuntimeException; use Illuminate\Contracts\Support\MessageProvider; class ValidationException extends RuntimeException { /** * The message provider implementation. * * @var \Illuminate\Contracts\Support\MessageProvider */ protected $provider; /** * Create a new validation exception instance. * * @param \Illuminate\Contracts\Support\MessageProvider $provider * @return void */ public function __construct(MessageProvider $provider) { $this->provider = $provider; } /** * Get the validation error message provider. * * @return \Illuminate\Contracts\Support\MessageBag */ public function errors() { return $this->provider->getMessageBag(); } /** * Get the validation error message provider. * * @return \Illuminate\Contracts\Support\MessageProvider */ public function getMessageProvider() { return $this->provider; } } contracts/Validation/ImplicitRule.php 0000644 00000000142 14736103231 0013746 0 ustar 00 <?php namespace Illuminate\Contracts\Validation; interface ImplicitRule extends Rule { // } contracts/Validation/UnauthorizedException.php 0000644 00000000212 14736103231 0015702 0 ustar 00 <?php namespace Illuminate\Contracts\Validation; use RuntimeException; class UnauthorizedException extends RuntimeException { // } contracts/Validation/Factory.php 0000644 00000002254 14736103231 0012761 0 ustar 00 <?php namespace Illuminate\Contracts\Validation; interface Factory { /** * Create a new Validator instance. * * @param array $data * @param array $rules * @param array $messages * @param array $customAttributes * @return \Illuminate\Contracts\Validation\Validator */ public function make(array $data, array $rules, array $messages = [], array $customAttributes = []); /** * Register a custom validator extension. * * @param string $rule * @param \Closure|string $extension * @param string|null $message * @return void */ public function extend($rule, $extension, $message = null); /** * Register a custom implicit validator extension. * * @param string $rule * @param \Closure|string $extension * @param string|null $message * @return void */ public function extendImplicit($rule, $extension, $message = null); /** * Register a custom implicit validator message replacer. * * @param string $rule * @param \Closure|string $replacer * @return void */ public function replacer($rule, $replacer); } contracts/Validation/ValidatesWhenResolved.php 0000644 00000000324 14736103231 0015610 0 ustar 00 <?php namespace Illuminate\Contracts\Validation; interface ValidatesWhenResolved { /** * Validate the given class instance. * * @return void */ public function validateResolved(); } contracts/Support/Htmlable.php 0000644 00000000272 14736103231 0012462 0 ustar 00 <?php namespace Illuminate\Contracts\Support; interface Htmlable { /** * Get content as a string of HTML. * * @return string */ public function toHtml(); } contracts/Support/Jsonable.php 0000644 00000000361 14736103231 0012466 0 ustar 00 <?php namespace Illuminate\Contracts\Support; interface Jsonable { /** * Convert the object to its JSON representation. * * @param int $options * @return string */ public function toJson($options = 0); } contracts/Support/MessageProvider.php 0000644 00000000354 14736103231 0014032 0 ustar 00 <?php namespace Illuminate\Contracts\Support; interface MessageProvider { /** * Get the messages for the instance. * * @return \Illuminate\Contracts\Support\MessageBag */ public function getMessageBag(); } contracts/Support/Renderable.php 0000644 00000000305 14736103231 0012772 0 ustar 00 <?php namespace Illuminate\Contracts\Support; interface Renderable { /** * Get the evaluated contents of the object. * * @return string */ public function render(); } contracts/Support/Responsable.php 0000644 00000000462 14736103231 0013210 0 ustar 00 <?php namespace Illuminate\Contracts\Support; interface Responsable { /** * Create an HTTP response that represents the object. * * @param \Illuminate\Http\Request $request * @return \Symfony\Component\HttpFoundation\Response */ public function toResponse($request); } contracts/Support/MessageBag.php 0000644 00000004212 14736103231 0012726 0 ustar 00 <?php namespace Illuminate\Contracts\Support; interface MessageBag extends Arrayable { /** * Get the keys present in the message bag. * * @return array */ public function keys(); /** * Add a message to the bag. * * @param string $key * @param string $message * @return $this */ public function add($key, $message); /** * Merge a new array of messages into the bag. * * @param \Illuminate\Contracts\Support\MessageProvider|array $messages * @return $this */ public function merge($messages); /** * Determine if messages exist for a given key. * * @param string|array $key * @return bool */ public function has($key); /** * Get the first message from the bag for a given key. * * @param string|null $key * @param string|null $format * @return string */ public function first($key = null, $format = null); /** * Get all of the messages from the bag for a given key. * * @param string $key * @param string|null $format * @return array */ public function get($key, $format = null); /** * Get all of the messages for every key in the bag. * * @param string|null $format * @return array */ public function all($format = null); /** * Get the raw messages in the container. * * @return array */ public function getMessages(); /** * Get the default message format. * * @return string */ public function getFormat(); /** * Set the default message format. * * @param string $format * @return $this */ public function setFormat($format = ':message'); /** * Determine if the message bag has any messages. * * @return bool */ public function isEmpty(); /** * Determine if the message bag has any messages. * * @return bool */ public function isNotEmpty(); /** * Get the number of messages in the container. * * @return int */ public function count(); } contracts/Support/Arrayable.php 0000644 00000000270 14736103231 0012632 0 ustar 00 <?php namespace Illuminate\Contracts\Support; interface Arrayable { /** * Get the instance as an array. * * @return array */ public function toArray(); } contracts/Support/DeferrableProvider.php 0000644 00000000317 14736103231 0014500 0 ustar 00 <?php namespace Illuminate\Contracts\Support; interface DeferrableProvider { /** * Get the services provided by the provider. * * @return array */ public function provides(); } contracts/Support/DeferringDisplayableValue.php 0000644 00000000435 14736103231 0016007 0 ustar 00 <?php namespace Illuminate\Contracts\Support; interface DeferringDisplayableValue { /** * Resolve the displayable value that the class is deferring. * * @return \Illuminate\Contracts\Support\Htmlable|string */ public function resolveDisplayableValue(); } contracts/Hashing/Hasher.php 0000644 00000001662 14736103231 0012055 0 ustar 00 <?php namespace Illuminate\Contracts\Hashing; interface Hasher { /** * Get information about the given hashed value. * * @param string $hashedValue * @return array */ public function info($hashedValue); /** * Hash the given value. * * @param string $value * @param array $options * @return string */ public function make($value, array $options = []); /** * Check the given plain value against a hash. * * @param string $value * @param string $hashedValue * @param array $options * @return bool */ public function check($value, $hashedValue, array $options = []); /** * Check if the given hash has been hashed using the given options. * * @param string $hashedValue * @param array $options * @return bool */ public function needsRehash($hashedValue, array $options = []); } contracts/Routing/Registrar.php 0000644 00000005203 14736103231 0012646 0 ustar 00 <?php namespace Illuminate\Contracts\Routing; interface Registrar { /** * Register a new GET route with the router. * * @param string $uri * @param array|string|callable $action * @return \Illuminate\Routing\Route */ public function get($uri, $action); /** * Register a new POST route with the router. * * @param string $uri * @param array|string|callable $action * @return \Illuminate\Routing\Route */ public function post($uri, $action); /** * Register a new PUT route with the router. * * @param string $uri * @param array|string|callable $action * @return \Illuminate\Routing\Route */ public function put($uri, $action); /** * Register a new DELETE route with the router. * * @param string $uri * @param array|string|callable $action * @return \Illuminate\Routing\Route */ public function delete($uri, $action); /** * Register a new PATCH route with the router. * * @param string $uri * @param array|string|callable $action * @return \Illuminate\Routing\Route */ public function patch($uri, $action); /** * Register a new OPTIONS route with the router. * * @param string $uri * @param array|string|callable $action * @return \Illuminate\Routing\Route */ public function options($uri, $action); /** * Register a new route with the given verbs. * * @param array|string $methods * @param string $uri * @param array|string|callable $action * @return \Illuminate\Routing\Route */ public function match($methods, $uri, $action); /** * Route a resource to a controller. * * @param string $name * @param string $controller * @param array $options * @return \Illuminate\Routing\PendingResourceRegistration */ public function resource($name, $controller, array $options = []); /** * Create a route group with shared attributes. * * @param array $attributes * @param \Closure|string $routes * @return void */ public function group(array $attributes, $routes); /** * Substitute the route bindings onto the route. * * @param \Illuminate\Routing\Route $route * @return \Illuminate\Routing\Route */ public function substituteBindings($route); /** * Substitute the implicit Eloquent model bindings for the route. * * @param \Illuminate\Routing\Route $route * @return void */ public function substituteImplicitBindings($route); } contracts/Routing/UrlRoutable.php 0000644 00000001561 14736103231 0013147 0 ustar 00 <?php namespace Illuminate\Contracts\Routing; interface UrlRoutable { /** * Get the value of the model's route key. * * @return mixed */ public function getRouteKey(); /** * Get the route key for the model. * * @return string */ public function getRouteKeyName(); /** * Retrieve the model for a bound value. * * @param mixed $value * @param string|null $field * @return \Illuminate\Database\Eloquent\Model|null */ public function resolveRouteBinding($value, $field = null); /** * Retrieve the child model for a bound value. * * @param string $childType * @param mixed $value * @param string|null $field * @return \Illuminate\Database\Eloquent\Model|null */ public function resolveChildRouteBinding($childType, $value, $field); } contracts/Routing/UrlGenerator.php 0000644 00000003400 14736103231 0013312 0 ustar 00 <?php namespace Illuminate\Contracts\Routing; interface UrlGenerator { /** * Get the current URL for the request. * * @return string */ public function current(); /** * Get the URL for the previous request. * * @param mixed $fallback * @return string */ public function previous($fallback = false); /** * Generate an absolute URL to the given path. * * @param string $path * @param mixed $extra * @param bool|null $secure * @return string */ public function to($path, $extra = [], $secure = null); /** * Generate a secure, absolute URL to the given path. * * @param string $path * @param array $parameters * @return string */ public function secure($path, $parameters = []); /** * Generate the URL to an application asset. * * @param string $path * @param bool|null $secure * @return string */ public function asset($path, $secure = null); /** * Get the URL to a named route. * * @param string $name * @param mixed $parameters * @param bool $absolute * @return string * * @throws \InvalidArgumentException */ public function route($name, $parameters = [], $absolute = true); /** * Get the URL to a controller action. * * @param string|array $action * @param mixed $parameters * @param bool $absolute * @return string */ public function action($action, $parameters = [], $absolute = true); /** * Set the root controller namespace. * * @param string $rootNamespace * @return $this */ public function setRootControllerNamespace($rootNamespace); } contracts/Routing/BindingRegistrar.php 0000644 00000000677 14736103231 0014153 0 ustar 00 <?php namespace Illuminate\Contracts\Routing; interface BindingRegistrar { /** * Add a new route parameter binder. * * @param string $key * @param string|callable $binder * @return void */ public function bind($key, $binder); /** * Get the binding callback for a given binding. * * @param string $key * @return \Closure */ public function getBindingCallback($key); } contracts/Routing/ResponseFactory.php 0000644 00000011166 14736103231 0014037 0 ustar 00 <?php namespace Illuminate\Contracts\Routing; interface ResponseFactory { /** * Create a new response instance. * * @param string $content * @param int $status * @param array $headers * @return \Illuminate\Http\Response */ public function make($content = '', $status = 200, array $headers = []); /** * Create a new "no content" response. * * @param int $status * @param array $headers * @return \Illuminate\Http\Response */ public function noContent($status = 204, array $headers = []); /** * Create a new response for a given view. * * @param string|array $view * @param array $data * @param int $status * @param array $headers * @return \Illuminate\Http\Response */ public function view($view, $data = [], $status = 200, array $headers = []); /** * Create a new JSON response instance. * * @param mixed $data * @param int $status * @param array $headers * @param int $options * @return \Illuminate\Http\JsonResponse */ public function json($data = [], $status = 200, array $headers = [], $options = 0); /** * Create a new JSONP response instance. * * @param string $callback * @param mixed $data * @param int $status * @param array $headers * @param int $options * @return \Illuminate\Http\JsonResponse */ public function jsonp($callback, $data = [], $status = 200, array $headers = [], $options = 0); /** * Create a new streamed response instance. * * @param \Closure $callback * @param int $status * @param array $headers * @return \Symfony\Component\HttpFoundation\StreamedResponse */ public function stream($callback, $status = 200, array $headers = []); /** * Create a new streamed response instance as a file download. * * @param \Closure $callback * @param string|null $name * @param array $headers * @param string|null $disposition * @return \Symfony\Component\HttpFoundation\StreamedResponse */ public function streamDownload($callback, $name = null, array $headers = [], $disposition = 'attachment'); /** * Create a new file download response. * * @param \SplFileInfo|string $file * @param string|null $name * @param array $headers * @param string|null $disposition * @return \Symfony\Component\HttpFoundation\BinaryFileResponse */ public function download($file, $name = null, array $headers = [], $disposition = 'attachment'); /** * Return the raw contents of a binary file. * * @param \SplFileInfo|string $file * @param array $headers * @return \Symfony\Component\HttpFoundation\BinaryFileResponse */ public function file($file, array $headers = []); /** * Create a new redirect response to the given path. * * @param string $path * @param int $status * @param array $headers * @param bool|null $secure * @return \Illuminate\Http\RedirectResponse */ public function redirectTo($path, $status = 302, $headers = [], $secure = null); /** * Create a new redirect response to a named route. * * @param string $route * @param mixed $parameters * @param int $status * @param array $headers * @return \Illuminate\Http\RedirectResponse */ public function redirectToRoute($route, $parameters = [], $status = 302, $headers = []); /** * Create a new redirect response to a controller action. * * @param string $action * @param mixed $parameters * @param int $status * @param array $headers * @return \Illuminate\Http\RedirectResponse */ public function redirectToAction($action, $parameters = [], $status = 302, $headers = []); /** * Create a new redirect response, while putting the current URL in the session. * * @param string $path * @param int $status * @param array $headers * @param bool|null $secure * @return \Illuminate\Http\RedirectResponse */ public function redirectGuest($path, $status = 302, $headers = [], $secure = null); /** * Create a new redirect response to the previously intended location. * * @param string $default * @param int $status * @param array $headers * @param bool|null $secure * @return \Illuminate\Http\RedirectResponse */ public function redirectToIntended($default = '/', $status = 302, $headers = [], $secure = null); } filesystem/FilesystemAdapter.php 0000644 00000047550 14736103231 0013101 0 ustar 00 <?php namespace Illuminate\Filesystem; use Illuminate\Contracts\Filesystem\Cloud as CloudFilesystemContract; use Illuminate\Contracts\Filesystem\FileExistsException as ContractFileExistsException; use Illuminate\Contracts\Filesystem\FileNotFoundException as ContractFileNotFoundException; use Illuminate\Contracts\Filesystem\Filesystem as FilesystemContract; use Illuminate\Http\File; use Illuminate\Http\UploadedFile; use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\Str; use InvalidArgumentException; use League\Flysystem\Adapter\Ftp; use League\Flysystem\Adapter\Local as LocalAdapter; use League\Flysystem\AdapterInterface; use League\Flysystem\AwsS3v3\AwsS3Adapter; use League\Flysystem\Cached\CachedAdapter; use League\Flysystem\FileExistsException; use League\Flysystem\FileNotFoundException; use League\Flysystem\FilesystemInterface; use PHPUnit\Framework\Assert as PHPUnit; use Psr\Http\Message\StreamInterface; use RuntimeException; use Symfony\Component\HttpFoundation\StreamedResponse; /** * @mixin \League\Flysystem\FilesystemInterface */ class FilesystemAdapter implements CloudFilesystemContract { /** * The Flysystem filesystem implementation. * * @var \League\Flysystem\FilesystemInterface */ protected $driver; /** * Create a new filesystem adapter instance. * * @param \League\Flysystem\FilesystemInterface $driver * @return void */ public function __construct(FilesystemInterface $driver) { $this->driver = $driver; } /** * Assert that the given file exists. * * @param string|array $path * @return $this */ public function assertExists($path) { $paths = Arr::wrap($path); foreach ($paths as $path) { PHPUnit::assertTrue( $this->exists($path), "Unable to find a file at path [{$path}]." ); } return $this; } /** * Assert that the given file does not exist. * * @param string|array $path * @return $this */ public function assertMissing($path) { $paths = Arr::wrap($path); foreach ($paths as $path) { PHPUnit::assertFalse( $this->exists($path), "Found unexpected file at path [{$path}]." ); } return $this; } /** * Determine if a file exists. * * @param string $path * @return bool */ public function exists($path) { return $this->driver->has($path); } /** * Determine if a file or directory is missing. * * @param string $path * @return bool */ public function missing($path) { return ! $this->exists($path); } /** * Get the full path for the file at the given "short" path. * * @param string $path * @return string */ public function path($path) { $adapter = $this->driver->getAdapter(); if ($adapter instanceof CachedAdapter) { $adapter = $adapter->getAdapter(); } return $adapter->getPathPrefix().$path; } /** * Get the contents of a file. * * @param string $path * @return string * * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException */ public function get($path) { try { return $this->driver->read($path); } catch (FileNotFoundException $e) { throw new ContractFileNotFoundException($e->getMessage(), $e->getCode(), $e); } } /** * Create a streamed response for a given file. * * @param string $path * @param string|null $name * @param array|null $headers * @param string|null $disposition * @return \Symfony\Component\HttpFoundation\StreamedResponse */ public function response($path, $name = null, array $headers = [], $disposition = 'inline') { $response = new StreamedResponse; $filename = $name ?? basename($path); $disposition = $response->headers->makeDisposition( $disposition, $filename, $this->fallbackName($filename) ); $response->headers->replace($headers + [ 'Content-Type' => $this->mimeType($path), 'Content-Length' => $this->size($path), 'Content-Disposition' => $disposition, ]); $response->setCallback(function () use ($path) { $stream = $this->readStream($path); fpassthru($stream); fclose($stream); }); return $response; } /** * Create a streamed download response for a given file. * * @param string $path * @param string|null $name * @param array|null $headers * @return \Symfony\Component\HttpFoundation\StreamedResponse */ public function download($path, $name = null, array $headers = []) { return $this->response($path, $name, $headers, 'attachment'); } /** * Convert the string to ASCII characters that are equivalent to the given name. * * @param string $name * @return string */ protected function fallbackName($name) { return str_replace('%', '', Str::ascii($name)); } /** * Write the contents of a file. * * @param string $path * @param string|resource $contents * @param mixed $options * @return bool */ public function put($path, $contents, $options = []) { $options = is_string($options) ? ['visibility' => $options] : (array) $options; // If the given contents is actually a file or uploaded file instance than we will // automatically store the file using a stream. This provides a convenient path // for the developer to store streams without managing them manually in code. if ($contents instanceof File || $contents instanceof UploadedFile) { return $this->putFile($path, $contents, $options); } if ($contents instanceof StreamInterface) { return $this->driver->putStream($path, $contents->detach(), $options); } return is_resource($contents) ? $this->driver->putStream($path, $contents, $options) : $this->driver->put($path, $contents, $options); } /** * Store the uploaded file on the disk. * * @param string $path * @param \Illuminate\Http\File|\Illuminate\Http\UploadedFile|string $file * @param mixed $options * @return string|false */ public function putFile($path, $file, $options = []) { $file = is_string($file) ? new File($file) : $file; return $this->putFileAs($path, $file, $file->hashName(), $options); } /** * Store the uploaded file on the disk with a given name. * * @param string $path * @param \Illuminate\Http\File|\Illuminate\Http\UploadedFile|string $file * @param string $name * @param mixed $options * @return string|false */ public function putFileAs($path, $file, $name, $options = []) { $stream = fopen(is_string($file) ? $file : $file->getRealPath(), 'r'); // Next, we will format the path of the file and store the file using a stream since // they provide better performance than alternatives. Once we write the file this // stream will get closed automatically by us so the developer doesn't have to. $result = $this->put( $path = trim($path.'/'.$name, '/'), $stream, $options ); if (is_resource($stream)) { fclose($stream); } return $result ? $path : false; } /** * Get the visibility for the given path. * * @param string $path * @return string */ public function getVisibility($path) { if ($this->driver->getVisibility($path) == AdapterInterface::VISIBILITY_PUBLIC) { return FilesystemContract::VISIBILITY_PUBLIC; } return FilesystemContract::VISIBILITY_PRIVATE; } /** * Set the visibility for the given path. * * @param string $path * @param string $visibility * @return bool */ public function setVisibility($path, $visibility) { return $this->driver->setVisibility($path, $this->parseVisibility($visibility)); } /** * Prepend to a file. * * @param string $path * @param string $data * @param string $separator * @return bool */ public function prepend($path, $data, $separator = PHP_EOL) { if ($this->exists($path)) { return $this->put($path, $data.$separator.$this->get($path)); } return $this->put($path, $data); } /** * Append to a file. * * @param string $path * @param string $data * @param string $separator * @return bool */ public function append($path, $data, $separator = PHP_EOL) { if ($this->exists($path)) { return $this->put($path, $this->get($path).$separator.$data); } return $this->put($path, $data); } /** * Delete the file at a given path. * * @param string|array $paths * @return bool */ public function delete($paths) { $paths = is_array($paths) ? $paths : func_get_args(); $success = true; foreach ($paths as $path) { try { if (! $this->driver->delete($path)) { $success = false; } } catch (FileNotFoundException $e) { $success = false; } } return $success; } /** * Copy a file to a new location. * * @param string $from * @param string $to * @return bool */ public function copy($from, $to) { return $this->driver->copy($from, $to); } /** * Move a file to a new location. * * @param string $from * @param string $to * @return bool */ public function move($from, $to) { return $this->driver->rename($from, $to); } /** * Get the file size of a given file. * * @param string $path * @return int */ public function size($path) { return $this->driver->getSize($path); } /** * Get the mime-type of a given file. * * @param string $path * @return string|false */ public function mimeType($path) { return $this->driver->getMimetype($path); } /** * Get the file's last modification time. * * @param string $path * @return int */ public function lastModified($path) { return $this->driver->getTimestamp($path); } /** * Get the URL for the file at the given path. * * @param string $path * @return string * * @throws \RuntimeException */ public function url($path) { $adapter = $this->driver->getAdapter(); if ($adapter instanceof CachedAdapter) { $adapter = $adapter->getAdapter(); } if (method_exists($adapter, 'getUrl')) { return $adapter->getUrl($path); } elseif (method_exists($this->driver, 'getUrl')) { return $this->driver->getUrl($path); } elseif ($adapter instanceof AwsS3Adapter) { return $this->getAwsUrl($adapter, $path); } elseif ($adapter instanceof Ftp) { return $this->getFtpUrl($path); } elseif ($adapter instanceof LocalAdapter) { return $this->getLocalUrl($path); } else { throw new RuntimeException('This driver does not support retrieving URLs.'); } } /** * {@inheritdoc} */ public function readStream($path) { try { return $this->driver->readStream($path) ?: null; } catch (FileNotFoundException $e) { throw new ContractFileNotFoundException($e->getMessage(), $e->getCode(), $e); } } /** * {@inheritdoc} */ public function writeStream($path, $resource, array $options = []) { try { return $this->driver->writeStream($path, $resource, $options); } catch (FileExistsException $e) { throw new ContractFileExistsException($e->getMessage(), $e->getCode(), $e); } } /** * Get the URL for the file at the given path. * * @param \League\Flysystem\AwsS3v3\AwsS3Adapter $adapter * @param string $path * @return string */ protected function getAwsUrl($adapter, $path) { // If an explicit base URL has been set on the disk configuration then we will use // it as the base URL instead of the default path. This allows the developer to // have full control over the base path for this filesystem's generated URLs. if (! is_null($url = $this->driver->getConfig()->get('url'))) { return $this->concatPathToUrl($url, $adapter->getPathPrefix().$path); } return $adapter->getClient()->getObjectUrl( $adapter->getBucket(), $adapter->getPathPrefix().$path ); } /** * Get the URL for the file at the given path. * * @param string $path * @return string */ protected function getFtpUrl($path) { $config = $this->driver->getConfig(); return $config->has('url') ? $this->concatPathToUrl($config->get('url'), $path) : $path; } /** * Get the URL for the file at the given path. * * @param string $path * @return string */ protected function getLocalUrl($path) { $config = $this->driver->getConfig(); // If an explicit base URL has been set on the disk configuration then we will use // it as the base URL instead of the default path. This allows the developer to // have full control over the base path for this filesystem's generated URLs. if ($config->has('url')) { return $this->concatPathToUrl($config->get('url'), $path); } $path = '/storage/'.$path; // If the path contains "storage/public", it probably means the developer is using // the default disk to generate the path instead of the "public" disk like they // are really supposed to use. We will remove the public from this path here. if (Str::contains($path, '/storage/public/')) { return Str::replaceFirst('/public/', '/', $path); } return $path; } /** * Get a temporary URL for the file at the given path. * * @param string $path * @param \DateTimeInterface $expiration * @param array $options * @return string * * @throws \RuntimeException */ public function temporaryUrl($path, $expiration, array $options = []) { $adapter = $this->driver->getAdapter(); if ($adapter instanceof CachedAdapter) { $adapter = $adapter->getAdapter(); } if (method_exists($adapter, 'getTemporaryUrl')) { return $adapter->getTemporaryUrl($path, $expiration, $options); } elseif ($adapter instanceof AwsS3Adapter) { return $this->getAwsTemporaryUrl($adapter, $path, $expiration, $options); } else { throw new RuntimeException('This driver does not support creating temporary URLs.'); } } /** * Get a temporary URL for the file at the given path. * * @param \League\Flysystem\AwsS3v3\AwsS3Adapter $adapter * @param string $path * @param \DateTimeInterface $expiration * @param array $options * @return string */ public function getAwsTemporaryUrl($adapter, $path, $expiration, $options) { $client = $adapter->getClient(); $command = $client->getCommand('GetObject', array_merge([ 'Bucket' => $adapter->getBucket(), 'Key' => $adapter->getPathPrefix().$path, ], $options)); return (string) $client->createPresignedRequest( $command, $expiration )->getUri(); } /** * Concatenate a path to a URL. * * @param string $url * @param string $path * @return string */ protected function concatPathToUrl($url, $path) { return rtrim($url, '/').'/'.ltrim($path, '/'); } /** * Get an array of all files in a directory. * * @param string|null $directory * @param bool $recursive * @return array */ public function files($directory = null, $recursive = false) { $contents = $this->driver->listContents($directory, $recursive); return $this->filterContentsByType($contents, 'file'); } /** * Get all of the files from the given directory (recursive). * * @param string|null $directory * @return array */ public function allFiles($directory = null) { return $this->files($directory, true); } /** * Get all of the directories within a given directory. * * @param string|null $directory * @param bool $recursive * @return array */ public function directories($directory = null, $recursive = false) { $contents = $this->driver->listContents($directory, $recursive); return $this->filterContentsByType($contents, 'dir'); } /** * Get all (recursive) of the directories within a given directory. * * @param string|null $directory * @return array */ public function allDirectories($directory = null) { return $this->directories($directory, true); } /** * Create a directory. * * @param string $path * @return bool */ public function makeDirectory($path) { return $this->driver->createDir($path); } /** * Recursively delete a directory. * * @param string $directory * @return bool */ public function deleteDirectory($directory) { return $this->driver->deleteDir($directory); } /** * Flush the Flysystem cache. * * @return void */ public function flushCache() { $adapter = $this->driver->getAdapter(); if ($adapter instanceof CachedAdapter) { $adapter->getCache()->flush(); } } /** * Get the Flysystem driver. * * @return \League\Flysystem\FilesystemInterface */ public function getDriver() { return $this->driver; } /** * Filter directory contents by type. * * @param array $contents * @param string $type * @return array */ protected function filterContentsByType($contents, $type) { return Collection::make($contents) ->where('type', $type) ->pluck('path') ->values() ->all(); } /** * Parse the given visibility value. * * @param string|null $visibility * @return string|null * * @throws \InvalidArgumentException */ protected function parseVisibility($visibility) { if (is_null($visibility)) { return; } switch ($visibility) { case FilesystemContract::VISIBILITY_PUBLIC: return AdapterInterface::VISIBILITY_PUBLIC; case FilesystemContract::VISIBILITY_PRIVATE: return AdapterInterface::VISIBILITY_PRIVATE; } throw new InvalidArgumentException("Unknown visibility: {$visibility}."); } /** * Pass dynamic methods call onto Flysystem. * * @param string $method * @param array $parameters * @return mixed * * @throws \BadMethodCallException */ public function __call($method, array $parameters) { return call_user_func_array([$this->driver, $method], $parameters); } } filesystem/Filesystem.php 0000644 00000036570 14736103231 0011600 0 ustar 00 <?php namespace Illuminate\Filesystem; use ErrorException; use FilesystemIterator; use Illuminate\Contracts\Filesystem\FileNotFoundException; use Illuminate\Support\Traits\Macroable; use RuntimeException; use Symfony\Component\Finder\Finder; use Symfony\Component\Mime\MimeTypes; class Filesystem { use Macroable; /** * Determine if a file or directory exists. * * @param string $path * @return bool */ public function exists($path) { return file_exists($path); } /** * Determine if a file or directory is missing. * * @param string $path * @return bool */ public function missing($path) { return ! $this->exists($path); } /** * Get the contents of a file. * * @param string $path * @param bool $lock * @return string * * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException */ public function get($path, $lock = false) { if ($this->isFile($path)) { return $lock ? $this->sharedGet($path) : file_get_contents($path); } throw new FileNotFoundException("File does not exist at path {$path}."); } /** * Get contents of a file with shared access. * * @param string $path * @return string */ public function sharedGet($path) { $contents = ''; $handle = fopen($path, 'rb'); if ($handle) { try { if (flock($handle, LOCK_SH)) { clearstatcache(true, $path); $contents = fread($handle, $this->size($path) ?: 1); flock($handle, LOCK_UN); } } finally { fclose($handle); } } return $contents; } /** * Get the returned value of a file. * * @param string $path * @return mixed * * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException */ public function getRequire($path) { if ($this->isFile($path)) { return require $path; } throw new FileNotFoundException("File does not exist at path {$path}."); } /** * Require the given file once. * * @param string $file * @return mixed */ public function requireOnce($file) { require_once $file; } /** * Get the MD5 hash of the file at the given path. * * @param string $path * @return string */ public function hash($path) { return md5_file($path); } /** * Write the contents of a file. * * @param string $path * @param string $contents * @param bool $lock * @return int|bool */ public function put($path, $contents, $lock = false) { return file_put_contents($path, $contents, $lock ? LOCK_EX : 0); } /** * Write the contents of a file, replacing it atomically if it already exists. * * @param string $path * @param string $content * @return void */ public function replace($path, $content) { // If the path already exists and is a symlink, get the real path... clearstatcache(true, $path); $path = realpath($path) ?: $path; $tempPath = tempnam(dirname($path), basename($path)); // Fix permissions of tempPath because `tempnam()` creates it with permissions set to 0600... chmod($tempPath, 0777 - umask()); file_put_contents($tempPath, $content); rename($tempPath, $path); } /** * Prepend to a file. * * @param string $path * @param string $data * @return int */ public function prepend($path, $data) { if ($this->exists($path)) { return $this->put($path, $data.$this->get($path)); } return $this->put($path, $data); } /** * Append to a file. * * @param string $path * @param string $data * @return int */ public function append($path, $data) { return file_put_contents($path, $data, FILE_APPEND); } /** * Get or set UNIX mode of a file or directory. * * @param string $path * @param int|null $mode * @return mixed */ public function chmod($path, $mode = null) { if ($mode) { return chmod($path, $mode); } return substr(sprintf('%o', fileperms($path)), -4); } /** * Delete the file at a given path. * * @param string|array $paths * @return bool */ public function delete($paths) { $paths = is_array($paths) ? $paths : func_get_args(); $success = true; foreach ($paths as $path) { try { if (! @unlink($path)) { $success = false; } } catch (ErrorException $e) { $success = false; } } return $success; } /** * Move a file to a new location. * * @param string $path * @param string $target * @return bool */ public function move($path, $target) { return rename($path, $target); } /** * Copy a file to a new location. * * @param string $path * @param string $target * @return bool */ public function copy($path, $target) { return copy($path, $target); } /** * Create a symlink to the target file or directory. On Windows, a hard link is created if the target is a file. * * @param string $target * @param string $link * @return void */ public function link($target, $link) { if (! windows_os()) { return symlink($target, $link); } $mode = $this->isDirectory($target) ? 'J' : 'H'; exec("mklink /{$mode} ".escapeshellarg($link).' '.escapeshellarg($target)); } /** * Extract the file name from a file path. * * @param string $path * @return string */ public function name($path) { return pathinfo($path, PATHINFO_FILENAME); } /** * Extract the trailing name component from a file path. * * @param string $path * @return string */ public function basename($path) { return pathinfo($path, PATHINFO_BASENAME); } /** * Extract the parent directory from a file path. * * @param string $path * @return string */ public function dirname($path) { return pathinfo($path, PATHINFO_DIRNAME); } /** * Extract the file extension from a file path. * * @param string $path * @return string */ public function extension($path) { return pathinfo($path, PATHINFO_EXTENSION); } /** * Guess the file extension from the mime-type of a given file. * * @param string $path * @return string|null */ public function guessExtension($path) { if (! class_exists(MimeTypes::class)) { throw new RuntimeException( 'To enable support for guessing extensions, please install the symfony/mime package.' ); } return (new MimeTypes)->getExtensions($this->mimeType($path))[0] ?? null; } /** * Get the file type of a given file. * * @param string $path * @return string */ public function type($path) { return filetype($path); } /** * Get the mime-type of a given file. * * @param string $path * @return string|false */ public function mimeType($path) { return finfo_file(finfo_open(FILEINFO_MIME_TYPE), $path); } /** * Get the file size of a given file. * * @param string $path * @return int */ public function size($path) { return filesize($path); } /** * Get the file's last modification time. * * @param string $path * @return int */ public function lastModified($path) { return filemtime($path); } /** * Determine if the given path is a directory. * * @param string $directory * @return bool */ public function isDirectory($directory) { return is_dir($directory); } /** * Determine if the given path is readable. * * @param string $path * @return bool */ public function isReadable($path) { return is_readable($path); } /** * Determine if the given path is writable. * * @param string $path * @return bool */ public function isWritable($path) { return is_writable($path); } /** * Determine if the given path is a file. * * @param string $file * @return bool */ public function isFile($file) { return is_file($file); } /** * Find path names matching a given pattern. * * @param string $pattern * @param int $flags * @return array */ public function glob($pattern, $flags = 0) { return glob($pattern, $flags); } /** * Get an array of all files in a directory. * * @param string $directory * @param bool $hidden * @return \Symfony\Component\Finder\SplFileInfo[] */ public function files($directory, $hidden = false) { return iterator_to_array( Finder::create()->files()->ignoreDotFiles(! $hidden)->in($directory)->depth(0)->sortByName(), false ); } /** * Get all of the files from the given directory (recursive). * * @param string $directory * @param bool $hidden * @return \Symfony\Component\Finder\SplFileInfo[] */ public function allFiles($directory, $hidden = false) { return iterator_to_array( Finder::create()->files()->ignoreDotFiles(! $hidden)->in($directory)->sortByName(), false ); } /** * Get all of the directories within a given directory. * * @param string $directory * @return array */ public function directories($directory) { $directories = []; foreach (Finder::create()->in($directory)->directories()->depth(0)->sortByName() as $dir) { $directories[] = $dir->getPathname(); } return $directories; } /** * Ensure a directory exists. * * @param string $path * @param int $mode * @param bool $recursive * @return void */ public function ensureDirectoryExists($path, $mode = 0755, $recursive = true) { if (! $this->isDirectory($path)) { $this->makeDirectory($path, $mode, $recursive); } } /** * Create a directory. * * @param string $path * @param int $mode * @param bool $recursive * @param bool $force * @return bool */ public function makeDirectory($path, $mode = 0755, $recursive = false, $force = false) { if ($force) { return @mkdir($path, $mode, $recursive); } return mkdir($path, $mode, $recursive); } /** * Move a directory. * * @param string $from * @param string $to * @param bool $overwrite * @return bool */ public function moveDirectory($from, $to, $overwrite = false) { if ($overwrite && $this->isDirectory($to) && ! $this->deleteDirectory($to)) { return false; } return @rename($from, $to) === true; } /** * Copy a directory from one location to another. * * @param string $directory * @param string $destination * @param int|null $options * @return bool */ public function copyDirectory($directory, $destination, $options = null) { if (! $this->isDirectory($directory)) { return false; } $options = $options ?: FilesystemIterator::SKIP_DOTS; // If the destination directory does not actually exist, we will go ahead and // create it recursively, which just gets the destination prepared to copy // the files over. Once we make the directory we'll proceed the copying. $this->ensureDirectoryExists($destination, 0777); $items = new FilesystemIterator($directory, $options); foreach ($items as $item) { // As we spin through items, we will check to see if the current file is actually // a directory or a file. When it is actually a directory we will need to call // back into this function recursively to keep copying these nested folders. $target = $destination.'/'.$item->getBasename(); if ($item->isDir()) { $path = $item->getPathname(); if (! $this->copyDirectory($path, $target, $options)) { return false; } } // If the current items is just a regular file, we will just copy this to the new // location and keep looping. If for some reason the copy fails we'll bail out // and return false, so the developer is aware that the copy process failed. else { if (! $this->copy($item->getPathname(), $target)) { return false; } } } return true; } /** * Recursively delete a directory. * * The directory itself may be optionally preserved. * * @param string $directory * @param bool $preserve * @return bool */ public function deleteDirectory($directory, $preserve = false) { if (! $this->isDirectory($directory)) { return false; } $items = new FilesystemIterator($directory); foreach ($items as $item) { // If the item is a directory, we can just recurse into the function and // delete that sub-directory otherwise we'll just delete the file and // keep iterating through each file until the directory is cleaned. if ($item->isDir() && ! $item->isLink()) { $this->deleteDirectory($item->getPathname()); } // If the item is just a file, we can go ahead and delete it since we're // just looping through and waxing all of the files in this directory // and calling directories recursively, so we delete the real path. else { $this->delete($item->getPathname()); } } if (! $preserve) { @rmdir($directory); } return true; } /** * Remove all of the directories within a given directory. * * @param string $directory * @return bool */ public function deleteDirectories($directory) { $allDirectories = $this->directories($directory); if (! empty($allDirectories)) { foreach ($allDirectories as $directoryName) { $this->deleteDirectory($directoryName); } return true; } return false; } /** * Empty the specified directory of all files and folders. * * @param string $directory * @return bool */ public function cleanDirectory($directory) { return $this->deleteDirectory($directory, true); } } filesystem/Cache.php 0000644 00000002601 14736103231 0010443 0 ustar 00 <?php namespace Illuminate\Filesystem; use Illuminate\Contracts\Cache\Repository; use League\Flysystem\Cached\Storage\AbstractCache; class Cache extends AbstractCache { /** * The cache repository implementation. * * @var \Illuminate\Contracts\Cache\Repository */ protected $repository; /** * The cache key. * * @var string */ protected $key; /** * The cache expiration time in seconds. * * @var int|null */ protected $expire; /** * Create a new cache instance. * * @param \Illuminate\Contracts\Cache\Repository $repository * @param string $key * @param int|null $expire * @return void */ public function __construct(Repository $repository, $key = 'flysystem', $expire = null) { $this->key = $key; $this->expire = $expire; $this->repository = $repository; } /** * Load the cache. * * @return void */ public function load() { $contents = $this->repository->get($this->key); if (! is_null($contents)) { $this->setFromStorage($contents); } } /** * Persist the cache. * * @return void */ public function save() { $contents = $this->getForStorage(); $this->repository->put($this->key, $contents, $this->expire); } } filesystem/FilesystemServiceProvider.php 0000644 00000003322 14736103231 0014621 0 ustar 00 <?php namespace Illuminate\Filesystem; use Illuminate\Support\ServiceProvider; class FilesystemServiceProvider extends ServiceProvider { /** * Register the service provider. * * @return void */ public function register() { $this->registerNativeFilesystem(); $this->registerFlysystem(); } /** * Register the native filesystem implementation. * * @return void */ protected function registerNativeFilesystem() { $this->app->singleton('files', function () { return new Filesystem; }); } /** * Register the driver based filesystem. * * @return void */ protected function registerFlysystem() { $this->registerManager(); $this->app->singleton('filesystem.disk', function ($app) { return $app['filesystem']->disk($this->getDefaultDriver()); }); $this->app->singleton('filesystem.cloud', function ($app) { return $app['filesystem']->disk($this->getCloudDriver()); }); } /** * Register the filesystem manager. * * @return void */ protected function registerManager() { $this->app->singleton('filesystem', function ($app) { return new FilesystemManager($app); }); } /** * Get the default file driver. * * @return string */ protected function getDefaultDriver() { return $this->app['config']['filesystems.default']; } /** * Get the default cloud based file driver. * * @return string */ protected function getCloudDriver() { return $this->app['config']['filesystems.cloud']; } } filesystem/LICENSE.md 0000644 00000002063 14736103231 0010335 0 ustar 00 The MIT License (MIT) Copyright (c) Taylor Otwell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. filesystem/FilesystemManager.php 0000644 00000022070 14736103231 0013061 0 ustar 00 <?php namespace Illuminate\Filesystem; use Aws\S3\S3Client; use Closure; use Illuminate\Contracts\Filesystem\Factory as FactoryContract; use Illuminate\Support\Arr; use InvalidArgumentException; use League\Flysystem\Adapter\Ftp as FtpAdapter; use League\Flysystem\Adapter\Local as LocalAdapter; use League\Flysystem\AdapterInterface; use League\Flysystem\AwsS3v3\AwsS3Adapter as S3Adapter; use League\Flysystem\Cached\CachedAdapter; use League\Flysystem\Cached\Storage\Memory as MemoryStore; use League\Flysystem\Filesystem as Flysystem; use League\Flysystem\FilesystemInterface; use League\Flysystem\Sftp\SftpAdapter; /** * @mixin \Illuminate\Contracts\Filesystem\Filesystem */ class FilesystemManager implements FactoryContract { /** * The application instance. * * @var \Illuminate\Contracts\Foundation\Application */ protected $app; /** * The array of resolved filesystem drivers. * * @var array */ protected $disks = []; /** * The registered custom driver creators. * * @var array */ protected $customCreators = []; /** * Create a new filesystem manager instance. * * @param \Illuminate\Contracts\Foundation\Application $app * @return void */ public function __construct($app) { $this->app = $app; } /** * Get a filesystem instance. * * @param string|null $name * @return \Illuminate\Contracts\Filesystem\Filesystem */ public function drive($name = null) { return $this->disk($name); } /** * Get a filesystem instance. * * @param string|null $name * @return \Illuminate\Contracts\Filesystem\Filesystem */ public function disk($name = null) { $name = $name ?: $this->getDefaultDriver(); return $this->disks[$name] = $this->get($name); } /** * Get a default cloud filesystem instance. * * @return \Illuminate\Contracts\Filesystem\Filesystem */ public function cloud() { $name = $this->getDefaultCloudDriver(); return $this->disks[$name] = $this->get($name); } /** * Attempt to get the disk from the local cache. * * @param string $name * @return \Illuminate\Contracts\Filesystem\Filesystem */ protected function get($name) { return $this->disks[$name] ?? $this->resolve($name); } /** * Resolve the given disk. * * @param string $name * @return \Illuminate\Contracts\Filesystem\Filesystem * * @throws \InvalidArgumentException */ protected function resolve($name) { $config = $this->getConfig($name); if (empty($config['driver'])) { throw new InvalidArgumentException("Disk [{$name}] does not have a configured driver."); } $name = $config['driver']; if (isset($this->customCreators[$name])) { return $this->callCustomCreator($config); } $driverMethod = 'create'.ucfirst($name).'Driver'; if (method_exists($this, $driverMethod)) { return $this->{$driverMethod}($config); } else { throw new InvalidArgumentException("Driver [{$name}] is not supported."); } } /** * Call a custom driver creator. * * @param array $config * @return \Illuminate\Contracts\Filesystem\Filesystem */ protected function callCustomCreator(array $config) { $driver = $this->customCreators[$config['driver']]($this->app, $config); if ($driver instanceof FilesystemInterface) { return $this->adapt($driver); } return $driver; } /** * Create an instance of the local driver. * * @param array $config * @return \Illuminate\Contracts\Filesystem\Filesystem */ public function createLocalDriver(array $config) { $permissions = $config['permissions'] ?? []; $links = ($config['links'] ?? null) === 'skip' ? LocalAdapter::SKIP_LINKS : LocalAdapter::DISALLOW_LINKS; return $this->adapt($this->createFlysystem(new LocalAdapter( $config['root'], $config['lock'] ?? LOCK_EX, $links, $permissions ), $config)); } /** * Create an instance of the ftp driver. * * @param array $config * @return \Illuminate\Contracts\Filesystem\Filesystem */ public function createFtpDriver(array $config) { return $this->adapt($this->createFlysystem( new FtpAdapter($config), $config )); } /** * Create an instance of the sftp driver. * * @param array $config * @return \Illuminate\Contracts\Filesystem\Filesystem */ public function createSftpDriver(array $config) { return $this->adapt($this->createFlysystem( new SftpAdapter($config), $config )); } /** * Create an instance of the Amazon S3 driver. * * @param array $config * @return \Illuminate\Contracts\Filesystem\Cloud */ public function createS3Driver(array $config) { $s3Config = $this->formatS3Config($config); $root = $s3Config['root'] ?? null; $options = $config['options'] ?? []; $streamReads = $config['stream_reads'] ?? false; return $this->adapt($this->createFlysystem( new S3Adapter(new S3Client($s3Config), $s3Config['bucket'], $root, $options, $streamReads), $config )); } /** * Format the given S3 configuration with the default options. * * @param array $config * @return array */ protected function formatS3Config(array $config) { $config += ['version' => 'latest']; if (! empty($config['key']) && ! empty($config['secret'])) { $config['credentials'] = Arr::only($config, ['key', 'secret', 'token']); } return $config; } /** * Create a Flysystem instance with the given adapter. * * @param \League\Flysystem\AdapterInterface $adapter * @param array $config * @return \League\Flysystem\FilesystemInterface */ protected function createFlysystem(AdapterInterface $adapter, array $config) { $cache = Arr::pull($config, 'cache'); $config = Arr::only($config, ['visibility', 'disable_asserts', 'url']); if ($cache) { $adapter = new CachedAdapter($adapter, $this->createCacheStore($cache)); } return new Flysystem($adapter, count($config) > 0 ? $config : null); } /** * Create a cache store instance. * * @param mixed $config * @return \League\Flysystem\Cached\CacheInterface * * @throws \InvalidArgumentException */ protected function createCacheStore($config) { if ($config === true) { return new MemoryStore; } return new Cache( $this->app['cache']->store($config['store']), $config['prefix'] ?? 'flysystem', $config['expire'] ?? null ); } /** * Adapt the filesystem implementation. * * @param \League\Flysystem\FilesystemInterface $filesystem * @return \Illuminate\Contracts\Filesystem\Filesystem */ protected function adapt(FilesystemInterface $filesystem) { return new FilesystemAdapter($filesystem); } /** * Set the given disk instance. * * @param string $name * @param mixed $disk * @return $this */ public function set($name, $disk) { $this->disks[$name] = $disk; return $this; } /** * Get the filesystem connection configuration. * * @param string $name * @return array */ protected function getConfig($name) { return $this->app['config']["filesystems.disks.{$name}"] ?: []; } /** * Get the default driver name. * * @return string */ public function getDefaultDriver() { return $this->app['config']['filesystems.default']; } /** * Get the default cloud driver name. * * @return string */ public function getDefaultCloudDriver() { return $this->app['config']['filesystems.cloud']; } /** * Unset the given disk instances. * * @param array|string $disk * @return $this */ public function forgetDisk($disk) { foreach ((array) $disk as $diskName) { unset($this->disks[$diskName]); } return $this; } /** * Register a custom driver creator Closure. * * @param string $driver * @param \Closure $callback * @return $this */ public function extend($driver, Closure $callback) { $this->customCreators[$driver] = $callback; return $this; } /** * Dynamically call the default driver instance. * * @param string $method * @param array $parameters * @return mixed */ public function __call($method, $parameters) { return $this->disk()->$method(...$parameters); } } database/DatabaseManager.php 0000644 00000023745 14736103231 0012033 0 ustar 00 <?php namespace Illuminate\Database; use Illuminate\Database\Connectors\ConnectionFactory; use Illuminate\Support\Arr; use Illuminate\Support\ConfigurationUrlParser; use Illuminate\Support\Str; use InvalidArgumentException; use PDO; /** * @mixin \Illuminate\Database\Connection */ class DatabaseManager implements ConnectionResolverInterface { /** * The application instance. * * @var \Illuminate\Contracts\Foundation\Application */ protected $app; /** * The database connection factory instance. * * @var \Illuminate\Database\Connectors\ConnectionFactory */ protected $factory; /** * The active connection instances. * * @var array */ protected $connections = []; /** * The custom connection resolvers. * * @var array */ protected $extensions = []; /** * The callback to be executed to reconnect to a database. * * @var callable */ protected $reconnector; /** * Create a new database manager instance. * * @param \Illuminate\Contracts\Foundation\Application $app * @param \Illuminate\Database\Connectors\ConnectionFactory $factory * @return void */ public function __construct($app, ConnectionFactory $factory) { $this->app = $app; $this->factory = $factory; $this->reconnector = function ($connection) { $this->reconnect($connection->getName()); }; } /** * Get a database connection instance. * * @param string|null $name * @return \Illuminate\Database\Connection */ public function connection($name = null) { [$database, $type] = $this->parseConnectionName($name); $name = $name ?: $database; // If we haven't created this connection, we'll create it based on the config // provided in the application. Once we've created the connections we will // set the "fetch mode" for PDO which determines the query return types. if (! isset($this->connections[$name])) { $this->connections[$name] = $this->configure( $this->makeConnection($database), $type ); } return $this->connections[$name]; } /** * Parse the connection into an array of the name and read / write type. * * @param string $name * @return array */ protected function parseConnectionName($name) { $name = $name ?: $this->getDefaultConnection(); return Str::endsWith($name, ['::read', '::write']) ? explode('::', $name, 2) : [$name, null]; } /** * Make the database connection instance. * * @param string $name * @return \Illuminate\Database\Connection */ protected function makeConnection($name) { $config = $this->configuration($name); // First we will check by the connection name to see if an extension has been // registered specifically for that connection. If it has we will call the // Closure and pass it the config allowing it to resolve the connection. if (isset($this->extensions[$name])) { return call_user_func($this->extensions[$name], $config, $name); } // Next we will check to see if an extension has been registered for a driver // and will call the Closure if so, which allows us to have a more generic // resolver for the drivers themselves which applies to all connections. if (isset($this->extensions[$driver = $config['driver']])) { return call_user_func($this->extensions[$driver], $config, $name); } return $this->factory->make($config, $name); } /** * Get the configuration for a connection. * * @param string $name * @return array * * @throws \InvalidArgumentException */ protected function configuration($name) { $name = $name ?: $this->getDefaultConnection(); // To get the database connection configuration, we will just pull each of the // connection configurations and get the configurations for the given name. // If the configuration doesn't exist, we'll throw an exception and bail. $connections = $this->app['config']['database.connections']; if (is_null($config = Arr::get($connections, $name))) { throw new InvalidArgumentException("Database connection [{$name}] not configured."); } return (new ConfigurationUrlParser) ->parseConfiguration($config); } /** * Prepare the database connection instance. * * @param \Illuminate\Database\Connection $connection * @param string $type * @return \Illuminate\Database\Connection */ protected function configure(Connection $connection, $type) { $connection = $this->setPdoForType($connection, $type); // First we'll set the fetch mode and a few other dependencies of the database // connection. This method basically just configures and prepares it to get // used by the application. Once we're finished we'll return it back out. if ($this->app->bound('events')) { $connection->setEventDispatcher($this->app['events']); } // Here we'll set a reconnector callback. This reconnector can be any callable // so we will set a Closure to reconnect from this manager with the name of // the connection, which will allow us to reconnect from the connections. $connection->setReconnector($this->reconnector); return $connection; } /** * Prepare the read / write mode for database connection instance. * * @param \Illuminate\Database\Connection $connection * @param string|null $type * @return \Illuminate\Database\Connection */ protected function setPdoForType(Connection $connection, $type = null) { if ($type === 'read') { $connection->setPdo($connection->getReadPdo()); } elseif ($type === 'write') { $connection->setReadPdo($connection->getPdo()); } return $connection; } /** * Disconnect from the given database and remove from local cache. * * @param string|null $name * @return void */ public function purge($name = null) { $name = $name ?: $this->getDefaultConnection(); $this->disconnect($name); unset($this->connections[$name]); } /** * Disconnect from the given database. * * @param string|null $name * @return void */ public function disconnect($name = null) { if (isset($this->connections[$name = $name ?: $this->getDefaultConnection()])) { $this->connections[$name]->disconnect(); } } /** * Reconnect to the given database. * * @param string|null $name * @return \Illuminate\Database\Connection */ public function reconnect($name = null) { $this->disconnect($name = $name ?: $this->getDefaultConnection()); if (! isset($this->connections[$name])) { return $this->connection($name); } return $this->refreshPdoConnections($name); } /** * Set the default database connection for the callback execution. * * @param string $name * @param callable $callback * @return mixed */ public function usingConnection($name, callable $callback) { $previousName = $this->getDefaultConnection(); $this->setDefaultConnection($name); return tap($callback(), function () use ($previousName) { $this->setDefaultConnection($previousName); }); } /** * Refresh the PDO connections on a given connection. * * @param string $name * @return \Illuminate\Database\Connection */ protected function refreshPdoConnections($name) { $fresh = $this->makeConnection($name); return $this->connections[$name] ->setPdo($fresh->getRawPdo()) ->setReadPdo($fresh->getRawReadPdo()); } /** * Get the default connection name. * * @return string */ public function getDefaultConnection() { return $this->app['config']['database.default']; } /** * Set the default connection name. * * @param string $name * @return void */ public function setDefaultConnection($name) { $this->app['config']['database.default'] = $name; } /** * Get all of the support drivers. * * @return array */ public function supportedDrivers() { return ['mysql', 'pgsql', 'sqlite', 'sqlsrv']; } /** * Get all of the drivers that are actually available. * * @return array */ public function availableDrivers() { return array_intersect( $this->supportedDrivers(), str_replace('dblib', 'sqlsrv', PDO::getAvailableDrivers()) ); } /** * Register an extension connection resolver. * * @param string $name * @param callable $resolver * @return void */ public function extend($name, callable $resolver) { $this->extensions[$name] = $resolver; } /** * Return all of the created connections. * * @return array */ public function getConnections() { return $this->connections; } /** * Set the database reconnector callback. * * @param callable $reconnector * @return void */ public function setReconnector(callable $reconnector) { $this->reconnector = $reconnector; } /** * Dynamically pass methods to the default connection. * * @param string $method * @param array $parameters * @return mixed */ public function __call($method, $parameters) { return $this->connection()->$method(...$parameters); } } database/MigrationServiceProvider.php 0000644 00000014013 14736103231 0014005 0 ustar 00 <?php namespace Illuminate\Database; use Illuminate\Contracts\Support\DeferrableProvider; use Illuminate\Database\Console\Migrations\FreshCommand; use Illuminate\Database\Console\Migrations\InstallCommand; use Illuminate\Database\Console\Migrations\MigrateCommand; use Illuminate\Database\Console\Migrations\MigrateMakeCommand; use Illuminate\Database\Console\Migrations\RefreshCommand; use Illuminate\Database\Console\Migrations\ResetCommand; use Illuminate\Database\Console\Migrations\RollbackCommand; use Illuminate\Database\Console\Migrations\StatusCommand; use Illuminate\Database\Migrations\DatabaseMigrationRepository; use Illuminate\Database\Migrations\MigrationCreator; use Illuminate\Database\Migrations\Migrator; use Illuminate\Support\ServiceProvider; class MigrationServiceProvider extends ServiceProvider implements DeferrableProvider { /** * The commands to be registered. * * @var array */ protected $commands = [ 'Migrate' => 'command.migrate', 'MigrateFresh' => 'command.migrate.fresh', 'MigrateInstall' => 'command.migrate.install', 'MigrateRefresh' => 'command.migrate.refresh', 'MigrateReset' => 'command.migrate.reset', 'MigrateRollback' => 'command.migrate.rollback', 'MigrateStatus' => 'command.migrate.status', 'MigrateMake' => 'command.migrate.make', ]; /** * Register the service provider. * * @return void */ public function register() { $this->registerRepository(); $this->registerMigrator(); $this->registerCreator(); $this->registerCommands($this->commands); } /** * Register the migration repository service. * * @return void */ protected function registerRepository() { $this->app->singleton('migration.repository', function ($app) { $table = $app['config']['database.migrations']; return new DatabaseMigrationRepository($app['db'], $table); }); } /** * Register the migrator service. * * @return void */ protected function registerMigrator() { // The migrator is responsible for actually running and rollback the migration // files in the application. We'll pass in our database connection resolver // so the migrator can resolve any of these connections when it needs to. $this->app->singleton('migrator', function ($app) { $repository = $app['migration.repository']; return new Migrator($repository, $app['db'], $app['files'], $app['events']); }); } /** * Register the migration creator. * * @return void */ protected function registerCreator() { $this->app->singleton('migration.creator', function ($app) { return new MigrationCreator($app['files'], $app->basePath('stubs')); }); } /** * Register the given commands. * * @param array $commands * @return void */ protected function registerCommands(array $commands) { foreach (array_keys($commands) as $command) { call_user_func_array([$this, "register{$command}Command"], []); } $this->commands(array_values($commands)); } /** * Register the command. * * @return void */ protected function registerMigrateCommand() { $this->app->singleton('command.migrate', function ($app) { return new MigrateCommand($app['migrator']); }); } /** * Register the command. * * @return void */ protected function registerMigrateFreshCommand() { $this->app->singleton('command.migrate.fresh', function () { return new FreshCommand; }); } /** * Register the command. * * @return void */ protected function registerMigrateInstallCommand() { $this->app->singleton('command.migrate.install', function ($app) { return new InstallCommand($app['migration.repository']); }); } /** * Register the command. * * @return void */ protected function registerMigrateMakeCommand() { $this->app->singleton('command.migrate.make', function ($app) { // Once we have the migration creator registered, we will create the command // and inject the creator. The creator is responsible for the actual file // creation of the migrations, and may be extended by these developers. $creator = $app['migration.creator']; $composer = $app['composer']; return new MigrateMakeCommand($creator, $composer); }); } /** * Register the command. * * @return void */ protected function registerMigrateRefreshCommand() { $this->app->singleton('command.migrate.refresh', function () { return new RefreshCommand; }); } /** * Register the command. * * @return void */ protected function registerMigrateResetCommand() { $this->app->singleton('command.migrate.reset', function ($app) { return new ResetCommand($app['migrator']); }); } /** * Register the command. * * @return void */ protected function registerMigrateRollbackCommand() { $this->app->singleton('command.migrate.rollback', function ($app) { return new RollbackCommand($app['migrator']); }); } /** * Register the command. * * @return void */ protected function registerMigrateStatusCommand() { $this->app->singleton('command.migrate.status', function ($app) { return new StatusCommand($app['migrator']); }); } /** * Get the services provided by the provider. * * @return array */ public function provides() { return array_merge([ 'migrator', 'migration.repository', 'migration.creator', ], array_values($this->commands)); } } database/Grammar.php 0000644 00000012271 14736103231 0010412 0 ustar 00 <?php namespace Illuminate\Database; use Illuminate\Database\Query\Expression; use Illuminate\Support\Traits\Macroable; abstract class Grammar { use Macroable; /** * The grammar table prefix. * * @var string */ protected $tablePrefix = ''; /** * Wrap an array of values. * * @param array $values * @return array */ public function wrapArray(array $values) { return array_map([$this, 'wrap'], $values); } /** * Wrap a table in keyword identifiers. * * @param \Illuminate\Database\Query\Expression|string $table * @return string */ public function wrapTable($table) { if (! $this->isExpression($table)) { return $this->wrap($this->tablePrefix.$table, true); } return $this->getValue($table); } /** * Wrap a value in keyword identifiers. * * @param \Illuminate\Database\Query\Expression|string $value * @param bool $prefixAlias * @return string */ public function wrap($value, $prefixAlias = false) { if ($this->isExpression($value)) { return $this->getValue($value); } // If the value being wrapped has a column alias we will need to separate out // the pieces so we can wrap each of the segments of the expression on its // own, and then join these both back together using the "as" connector. if (stripos($value, ' as ') !== false) { return $this->wrapAliasedValue($value, $prefixAlias); } return $this->wrapSegments(explode('.', $value)); } /** * Wrap a value that has an alias. * * @param string $value * @param bool $prefixAlias * @return string */ protected function wrapAliasedValue($value, $prefixAlias = false) { $segments = preg_split('/\s+as\s+/i', $value); // If we are wrapping a table we need to prefix the alias with the table prefix // as well in order to generate proper syntax. If this is a column of course // no prefix is necessary. The condition will be true when from wrapTable. if ($prefixAlias) { $segments[1] = $this->tablePrefix.$segments[1]; } return $this->wrap($segments[0]).' as '.$this->wrapValue($segments[1]); } /** * Wrap the given value segments. * * @param array $segments * @return string */ protected function wrapSegments($segments) { return collect($segments)->map(function ($segment, $key) use ($segments) { return $key == 0 && count($segments) > 1 ? $this->wrapTable($segment) : $this->wrapValue($segment); })->implode('.'); } /** * Wrap a single string in keyword identifiers. * * @param string $value * @return string */ protected function wrapValue($value) { if ($value !== '*') { return '"'.str_replace('"', '""', $value).'"'; } return $value; } /** * Convert an array of column names into a delimited string. * * @param array $columns * @return string */ public function columnize(array $columns) { return implode(', ', array_map([$this, 'wrap'], $columns)); } /** * Create query parameter place-holders for an array. * * @param array $values * @return string */ public function parameterize(array $values) { return implode(', ', array_map([$this, 'parameter'], $values)); } /** * Get the appropriate query parameter place-holder for a value. * * @param mixed $value * @return string */ public function parameter($value) { return $this->isExpression($value) ? $this->getValue($value) : '?'; } /** * Quote the given string literal. * * @param string|array $value * @return string */ public function quoteString($value) { if (is_array($value)) { return implode(', ', array_map([$this, __FUNCTION__], $value)); } return "'$value'"; } /** * Determine if the given value is a raw expression. * * @param mixed $value * @return bool */ public function isExpression($value) { return $value instanceof Expression; } /** * Get the value of a raw expression. * * @param \Illuminate\Database\Query\Expression $expression * @return string */ public function getValue($expression) { return $expression->getValue(); } /** * Get the format for database stored dates. * * @return string */ public function getDateFormat() { return 'Y-m-d H:i:s'; } /** * Get the grammar's table prefix. * * @return string */ public function getTablePrefix() { return $this->tablePrefix; } /** * Set the grammar's table prefix. * * @param string $prefix * @return $this */ public function setTablePrefix($prefix) { $this->tablePrefix = $prefix; return $this; } } database/Events/MigrationEnded.php 0000644 00000000145 14736103231 0013156 0 ustar 00 <?php namespace Illuminate\Database\Events; class MigrationEnded extends MigrationEvent { // } database/Events/TransactionCommitted.php 0000644 00000000154 14736103231 0014420 0 ustar 00 <?php namespace Illuminate\Database\Events; class TransactionCommitted extends ConnectionEvent { // } database/Events/QueryExecuted.php 0000644 00000002162 14736103231 0013062 0 ustar 00 <?php namespace Illuminate\Database\Events; class QueryExecuted { /** * The SQL query that was executed. * * @var string */ public $sql; /** * The array of query bindings. * * @var array */ public $bindings; /** * The number of milliseconds it took to execute the query. * * @var float */ public $time; /** * The database connection instance. * * @var \Illuminate\Database\Connection */ public $connection; /** * The database connection name. * * @var string */ public $connectionName; /** * Create a new event instance. * * @param string $sql * @param array $bindings * @param float|null $time * @param \Illuminate\Database\Connection $connection * @return void */ public function __construct($sql, $bindings, $time, $connection) { $this->sql = $sql; $this->time = $time; $this->bindings = $bindings; $this->connection = $connection; $this->connectionName = $connection->getName(); } } database/Events/NoPendingMigrations.php 0000644 00000000574 14736103231 0014211 0 ustar 00 <?php namespace Illuminate\Database\Events; class NoPendingMigrations { /** * The migration method that was called. * * @var string */ public $method; /** * Create a new event instance. * * @param string $method * @return void */ public function __construct($method) { $this->method = $method; } } database/Events/ConnectionEvent.php 0000644 00000001145 14736103231 0013367 0 ustar 00 <?php namespace Illuminate\Database\Events; abstract class ConnectionEvent { /** * The name of the connection. * * @var string */ public $connectionName; /** * The database connection instance. * * @var \Illuminate\Database\Connection */ public $connection; /** * Create a new event instance. * * @param \Illuminate\Database\Connection $connection * @return void */ public function __construct($connection) { $this->connection = $connection; $this->connectionName = $connection->getName(); } } database/Events/TransactionRolledBack.php 0000644 00000000155 14736103231 0014476 0 ustar 00 <?php namespace Illuminate\Database\Events; class TransactionRolledBack extends ConnectionEvent { // } database/Events/MigrationsStarted.php 0000644 00000000307 14736103231 0013730 0 ustar 00 <?php namespace Illuminate\Database\Events; use Illuminate\Contracts\Database\Events\MigrationEvent as MigrationEventContract; class MigrationsStarted implements MigrationEventContract { // } database/Events/MigrationStarted.php 0000644 00000000147 14736103231 0013547 0 ustar 00 <?php namespace Illuminate\Database\Events; class MigrationStarted extends MigrationEvent { // } database/Events/StatementPrepared.php 0000644 00000001173 14736103231 0013716 0 ustar 00 <?php namespace Illuminate\Database\Events; class StatementPrepared { /** * The database connection instance. * * @var \Illuminate\Database\Connection */ public $connection; /** * The PDO statement. * * @var \PDOStatement */ public $statement; /** * Create a new event instance. * * @param \Illuminate\Database\Connection $connection * @param \PDOStatement $statement * @return void */ public function __construct($connection, $statement) { $this->statement = $statement; $this->connection = $connection; } } database/Events/MigrationsEnded.php 0000644 00000000305 14736103231 0013337 0 ustar 00 <?php namespace Illuminate\Database\Events; use Illuminate\Contracts\Database\Events\MigrationEvent as MigrationEventContract; class MigrationsEnded implements MigrationEventContract { // } database/Events/TransactionBeginning.php 0000644 00000000154 14736103231 0014373 0 ustar 00 <?php namespace Illuminate\Database\Events; class TransactionBeginning extends ConnectionEvent { // } database/Events/MigrationEvent.php 0000644 00000001451 14736103231 0013221 0 ustar 00 <?php namespace Illuminate\Database\Events; use Illuminate\Contracts\Database\Events\MigrationEvent as MigrationEventContract; use Illuminate\Database\Migrations\Migration; abstract class MigrationEvent implements MigrationEventContract { /** * An migration instance. * * @var \Illuminate\Database\Migrations\Migration */ public $migration; /** * The migration method that was called. * * @var string */ public $method; /** * Create a new event instance. * * @param \Illuminate\Database\Migrations\Migration $migration * @param string $method * @return void */ public function __construct(Migration $migration, $method) { $this->method = $method; $this->migration = $migration; } } database/SQLiteConnection.php 0000644 00000005224 14736103231 0012205 0 ustar 00 <?php namespace Illuminate\Database; use Doctrine\DBAL\Driver\PDOSqlite\Driver as DoctrineDriver; use Illuminate\Database\Query\Grammars\SQLiteGrammar as QueryGrammar; use Illuminate\Database\Query\Processors\SQLiteProcessor; use Illuminate\Database\Schema\Grammars\SQLiteGrammar as SchemaGrammar; use Illuminate\Database\Schema\SQLiteBuilder; class SQLiteConnection extends Connection { /** * Create a new database connection instance. * * @param \PDO|\Closure $pdo * @param string $database * @param string $tablePrefix * @param array $config * @return void */ public function __construct($pdo, $database = '', $tablePrefix = '', array $config = []) { parent::__construct($pdo, $database, $tablePrefix, $config); $enableForeignKeyConstraints = $this->getForeignKeyConstraintsConfigurationValue(); if ($enableForeignKeyConstraints === null) { return; } $enableForeignKeyConstraints ? $this->getSchemaBuilder()->enableForeignKeyConstraints() : $this->getSchemaBuilder()->disableForeignKeyConstraints(); } /** * Get the default query grammar instance. * * @return \Illuminate\Database\Query\Grammars\SQLiteGrammar */ protected function getDefaultQueryGrammar() { return $this->withTablePrefix(new QueryGrammar); } /** * Get a schema builder instance for the connection. * * @return \Illuminate\Database\Schema\SQLiteBuilder */ public function getSchemaBuilder() { if (is_null($this->schemaGrammar)) { $this->useDefaultSchemaGrammar(); } return new SQLiteBuilder($this); } /** * Get the default schema grammar instance. * * @return \Illuminate\Database\Schema\Grammars\SQLiteGrammar */ protected function getDefaultSchemaGrammar() { return $this->withTablePrefix(new SchemaGrammar); } /** * Get the default post processor instance. * * @return \Illuminate\Database\Query\Processors\SQLiteProcessor */ protected function getDefaultPostProcessor() { return new SQLiteProcessor; } /** * Get the Doctrine DBAL driver. * * @return \Doctrine\DBAL\Driver\PDOSqlite\Driver */ protected function getDoctrineDriver() { return new DoctrineDriver; } /** * Get the database connection foreign key constraints configuration option. * * @return bool|null */ protected function getForeignKeyConstraintsConfigurationValue() { return $this->getConfig('foreign_key_constraints'); } } database/MySqlConnection.php 0000644 00000003200 14736103231 0012101 0 ustar 00 <?php namespace Illuminate\Database; use Doctrine\DBAL\Driver\PDOMySql\Driver as DoctrineDriver; use Illuminate\Database\Query\Grammars\MySqlGrammar as QueryGrammar; use Illuminate\Database\Query\Processors\MySqlProcessor; use Illuminate\Database\Schema\Grammars\MySqlGrammar as SchemaGrammar; use Illuminate\Database\Schema\MySqlBuilder; class MySqlConnection extends Connection { /** * Get the default query grammar instance. * * @return \Illuminate\Database\Query\Grammars\MySqlGrammar */ protected function getDefaultQueryGrammar() { return $this->withTablePrefix(new QueryGrammar); } /** * Get a schema builder instance for the connection. * * @return \Illuminate\Database\Schema\MySqlBuilder */ public function getSchemaBuilder() { if (is_null($this->schemaGrammar)) { $this->useDefaultSchemaGrammar(); } return new MySqlBuilder($this); } /** * Get the default schema grammar instance. * * @return \Illuminate\Database\Schema\Grammars\MySqlGrammar */ protected function getDefaultSchemaGrammar() { return $this->withTablePrefix(new SchemaGrammar); } /** * Get the default post processor instance. * * @return \Illuminate\Database\Query\Processors\MySqlProcessor */ protected function getDefaultPostProcessor() { return new MySqlProcessor; } /** * Get the Doctrine DBAL driver. * * @return \Doctrine\DBAL\Driver\PDOMySql\Driver */ protected function getDoctrineDriver() { return new DoctrineDriver; } } database/Console/Factories/stubs/factory.stub 0000644 00000000337 14736103231 0015342 0 ustar 00 <?php /** @var \Illuminate\Database\Eloquent\Factory $factory */ use Faker\Generator as Faker; use {{ namespacedModel }}; $factory->define({{ model }}::class, function (Faker $faker) { return [ // ]; }); database/Console/Factories/FactoryMakeCommand.php 0000644 00000004723 14736103231 0016054 0 ustar 00 <?php namespace Illuminate\Database\Console\Factories; use Illuminate\Console\GeneratorCommand; use Symfony\Component\Console\Input\InputOption; class FactoryMakeCommand extends GeneratorCommand { /** * The console command name. * * @var string */ protected $name = 'make:factory'; /** * The console command description. * * @var string */ protected $description = 'Create a new model factory'; /** * The type of class being generated. * * @var string */ protected $type = 'Factory'; /** * Get the stub file for the generator. * * @return string */ protected function getStub() { return $this->resolveStubPath('/stubs/factory.stub'); } /** * Resolve the fully-qualified path to the stub. * * @param string $stub * @return string */ protected function resolveStubPath($stub) { return file_exists($customPath = $this->laravel->basePath(trim($stub, '/'))) ? $customPath : __DIR__.$stub; } /** * Build the class with the given name. * * @param string $name * @return string */ protected function buildClass($name) { $namespaceModel = $this->option('model') ? $this->qualifyClass($this->option('model')) : trim($this->rootNamespace(), '\\').'\\Model'; $model = class_basename($namespaceModel); $replace = [ 'NamespacedDummyModel' => $namespaceModel, '{{ namespacedModel }}' => $namespaceModel, '{{namespacedModel}}' => $namespaceModel, 'DummyModel' => $model, '{{ model }}' => $model, '{{model}}' => $model, ]; return str_replace( array_keys($replace), array_values($replace), parent::buildClass($name) ); } /** * Get the destination class path. * * @param string $name * @return string */ protected function getPath($name) { $name = str_replace( ['\\', '/'], '', $this->argument('name') ); return $this->laravel->databasePath()."/factories/{$name}.php"; } /** * Get the console command options. * * @return array */ protected function getOptions() { return [ ['model', 'm', InputOption::VALUE_OPTIONAL, 'The name of the model'], ]; } } database/Console/WipeCommand.php 0000644 00000005136 14736103231 0012633 0 ustar 00 <?php namespace Illuminate\Database\Console; use Illuminate\Console\Command; use Illuminate\Console\ConfirmableTrait; use Symfony\Component\Console\Input\InputOption; class WipeCommand extends Command { use ConfirmableTrait; /** * The console command name. * * @var string */ protected $name = 'db:wipe'; /** * The console command description. * * @var string */ protected $description = 'Drop all tables, views, and types'; /** * Execute the console command. * * @return int */ public function handle() { if (! $this->confirmToProceed()) { return 1; } $database = $this->input->getOption('database'); if ($this->option('drop-views')) { $this->dropAllViews($database); $this->info('Dropped all views successfully.'); } $this->dropAllTables($database); $this->info('Dropped all tables successfully.'); if ($this->option('drop-types')) { $this->dropAllTypes($database); $this->info('Dropped all types successfully.'); } return 0; } /** * Drop all of the database tables. * * @param string $database * @return void */ protected function dropAllTables($database) { $this->laravel['db']->connection($database) ->getSchemaBuilder() ->dropAllTables(); } /** * Drop all of the database views. * * @param string $database * @return void */ protected function dropAllViews($database) { $this->laravel['db']->connection($database) ->getSchemaBuilder() ->dropAllViews(); } /** * Drop all of the database types. * * @param string $database * @return void */ protected function dropAllTypes($database) { $this->laravel['db']->connection($database) ->getSchemaBuilder() ->dropAllTypes(); } /** * Get the console command options. * * @return array */ protected function getOptions() { return [ ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use'], ['drop-views', null, InputOption::VALUE_NONE, 'Drop all tables and views'], ['drop-types', null, InputOption::VALUE_NONE, 'Drop all tables and types (Postgres only)'], ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production'], ]; } } database/Console/Seeds/stubs/seeder.stub 0000644 00000000310 14736103231 0014255 0 ustar 00 <?php use Illuminate\Database\Seeder; class {{ class }} extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { // } } database/Console/Seeds/SeederMakeCommand.php 0000644 00000004267 14736103231 0015003 0 ustar 00 <?php namespace Illuminate\Database\Console\Seeds; use Illuminate\Console\GeneratorCommand; use Illuminate\Filesystem\Filesystem; use Illuminate\Support\Composer; class SeederMakeCommand extends GeneratorCommand { /** * The console command name. * * @var string */ protected $name = 'make:seeder'; /** * The console command description. * * @var string */ protected $description = 'Create a new seeder class'; /** * The type of class being generated. * * @var string */ protected $type = 'Seeder'; /** * The Composer instance. * * @var \Illuminate\Support\Composer */ protected $composer; /** * Create a new command instance. * * @param \Illuminate\Filesystem\Filesystem $files * @param \Illuminate\Support\Composer $composer * @return void */ public function __construct(Filesystem $files, Composer $composer) { parent::__construct($files); $this->composer = $composer; } /** * Execute the console command. * * @return void */ public function handle() { parent::handle(); $this->composer->dumpAutoloads(); } /** * Get the stub file for the generator. * * @return string */ protected function getStub() { return $this->resolveStubPath('/stubs/seeder.stub'); } /** * Resolve the fully-qualified path to the stub. * * @param string $stub * @return string */ protected function resolveStubPath($stub) { return file_exists($customPath = $this->laravel->basePath(trim($stub, '/'))) ? $customPath : __DIR__.$stub; } /** * Get the destination class path. * * @param string $name * @return string */ protected function getPath($name) { return $this->laravel->databasePath().'/seeds/'.$name.'.php'; } /** * Parse the class name and format according to the root namespace. * * @param string $name * @return string */ protected function qualifyClass($name) { return $name; } } database/Console/Seeds/SeedCommand.php 0000644 00000005305 14736103231 0013650 0 ustar 00 <?php namespace Illuminate\Database\Console\Seeds; use Illuminate\Console\Command; use Illuminate\Console\ConfirmableTrait; use Illuminate\Database\ConnectionResolverInterface as Resolver; use Illuminate\Database\Eloquent\Model; use Symfony\Component\Console\Input\InputOption; class SeedCommand extends Command { use ConfirmableTrait; /** * The console command name. * * @var string */ protected $name = 'db:seed'; /** * The console command description. * * @var string */ protected $description = 'Seed the database with records'; /** * The connection resolver instance. * * @var \Illuminate\Database\ConnectionResolverInterface */ protected $resolver; /** * Create a new database seed command instance. * * @param \Illuminate\Database\ConnectionResolverInterface $resolver * @return void */ public function __construct(Resolver $resolver) { parent::__construct(); $this->resolver = $resolver; } /** * Execute the console command. * * @return int */ public function handle() { if (! $this->confirmToProceed()) { return 1; } $previousConnection = $this->resolver->getDefaultConnection(); $this->resolver->setDefaultConnection($this->getDatabase()); Model::unguarded(function () { $this->getSeeder()->__invoke(); }); if ($previousConnection) { $this->resolver->setDefaultConnection($previousConnection); } $this->info('Database seeding completed successfully.'); return 0; } /** * Get a seeder instance from the container. * * @return \Illuminate\Database\Seeder */ protected function getSeeder() { $class = $this->laravel->make($this->input->getOption('class')); return $class->setContainer($this->laravel)->setCommand($this); } /** * Get the name of the database connection to use. * * @return string */ protected function getDatabase() { $database = $this->input->getOption('database'); return $database ?: $this->laravel['config']['database.default']; } /** * Get the console command options. * * @return array */ protected function getOptions() { return [ ['class', null, InputOption::VALUE_OPTIONAL, 'The class name of the root seeder', 'DatabaseSeeder'], ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to seed'], ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production'], ]; } } database/Console/Migrations/MigrateCommand.php 0000644 00000005777 14736103231 0015446 0 ustar 00 <?php namespace Illuminate\Database\Console\Migrations; use Illuminate\Console\ConfirmableTrait; use Illuminate\Database\Migrations\Migrator; class MigrateCommand extends BaseCommand { use ConfirmableTrait; /** * The name and signature of the console command. * * @var string */ protected $signature = 'migrate {--database= : The database connection to use} {--force : Force the operation to run when in production} {--path=* : The path(s) to the migrations files to be executed} {--realpath : Indicate any provided migration file paths are pre-resolved absolute paths} {--pretend : Dump the SQL queries that would be run} {--seed : Indicates if the seed task should be re-run} {--step : Force the migrations to be run so they can be rolled back individually}'; /** * The console command description. * * @var string */ protected $description = 'Run the database migrations'; /** * The migrator instance. * * @var \Illuminate\Database\Migrations\Migrator */ protected $migrator; /** * Create a new migration command instance. * * @param \Illuminate\Database\Migrations\Migrator $migrator * @return void */ public function __construct(Migrator $migrator) { parent::__construct(); $this->migrator = $migrator; } /** * Execute the console command. * * @return int */ public function handle() { if (! $this->confirmToProceed()) { return 1; } $this->migrator->usingConnection($this->option('database'), function () { $this->prepareDatabase(); // Next, we will check to see if a path option has been defined. If it has // we will use the path relative to the root of this installation folder // so that migrations may be run for any path within the applications. $this->migrator->setOutput($this->output) ->run($this->getMigrationPaths(), [ 'pretend' => $this->option('pretend'), 'step' => $this->option('step'), ]); // Finally, if the "seed" option has been given, we will re-run the database // seed task to re-populate the database, which is convenient when adding // a migration and a seed at the same time, as it is only this command. if ($this->option('seed') && ! $this->option('pretend')) { $this->call('db:seed', ['--force' => true]); } }); return 0; } /** * Prepare the migration database for running. * * @return void */ protected function prepareDatabase() { if (! $this->migrator->repositoryExists()) { $this->call('migrate:install', array_filter([ '--database' => $this->option('database'), ])); } } } database/Console/Migrations/RefreshCommand.php 0000644 00000010754 14736103231 0015443 0 ustar 00 <?php namespace Illuminate\Database\Console\Migrations; use Illuminate\Console\Command; use Illuminate\Console\ConfirmableTrait; use Symfony\Component\Console\Input\InputOption; class RefreshCommand extends Command { use ConfirmableTrait; /** * The console command name. * * @var string */ protected $name = 'migrate:refresh'; /** * The console command description. * * @var string */ protected $description = 'Reset and re-run all migrations'; /** * Execute the console command. * * @return int */ public function handle() { if (! $this->confirmToProceed()) { return 1; } // Next we'll gather some of the options so that we can have the right options // to pass to the commands. This includes options such as which database to // use and the path to use for the migration. Then we'll run the command. $database = $this->input->getOption('database'); $path = $this->input->getOption('path'); // If the "step" option is specified it means we only want to rollback a small // number of migrations before migrating again. For example, the user might // only rollback and remigrate the latest four migrations instead of all. $step = $this->input->getOption('step') ?: 0; if ($step > 0) { $this->runRollback($database, $path, $step); } else { $this->runReset($database, $path); } // The refresh command is essentially just a brief aggregate of a few other of // the migration commands and just provides a convenient wrapper to execute // them in succession. We'll also see if we need to re-seed the database. $this->call('migrate', array_filter([ '--database' => $database, '--path' => $path, '--realpath' => $this->input->getOption('realpath'), '--force' => true, ])); if ($this->needsSeeding()) { $this->runSeeder($database); } return 0; } /** * Run the rollback command. * * @param string $database * @param string $path * @param int $step * @return void */ protected function runRollback($database, $path, $step) { $this->call('migrate:rollback', array_filter([ '--database' => $database, '--path' => $path, '--realpath' => $this->input->getOption('realpath'), '--step' => $step, '--force' => true, ])); } /** * Run the reset command. * * @param string $database * @param string $path * @return void */ protected function runReset($database, $path) { $this->call('migrate:reset', array_filter([ '--database' => $database, '--path' => $path, '--realpath' => $this->input->getOption('realpath'), '--force' => true, ])); } /** * Determine if the developer has requested database seeding. * * @return bool */ protected function needsSeeding() { return $this->option('seed') || $this->option('seeder'); } /** * Run the database seeder command. * * @param string $database * @return void */ protected function runSeeder($database) { $this->call('db:seed', array_filter([ '--database' => $database, '--class' => $this->option('seeder') ?: 'DatabaseSeeder', '--force' => true, ])); } /** * Get the console command options. * * @return array */ protected function getOptions() { return [ ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use'], ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production'], ['path', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'The path(s) to the migrations files to be executed'], ['realpath', null, InputOption::VALUE_NONE, 'Indicate any provided migration file paths are pre-resolved absolute paths'], ['seed', null, InputOption::VALUE_NONE, 'Indicates if the seed task should be re-run'], ['seeder', null, InputOption::VALUE_OPTIONAL, 'The class name of the root seeder'], ['step', null, InputOption::VALUE_OPTIONAL, 'The number of migrations to be reverted & re-run'], ]; } } database/Console/Migrations/FreshCommand.php 0000644 00000006145 14736103231 0015113 0 ustar 00 <?php namespace Illuminate\Database\Console\Migrations; use Illuminate\Console\Command; use Illuminate\Console\ConfirmableTrait; use Symfony\Component\Console\Input\InputOption; class FreshCommand extends Command { use ConfirmableTrait; /** * The console command name. * * @var string */ protected $name = 'migrate:fresh'; /** * The console command description. * * @var string */ protected $description = 'Drop all tables and re-run all migrations'; /** * Execute the console command. * * @return int */ public function handle() { if (! $this->confirmToProceed()) { return 1; } $database = $this->input->getOption('database'); $this->call('db:wipe', array_filter([ '--database' => $database, '--drop-views' => $this->option('drop-views'), '--drop-types' => $this->option('drop-types'), '--force' => true, ])); $this->call('migrate', array_filter([ '--database' => $database, '--path' => $this->input->getOption('path'), '--realpath' => $this->input->getOption('realpath'), '--force' => true, '--step' => $this->option('step'), ])); if ($this->needsSeeding()) { $this->runSeeder($database); } return 0; } /** * Determine if the developer has requested database seeding. * * @return bool */ protected function needsSeeding() { return $this->option('seed') || $this->option('seeder'); } /** * Run the database seeder command. * * @param string $database * @return void */ protected function runSeeder($database) { $this->call('db:seed', array_filter([ '--database' => $database, '--class' => $this->option('seeder') ?: 'DatabaseSeeder', '--force' => true, ])); } /** * Get the console command options. * * @return array */ protected function getOptions() { return [ ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use'], ['drop-views', null, InputOption::VALUE_NONE, 'Drop all tables and views'], ['drop-types', null, InputOption::VALUE_NONE, 'Drop all tables and types (Postgres only)'], ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production'], ['path', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'The path(s) to the migrations files to be executed'], ['realpath', null, InputOption::VALUE_NONE, 'Indicate any provided migration file paths are pre-resolved absolute paths'], ['seed', null, InputOption::VALUE_NONE, 'Indicates if the seed task should be re-run'], ['seeder', null, InputOption::VALUE_OPTIONAL, 'The class name of the root seeder'], ['step', null, InputOption::VALUE_NONE, 'Force the migrations to be run so they can be rolled back individually'], ]; } } database/Console/Migrations/StatusCommand.php 0000644 00000006176 14736103231 0015333 0 ustar 00 <?php namespace Illuminate\Database\Console\Migrations; use Illuminate\Database\Migrations\Migrator; use Illuminate\Support\Collection; use Symfony\Component\Console\Input\InputOption; class StatusCommand extends BaseCommand { /** * The console command name. * * @var string */ protected $name = 'migrate:status'; /** * The console command description. * * @var string */ protected $description = 'Show the status of each migration'; /** * The migrator instance. * * @var \Illuminate\Database\Migrations\Migrator */ protected $migrator; /** * Create a new migration rollback command instance. * * @param \Illuminate\Database\Migrations\Migrator $migrator * @return void */ public function __construct(Migrator $migrator) { parent::__construct(); $this->migrator = $migrator; } /** * Execute the console command. * * @return int|null */ public function handle() { return $this->migrator->usingConnection($this->option('database'), function () { if (! $this->migrator->repositoryExists()) { $this->error('Migration table not found.'); return 1; } $ran = $this->migrator->getRepository()->getRan(); $batches = $this->migrator->getRepository()->getMigrationBatches(); if (count($migrations = $this->getStatusFor($ran, $batches)) > 0) { $this->table(['Ran?', 'Migration', 'Batch'], $migrations); } else { $this->error('No migrations found'); } }); } /** * Get the status for the given ran migrations. * * @param array $ran * @param array $batches * @return \Illuminate\Support\Collection */ protected function getStatusFor(array $ran, array $batches) { return Collection::make($this->getAllMigrationFiles()) ->map(function ($migration) use ($ran, $batches) { $migrationName = $this->migrator->getMigrationName($migration); return in_array($migrationName, $ran) ? ['<info>Yes</info>', $migrationName, $batches[$migrationName]] : ['<fg=red>No</fg=red>', $migrationName]; }); } /** * Get an array of all of the migration files. * * @return array */ protected function getAllMigrationFiles() { return $this->migrator->getMigrationFiles($this->getMigrationPaths()); } /** * Get the console command options. * * @return array */ protected function getOptions() { return [ ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use'], ['path', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'The path(s) to the migrations files to use'], ['realpath', null, InputOption::VALUE_NONE, 'Indicate any provided migration file paths are pre-resolved absolute paths'], ]; } } database/Console/Migrations/MigrateMakeCommand.php 0000644 00000010424 14736103231 0016225 0 ustar 00 <?php namespace Illuminate\Database\Console\Migrations; use Illuminate\Database\Migrations\MigrationCreator; use Illuminate\Support\Composer; use Illuminate\Support\Str; class MigrateMakeCommand extends BaseCommand { /** * The console command signature. * * @var string */ protected $signature = 'make:migration {name : The name of the migration} {--create= : The table to be created} {--table= : The table to migrate} {--path= : The location where the migration file should be created} {--realpath : Indicate any provided migration file paths are pre-resolved absolute paths} {--fullpath : Output the full path of the migration}'; /** * The console command description. * * @var string */ protected $description = 'Create a new migration file'; /** * The migration creator instance. * * @var \Illuminate\Database\Migrations\MigrationCreator */ protected $creator; /** * The Composer instance. * * @var \Illuminate\Support\Composer */ protected $composer; /** * Create a new migration install command instance. * * @param \Illuminate\Database\Migrations\MigrationCreator $creator * @param \Illuminate\Support\Composer $composer * @return void */ public function __construct(MigrationCreator $creator, Composer $composer) { parent::__construct(); $this->creator = $creator; $this->composer = $composer; } /** * Execute the console command. * * @return void */ public function handle() { // It's possible for the developer to specify the tables to modify in this // schema operation. The developer may also specify if this table needs // to be freshly created so we can create the appropriate migrations. $name = Str::snake(trim($this->input->getArgument('name'))); $table = $this->input->getOption('table'); $create = $this->input->getOption('create') ?: false; // If no table was given as an option but a create option is given then we // will use the "create" option as the table name. This allows the devs // to pass a table name into this option as a short-cut for creating. if (! $table && is_string($create)) { $table = $create; $create = true; } // Next, we will attempt to guess the table name if this the migration has // "create" in the name. This will allow us to provide a convenient way // of creating migrations that create new tables for the application. if (! $table) { [$table, $create] = TableGuesser::guess($name); } // Now we are ready to write the migration out to disk. Once we've written // the migration out, we will dump-autoload for the entire framework to // make sure that the migrations are registered by the class loaders. $this->writeMigration($name, $table, $create); $this->composer->dumpAutoloads(); } /** * Write the migration file to disk. * * @param string $name * @param string $table * @param bool $create * @return string */ protected function writeMigration($name, $table, $create) { $file = $this->creator->create( $name, $this->getMigrationPath(), $table, $create ); if (! $this->option('fullpath')) { $file = pathinfo($file, PATHINFO_FILENAME); } $this->line("<info>Created Migration:</info> {$file}"); } /** * Get migration path (either specified by '--path' option or default location). * * @return string */ protected function getMigrationPath() { if (! is_null($targetPath = $this->input->getOption('path'))) { return ! $this->usingRealPath() ? $this->laravel->basePath().'/'.$targetPath : $targetPath; } return parent::getMigrationPath(); } /** * Determine if the given path(s) are pre-resolved "real" paths. * * @return bool */ protected function usingRealPath() { return $this->input->hasOption('realpath') && $this->option('realpath'); } } database/Console/Migrations/TableGuesser.php 0000644 00000001607 14736103231 0015130 0 ustar 00 <?php namespace Illuminate\Database\Console\Migrations; class TableGuesser { const CREATE_PATTERNS = [ '/^create_(\w+)_table$/', '/^create_(\w+)$/', ]; const CHANGE_PATTERNS = [ '/_(to|from|in)_(\w+)_table$/', '/_(to|from|in)_(\w+)$/', ]; /** * Attempt to guess the table name and "creation" status of the given migration. * * @param string $migration * @return array */ public static function guess($migration) { foreach (self::CREATE_PATTERNS as $pattern) { if (preg_match($pattern, $migration, $matches)) { return [$matches[1], $create = true]; } } foreach (self::CHANGE_PATTERNS as $pattern) { if (preg_match($pattern, $migration, $matches)) { return [$matches[2], $create = false]; } } } } database/Console/Migrations/InstallCommand.php 0000644 00000003050 14736103231 0015442 0 ustar 00 <?php namespace Illuminate\Database\Console\Migrations; use Illuminate\Console\Command; use Illuminate\Database\Migrations\MigrationRepositoryInterface; use Symfony\Component\Console\Input\InputOption; class InstallCommand extends Command { /** * The console command name. * * @var string */ protected $name = 'migrate:install'; /** * The console command description. * * @var string */ protected $description = 'Create the migration repository'; /** * The repository instance. * * @var \Illuminate\Database\Migrations\MigrationRepositoryInterface */ protected $repository; /** * Create a new migration install command instance. * * @param \Illuminate\Database\Migrations\MigrationRepositoryInterface $repository * @return void */ public function __construct(MigrationRepositoryInterface $repository) { parent::__construct(); $this->repository = $repository; } /** * Execute the console command. * * @return void */ public function handle() { $this->repository->setSource($this->input->getOption('database')); $this->repository->createRepository(); $this->info('Migration table created successfully.'); } /** * Get the console command options. * * @return array */ protected function getOptions() { return [ ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use'], ]; } } database/Console/Migrations/ResetCommand.php 0000644 00000004776 14736103231 0015136 0 ustar 00 <?php namespace Illuminate\Database\Console\Migrations; use Illuminate\Console\ConfirmableTrait; use Illuminate\Database\Migrations\Migrator; use Symfony\Component\Console\Input\InputOption; class ResetCommand extends BaseCommand { use ConfirmableTrait; /** * The console command name. * * @var string */ protected $name = 'migrate:reset'; /** * The console command description. * * @var string */ protected $description = 'Rollback all database migrations'; /** * The migrator instance. * * @var \Illuminate\Database\Migrations\Migrator */ protected $migrator; /** * Create a new migration rollback command instance. * * @param \Illuminate\Database\Migrations\Migrator $migrator * @return void */ public function __construct(Migrator $migrator) { parent::__construct(); $this->migrator = $migrator; } /** * Execute the console command. * * @return int */ public function handle() { if (! $this->confirmToProceed()) { return 1; } return $this->migrator->usingConnection($this->option('database'), function () { // First, we'll make sure that the migration table actually exists before we // start trying to rollback and re-run all of the migrations. If it's not // present we'll just bail out with an info message for the developers. if (! $this->migrator->repositoryExists()) { return $this->comment('Migration table not found.'); } $this->migrator->setOutput($this->output)->reset( $this->getMigrationPaths(), $this->option('pretend') ); }); return 0; } /** * Get the console command options. * * @return array */ protected function getOptions() { return [ ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use'], ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production'], ['path', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'The path(s) to the migrations files to be executed'], ['realpath', null, InputOption::VALUE_NONE, 'Indicate any provided migration file paths are pre-resolved absolute paths'], ['pretend', null, InputOption::VALUE_NONE, 'Dump the SQL queries that would be run'], ]; } } database/Console/Migrations/BaseCommand.php 0000644 00000002652 14736103231 0014715 0 ustar 00 <?php namespace Illuminate\Database\Console\Migrations; use Illuminate\Console\Command; class BaseCommand extends Command { /** * Get all of the migration paths. * * @return array */ protected function getMigrationPaths() { // Here, we will check to see if a path option has been defined. If it has we will // use the path relative to the root of the installation folder so our database // migrations may be run for any customized path from within the application. if ($this->input->hasOption('path') && $this->option('path')) { return collect($this->option('path'))->map(function ($path) { return ! $this->usingRealPath() ? $this->laravel->basePath().'/'.$path : $path; })->all(); } return array_merge( $this->migrator->paths(), [$this->getMigrationPath()] ); } /** * Determine if the given path(s) are pre-resolved "real" paths. * * @return bool */ protected function usingRealPath() { return $this->input->hasOption('realpath') && $this->option('realpath'); } /** * Get the path to the migration directory. * * @return string */ protected function getMigrationPath() { return $this->laravel->databasePath().DIRECTORY_SEPARATOR.'migrations'; } } database/Console/Migrations/RollbackCommand.php 0000644 00000004512 14736103231 0015571 0 ustar 00 <?php namespace Illuminate\Database\Console\Migrations; use Illuminate\Console\ConfirmableTrait; use Illuminate\Database\Migrations\Migrator; use Symfony\Component\Console\Input\InputOption; class RollbackCommand extends BaseCommand { use ConfirmableTrait; /** * The console command name. * * @var string */ protected $name = 'migrate:rollback'; /** * The console command description. * * @var string */ protected $description = 'Rollback the last database migration'; /** * The migrator instance. * * @var \Illuminate\Database\Migrations\Migrator */ protected $migrator; /** * Create a new migration rollback command instance. * * @param \Illuminate\Database\Migrations\Migrator $migrator * @return void */ public function __construct(Migrator $migrator) { parent::__construct(); $this->migrator = $migrator; } /** * Execute the console command. * * @return int */ public function handle() { if (! $this->confirmToProceed()) { return 1; } $this->migrator->usingConnection($this->option('database'), function () { $this->migrator->setOutput($this->output)->rollback( $this->getMigrationPaths(), [ 'pretend' => $this->option('pretend'), 'step' => (int) $this->option('step'), ] ); }); return 0; } /** * Get the console command options. * * @return array */ protected function getOptions() { return [ ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use'], ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production'], ['path', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'The path(s) to the migrations files to be executed'], ['realpath', null, InputOption::VALUE_NONE, 'Indicate any provided migration file paths are pre-resolved absolute paths'], ['pretend', null, InputOption::VALUE_NONE, 'Dump the SQL queries that would be run'], ['step', null, InputOption::VALUE_OPTIONAL, 'The number of migrations to be reverted'], ]; } } database/Schema/PostgresBuilder.php 0000644 00000007576 14736103231 0013355 0 ustar 00 <?php namespace Illuminate\Database\Schema; class PostgresBuilder extends Builder { /** * Determine if the given table exists. * * @param string $table * @return bool */ public function hasTable($table) { [$schema, $table] = $this->parseSchemaAndTable($table); $table = $this->connection->getTablePrefix().$table; return count($this->connection->select( $this->grammar->compileTableExists(), [$schema, $table] )) > 0; } /** * Drop all tables from the database. * * @return void */ public function dropAllTables() { $tables = []; $excludedTables = $this->connection->getConfig('dont_drop') ?? ['spatial_ref_sys']; foreach ($this->getAllTables() as $row) { $row = (array) $row; $table = reset($row); if (! in_array($table, $excludedTables)) { $tables[] = $table; } } if (empty($tables)) { return; } $this->connection->statement( $this->grammar->compileDropAllTables($tables) ); } /** * Drop all views from the database. * * @return void */ public function dropAllViews() { $views = []; foreach ($this->getAllViews() as $row) { $row = (array) $row; $views[] = reset($row); } if (empty($views)) { return; } $this->connection->statement( $this->grammar->compileDropAllViews($views) ); } /** * Drop all types from the database. * * @return void */ public function dropAllTypes() { $types = []; foreach ($this->getAllTypes() as $row) { $row = (array) $row; $types[] = reset($row); } if (empty($types)) { return; } $this->connection->statement( $this->grammar->compileDropAllTypes($types) ); } /** * Get all of the table names for the database. * * @return array */ public function getAllTables() { return $this->connection->select( $this->grammar->compileGetAllTables((array) $this->connection->getConfig('schema')) ); } /** * Get all of the view names for the database. * * @return array */ public function getAllViews() { return $this->connection->select( $this->grammar->compileGetAllViews((array) $this->connection->getConfig('schema')) ); } /** * Get all of the type names for the database. * * @return array */ public function getAllTypes() { return $this->connection->select( $this->grammar->compileGetAllTypes() ); } /** * Get the column listing for a given table. * * @param string $table * @return array */ public function getColumnListing($table) { [$schema, $table] = $this->parseSchemaAndTable($table); $table = $this->connection->getTablePrefix().$table; $results = $this->connection->select( $this->grammar->compileColumnListing(), [$schema, $table] ); return $this->connection->getPostProcessor()->processColumnListing($results); } /** * Parse the table name and extract the schema and table. * * @param string $table * @return array */ protected function parseSchemaAndTable($table) { $table = explode('.', $table); if (is_array($schema = $this->connection->getConfig('schema'))) { if (in_array($table[0], $schema)) { return [array_shift($table), implode('.', $table)]; } $schema = head($schema); } return [$schema ?: 'public', implode('.', $table)]; } } database/Schema/MySqlBuilder.php 0000644 00000004624 14736103231 0012603 0 ustar 00 <?php namespace Illuminate\Database\Schema; class MySqlBuilder extends Builder { /** * Determine if the given table exists. * * @param string $table * @return bool */ public function hasTable($table) { $table = $this->connection->getTablePrefix().$table; return count($this->connection->select( $this->grammar->compileTableExists(), [$this->connection->getDatabaseName(), $table] )) > 0; } /** * Get the column listing for a given table. * * @param string $table * @return array */ public function getColumnListing($table) { $table = $this->connection->getTablePrefix().$table; $results = $this->connection->select( $this->grammar->compileColumnListing(), [$this->connection->getDatabaseName(), $table] ); return $this->connection->getPostProcessor()->processColumnListing($results); } /** * Drop all tables from the database. * * @return void */ public function dropAllTables() { $tables = []; foreach ($this->getAllTables() as $row) { $row = (array) $row; $tables[] = reset($row); } if (empty($tables)) { return; } $this->disableForeignKeyConstraints(); $this->connection->statement( $this->grammar->compileDropAllTables($tables) ); $this->enableForeignKeyConstraints(); } /** * Drop all views from the database. * * @return void */ public function dropAllViews() { $views = []; foreach ($this->getAllViews() as $row) { $row = (array) $row; $views[] = reset($row); } if (empty($views)) { return; } $this->connection->statement( $this->grammar->compileDropAllViews($views) ); } /** * Get all of the table names for the database. * * @return array */ public function getAllTables() { return $this->connection->select( $this->grammar->compileGetAllTables() ); } /** * Get all of the view names for the database. * * @return array */ public function getAllViews() { return $this->connection->select( $this->grammar->compileGetAllViews() ); } } database/Schema/ColumnDefinition.php 0000644 00000003715 14736103231 0013475 0 ustar 00 <?php namespace Illuminate\Database\Schema; use Illuminate\Database\Query\Expression; use Illuminate\Support\Fluent; /** * @method ColumnDefinition after(string $column) Place the column "after" another column (MySQL) * @method ColumnDefinition always() Used as a modifier for generatedAs() (PostgreSQL) * @method ColumnDefinition autoIncrement() Set INTEGER columns as auto-increment (primary key) * @method ColumnDefinition change() Change the column * @method ColumnDefinition charset(string $charset) Specify a character set for the column (MySQL) * @method ColumnDefinition collation(string $collation) Specify a collation for the column (MySQL/PostgreSQL/SQL Server) * @method ColumnDefinition comment(string $comment) Add a comment to the column (MySQL) * @method ColumnDefinition default(mixed $value) Specify a "default" value for the column * @method ColumnDefinition first() Place the column "first" in the table (MySQL) * @method ColumnDefinition generatedAs(string|Expression $expression = null) Create a SQL compliant identity column (PostgreSQL) * @method ColumnDefinition index(string $indexName = null) Add an index * @method ColumnDefinition nullable(bool $value = true) Allow NULL values to be inserted into the column * @method ColumnDefinition persisted() Mark the computed generated column as persistent (SQL Server) * @method ColumnDefinition primary() Add a primary index * @method ColumnDefinition spatialIndex() Add a spatial index * @method ColumnDefinition storedAs(string $expression) Create a stored generated column (MySQL) * @method ColumnDefinition unique(string $indexName = null) Add a unique index * @method ColumnDefinition unsigned() Set the INTEGER column as UNSIGNED (MySQL) * @method ColumnDefinition useCurrent() Set the TIMESTAMP column to use CURRENT_TIMESTAMP as default value * @method ColumnDefinition virtualAs(string $expression) Create a virtual generated column (MySQL) */ class ColumnDefinition extends Fluent { // } database/Schema/SqlServerBuilder.php 0000644 00000001121 14736103231 0013451 0 ustar 00 <?php namespace Illuminate\Database\Schema; class SqlServerBuilder extends Builder { /** * Drop all tables from the database. * * @return void */ public function dropAllTables() { $this->connection->statement($this->grammar->compileDropAllForeignKeys()); $this->connection->statement($this->grammar->compileDropAllTables()); } /** * Drop all views from the database. * * @return void */ public function dropAllViews() { $this->connection->statement($this->grammar->compileDropAllViews()); } } database/Schema/ForeignIdColumnDefinition.php 0000644 00000002703 14736103231 0015260 0 ustar 00 <?php namespace Illuminate\Database\Schema; use Illuminate\Support\Str; class ForeignIdColumnDefinition extends ColumnDefinition { /** * The schema builder blueprint instance. * * @var \Illuminate\Database\Schema\Blueprint */ protected $blueprint; /** * Create a new foreign ID column definition. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param array $attributes * @return void */ public function __construct(Blueprint $blueprint, $attributes = []) { parent::__construct($attributes); $this->blueprint = $blueprint; } /** * Create a foreign key constraint on this column referencing the "id" column of the conventionally related table. * * @param string|null $table * @param string $column * @return \Illuminate\Support\Fluent|\Illuminate\Database\Schema\ForeignKeyDefinition */ public function constrained($table = null, $column = 'id') { return $this->references($column)->on($table ?? Str::plural(Str::beforeLast($this->name, '_'.$column))); } /** * Specify which column this foreign ID references on another table. * * @param string $column * @return \Illuminate\Support\Fluent|\Illuminate\Database\Schema\ForeignKeyDefinition */ public function references($column) { return $this->blueprint->foreign($this->name)->references($column); } } database/Schema/Blueprint.php 0000644 00000121114 14736103231 0012165 0 ustar 00 <?php namespace Illuminate\Database\Schema; use BadMethodCallException; use Closure; use Illuminate\Database\Connection; use Illuminate\Database\Query\Expression; use Illuminate\Database\Schema\Grammars\Grammar; use Illuminate\Database\SQLiteConnection; use Illuminate\Support\Fluent; use Illuminate\Support\Traits\Macroable; class Blueprint { use Macroable; /** * The table the blueprint describes. * * @var string */ protected $table; /** * The prefix of the table. * * @var string */ protected $prefix; /** * The columns that should be added to the table. * * @var \Illuminate\Database\Schema\ColumnDefinition[] */ protected $columns = []; /** * The commands that should be run for the table. * * @var \Illuminate\Support\Fluent[] */ protected $commands = []; /** * The storage engine that should be used for the table. * * @var string */ public $engine; /** * The default character set that should be used for the table. * * @var string */ public $charset; /** * The collation that should be used for the table. * * @var string */ public $collation; /** * Whether to make the table temporary. * * @var bool */ public $temporary = false; /** * Create a new schema blueprint. * * @param string $table * @param \Closure|null $callback * @param string $prefix * @return void */ public function __construct($table, Closure $callback = null, $prefix = '') { $this->table = $table; $this->prefix = $prefix; if (! is_null($callback)) { $callback($this); } } /** * Execute the blueprint against the database. * * @param \Illuminate\Database\Connection $connection * @param \Illuminate\Database\Schema\Grammars\Grammar $grammar * @return void */ public function build(Connection $connection, Grammar $grammar) { foreach ($this->toSql($connection, $grammar) as $statement) { $connection->statement($statement); } } /** * Get the raw SQL statements for the blueprint. * * @param \Illuminate\Database\Connection $connection * @param \Illuminate\Database\Schema\Grammars\Grammar $grammar * @return array */ public function toSql(Connection $connection, Grammar $grammar) { $this->addImpliedCommands($grammar); $statements = []; // Each type of command has a corresponding compiler function on the schema // grammar which is used to build the necessary SQL statements to build // the blueprint element, so we'll just call that compilers function. $this->ensureCommandsAreValid($connection); foreach ($this->commands as $command) { $method = 'compile'.ucfirst($command->name); if (method_exists($grammar, $method) || $grammar::hasMacro($method)) { if (! is_null($sql = $grammar->$method($this, $command, $connection))) { $statements = array_merge($statements, (array) $sql); } } } return $statements; } /** * Ensure the commands on the blueprint are valid for the connection type. * * @param \Illuminate\Database\Connection $connection * @return void * * @throws \BadMethodCallException */ protected function ensureCommandsAreValid(Connection $connection) { if ($connection instanceof SQLiteConnection) { if ($this->commandsNamed(['dropColumn', 'renameColumn'])->count() > 1) { throw new BadMethodCallException( "SQLite doesn't support multiple calls to dropColumn / renameColumn in a single modification." ); } if ($this->commandsNamed(['dropForeign'])->count() > 0) { throw new BadMethodCallException( "SQLite doesn't support dropping foreign keys (you would need to re-create the table)." ); } } } /** * Get all of the commands matching the given names. * * @param array $names * @return \Illuminate\Support\Collection */ protected function commandsNamed(array $names) { return collect($this->commands)->filter(function ($command) use ($names) { return in_array($command->name, $names); }); } /** * Add the commands that are implied by the blueprint's state. * * @param \Illuminate\Database\Schema\Grammars\Grammar $grammar * @return void */ protected function addImpliedCommands(Grammar $grammar) { if (count($this->getAddedColumns()) > 0 && ! $this->creating()) { array_unshift($this->commands, $this->createCommand('add')); } if (count($this->getChangedColumns()) > 0 && ! $this->creating()) { array_unshift($this->commands, $this->createCommand('change')); } $this->addFluentIndexes(); $this->addFluentCommands($grammar); } /** * Add the index commands fluently specified on columns. * * @return void */ protected function addFluentIndexes() { foreach ($this->columns as $column) { foreach (['primary', 'unique', 'index', 'spatialIndex'] as $index) { // If the index has been specified on the given column, but is simply equal // to "true" (boolean), no name has been specified for this index so the // index method can be called without a name and it will generate one. if ($column->{$index} === true) { $this->{$index}($column->name); $column->{$index} = false; continue 2; } // If the index has been specified on the given column, and it has a string // value, we'll go ahead and call the index method and pass the name for // the index since the developer specified the explicit name for this. elseif (isset($column->{$index})) { $this->{$index}($column->name, $column->{$index}); $column->{$index} = false; continue 2; } } } } /** * Add the fluent commands specified on any columns. * * @param \Illuminate\Database\Schema\Grammars\Grammar $grammar * @return void */ public function addFluentCommands(Grammar $grammar) { foreach ($this->columns as $column) { foreach ($grammar->getFluentCommands() as $commandName) { $attributeName = lcfirst($commandName); if (! isset($column->{$attributeName})) { continue; } $value = $column->{$attributeName}; $this->addCommand( $commandName, compact('value', 'column') ); } } } /** * Determine if the blueprint has a create command. * * @return bool */ protected function creating() { return collect($this->commands)->contains(function ($command) { return $command->name === 'create'; }); } /** * Indicate that the table needs to be created. * * @return \Illuminate\Support\Fluent */ public function create() { return $this->addCommand('create'); } /** * Indicate that the table needs to be temporary. * * @return void */ public function temporary() { $this->temporary = true; } /** * Indicate that the table should be dropped. * * @return \Illuminate\Support\Fluent */ public function drop() { return $this->addCommand('drop'); } /** * Indicate that the table should be dropped if it exists. * * @return \Illuminate\Support\Fluent */ public function dropIfExists() { return $this->addCommand('dropIfExists'); } /** * Indicate that the given columns should be dropped. * * @param array|mixed $columns * @return \Illuminate\Support\Fluent */ public function dropColumn($columns) { $columns = is_array($columns) ? $columns : func_get_args(); return $this->addCommand('dropColumn', compact('columns')); } /** * Indicate that the given columns should be renamed. * * @param string $from * @param string $to * @return \Illuminate\Support\Fluent */ public function renameColumn($from, $to) { return $this->addCommand('renameColumn', compact('from', 'to')); } /** * Indicate that the given primary key should be dropped. * * @param string|array|null $index * @return \Illuminate\Support\Fluent */ public function dropPrimary($index = null) { return $this->dropIndexCommand('dropPrimary', 'primary', $index); } /** * Indicate that the given unique key should be dropped. * * @param string|array $index * @return \Illuminate\Support\Fluent */ public function dropUnique($index) { return $this->dropIndexCommand('dropUnique', 'unique', $index); } /** * Indicate that the given index should be dropped. * * @param string|array $index * @return \Illuminate\Support\Fluent */ public function dropIndex($index) { return $this->dropIndexCommand('dropIndex', 'index', $index); } /** * Indicate that the given spatial index should be dropped. * * @param string|array $index * @return \Illuminate\Support\Fluent */ public function dropSpatialIndex($index) { return $this->dropIndexCommand('dropSpatialIndex', 'spatialIndex', $index); } /** * Indicate that the given foreign key should be dropped. * * @param string|array $index * @return \Illuminate\Support\Fluent */ public function dropForeign($index) { return $this->dropIndexCommand('dropForeign', 'foreign', $index); } /** * Indicate that the given indexes should be renamed. * * @param string $from * @param string $to * @return \Illuminate\Support\Fluent */ public function renameIndex($from, $to) { return $this->addCommand('renameIndex', compact('from', 'to')); } /** * Indicate that the timestamp columns should be dropped. * * @return void */ public function dropTimestamps() { $this->dropColumn('created_at', 'updated_at'); } /** * Indicate that the timestamp columns should be dropped. * * @return void */ public function dropTimestampsTz() { $this->dropTimestamps(); } /** * Indicate that the soft delete column should be dropped. * * @param string $column * @return void */ public function dropSoftDeletes($column = 'deleted_at') { $this->dropColumn($column); } /** * Indicate that the soft delete column should be dropped. * * @param string $column * @return void */ public function dropSoftDeletesTz($column = 'deleted_at') { $this->dropSoftDeletes($column); } /** * Indicate that the remember token column should be dropped. * * @return void */ public function dropRememberToken() { $this->dropColumn('remember_token'); } /** * Indicate that the polymorphic columns should be dropped. * * @param string $name * @param string|null $indexName * @return void */ public function dropMorphs($name, $indexName = null) { $this->dropIndex($indexName ?: $this->createIndexName('index', ["{$name}_type", "{$name}_id"])); $this->dropColumn("{$name}_type", "{$name}_id"); } /** * Rename the table to a given name. * * @param string $to * @return \Illuminate\Support\Fluent */ public function rename($to) { return $this->addCommand('rename', compact('to')); } /** * Specify the primary key(s) for the table. * * @param string|array $columns * @param string|null $name * @param string|null $algorithm * @return \Illuminate\Support\Fluent */ public function primary($columns, $name = null, $algorithm = null) { return $this->indexCommand('primary', $columns, $name, $algorithm); } /** * Specify a unique index for the table. * * @param string|array $columns * @param string|null $name * @param string|null $algorithm * @return \Illuminate\Support\Fluent */ public function unique($columns, $name = null, $algorithm = null) { return $this->indexCommand('unique', $columns, $name, $algorithm); } /** * Specify an index for the table. * * @param string|array $columns * @param string|null $name * @param string|null $algorithm * @return \Illuminate\Support\Fluent */ public function index($columns, $name = null, $algorithm = null) { return $this->indexCommand('index', $columns, $name, $algorithm); } /** * Specify a spatial index for the table. * * @param string|array $columns * @param string|null $name * @return \Illuminate\Support\Fluent */ public function spatialIndex($columns, $name = null) { return $this->indexCommand('spatialIndex', $columns, $name); } /** * Specify a raw index for the table. * * @param string $expression * @param string $name * @return \Illuminate\Support\Fluent */ public function rawIndex($expression, $name) { return $this->index([new Expression($expression)], $name); } /** * Specify a foreign key for the table. * * @param string|array $columns * @param string|null $name * @return \Illuminate\Database\Schema\ForeignKeyDefinition */ public function foreign($columns, $name = null) { $command = new ForeignKeyDefinition( $this->indexCommand('foreign', $columns, $name)->getAttributes() ); $this->commands[count($this->commands) - 1] = $command; return $command; } /** * Create a new auto-incrementing big integer (8-byte) column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function id($column = 'id') { return $this->bigIncrements($column); } /** * Create a new auto-incrementing integer (4-byte) column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function increments($column) { return $this->unsignedInteger($column, true); } /** * Create a new auto-incrementing integer (4-byte) column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function integerIncrements($column) { return $this->unsignedInteger($column, true); } /** * Create a new auto-incrementing tiny integer (1-byte) column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function tinyIncrements($column) { return $this->unsignedTinyInteger($column, true); } /** * Create a new auto-incrementing small integer (2-byte) column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function smallIncrements($column) { return $this->unsignedSmallInteger($column, true); } /** * Create a new auto-incrementing medium integer (3-byte) column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function mediumIncrements($column) { return $this->unsignedMediumInteger($column, true); } /** * Create a new auto-incrementing big integer (8-byte) column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function bigIncrements($column) { return $this->unsignedBigInteger($column, true); } /** * Create a new char column on the table. * * @param string $column * @param int|null $length * @return \Illuminate\Database\Schema\ColumnDefinition */ public function char($column, $length = null) { $length = $length ?: Builder::$defaultStringLength; return $this->addColumn('char', $column, compact('length')); } /** * Create a new string column on the table. * * @param string $column * @param int|null $length * @return \Illuminate\Database\Schema\ColumnDefinition */ public function string($column, $length = null) { $length = $length ?: Builder::$defaultStringLength; return $this->addColumn('string', $column, compact('length')); } /** * Create a new text column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function text($column) { return $this->addColumn('text', $column); } /** * Create a new medium text column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function mediumText($column) { return $this->addColumn('mediumText', $column); } /** * Create a new long text column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function longText($column) { return $this->addColumn('longText', $column); } /** * Create a new integer (4-byte) column on the table. * * @param string $column * @param bool $autoIncrement * @param bool $unsigned * @return \Illuminate\Database\Schema\ColumnDefinition */ public function integer($column, $autoIncrement = false, $unsigned = false) { return $this->addColumn('integer', $column, compact('autoIncrement', 'unsigned')); } /** * Create a new tiny integer (1-byte) column on the table. * * @param string $column * @param bool $autoIncrement * @param bool $unsigned * @return \Illuminate\Database\Schema\ColumnDefinition */ public function tinyInteger($column, $autoIncrement = false, $unsigned = false) { return $this->addColumn('tinyInteger', $column, compact('autoIncrement', 'unsigned')); } /** * Create a new small integer (2-byte) column on the table. * * @param string $column * @param bool $autoIncrement * @param bool $unsigned * @return \Illuminate\Database\Schema\ColumnDefinition */ public function smallInteger($column, $autoIncrement = false, $unsigned = false) { return $this->addColumn('smallInteger', $column, compact('autoIncrement', 'unsigned')); } /** * Create a new medium integer (3-byte) column on the table. * * @param string $column * @param bool $autoIncrement * @param bool $unsigned * @return \Illuminate\Database\Schema\ColumnDefinition */ public function mediumInteger($column, $autoIncrement = false, $unsigned = false) { return $this->addColumn('mediumInteger', $column, compact('autoIncrement', 'unsigned')); } /** * Create a new big integer (8-byte) column on the table. * * @param string $column * @param bool $autoIncrement * @param bool $unsigned * @return \Illuminate\Database\Schema\ColumnDefinition */ public function bigInteger($column, $autoIncrement = false, $unsigned = false) { return $this->addColumn('bigInteger', $column, compact('autoIncrement', 'unsigned')); } /** * Create a new unsigned integer (4-byte) column on the table. * * @param string $column * @param bool $autoIncrement * @return \Illuminate\Database\Schema\ColumnDefinition */ public function unsignedInteger($column, $autoIncrement = false) { return $this->integer($column, $autoIncrement, true); } /** * Create a new unsigned tiny integer (1-byte) column on the table. * * @param string $column * @param bool $autoIncrement * @return \Illuminate\Database\Schema\ColumnDefinition */ public function unsignedTinyInteger($column, $autoIncrement = false) { return $this->tinyInteger($column, $autoIncrement, true); } /** * Create a new unsigned small integer (2-byte) column on the table. * * @param string $column * @param bool $autoIncrement * @return \Illuminate\Database\Schema\ColumnDefinition */ public function unsignedSmallInteger($column, $autoIncrement = false) { return $this->smallInteger($column, $autoIncrement, true); } /** * Create a new unsigned medium integer (3-byte) column on the table. * * @param string $column * @param bool $autoIncrement * @return \Illuminate\Database\Schema\ColumnDefinition */ public function unsignedMediumInteger($column, $autoIncrement = false) { return $this->mediumInteger($column, $autoIncrement, true); } /** * Create a new unsigned big integer (8-byte) column on the table. * * @param string $column * @param bool $autoIncrement * @return \Illuminate\Database\Schema\ColumnDefinition */ public function unsignedBigInteger($column, $autoIncrement = false) { return $this->bigInteger($column, $autoIncrement, true); } /** * Create a new unsigned big integer (8-byte) column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ForeignIdColumnDefinition */ public function foreignId($column) { $this->columns[] = $column = new ForeignIdColumnDefinition($this, [ 'type' => 'bigInteger', 'name' => $column, 'autoIncrement' => false, 'unsigned' => true, ]); return $column; } /** * Create a new float column on the table. * * @param string $column * @param int $total * @param int $places * @param bool $unsigned * @return \Illuminate\Database\Schema\ColumnDefinition */ public function float($column, $total = 8, $places = 2, $unsigned = false) { return $this->addColumn('float', $column, compact('total', 'places', 'unsigned')); } /** * Create a new double column on the table. * * @param string $column * @param int|null $total * @param int|null $places * @param bool $unsigned * @return \Illuminate\Database\Schema\ColumnDefinition */ public function double($column, $total = null, $places = null, $unsigned = false) { return $this->addColumn('double', $column, compact('total', 'places', 'unsigned')); } /** * Create a new decimal column on the table. * * @param string $column * @param int $total * @param int $places * @param bool $unsigned * @return \Illuminate\Database\Schema\ColumnDefinition */ public function decimal($column, $total = 8, $places = 2, $unsigned = false) { return $this->addColumn('decimal', $column, compact('total', 'places', 'unsigned')); } /** * Create a new unsigned float column on the table. * * @param string $column * @param int $total * @param int $places * @return \Illuminate\Database\Schema\ColumnDefinition */ public function unsignedFloat($column, $total = 8, $places = 2) { return $this->float($column, $total, $places, true); } /** * Create a new unsigned double column on the table. * * @param string $column * @param int $total * @param int $places * @return \Illuminate\Database\Schema\ColumnDefinition */ public function unsignedDouble($column, $total = null, $places = null) { return $this->double($column, $total, $places, true); } /** * Create a new unsigned decimal column on the table. * * @param string $column * @param int $total * @param int $places * @return \Illuminate\Database\Schema\ColumnDefinition */ public function unsignedDecimal($column, $total = 8, $places = 2) { return $this->decimal($column, $total, $places, true); } /** * Create a new boolean column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function boolean($column) { return $this->addColumn('boolean', $column); } /** * Create a new enum column on the table. * * @param string $column * @param array $allowed * @return \Illuminate\Database\Schema\ColumnDefinition */ public function enum($column, array $allowed) { return $this->addColumn('enum', $column, compact('allowed')); } /** * Create a new set column on the table. * * @param string $column * @param array $allowed * @return \Illuminate\Database\Schema\ColumnDefinition */ public function set($column, array $allowed) { return $this->addColumn('set', $column, compact('allowed')); } /** * Create a new json column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function json($column) { return $this->addColumn('json', $column); } /** * Create a new jsonb column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function jsonb($column) { return $this->addColumn('jsonb', $column); } /** * Create a new date column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function date($column) { return $this->addColumn('date', $column); } /** * Create a new date-time column on the table. * * @param string $column * @param int $precision * @return \Illuminate\Database\Schema\ColumnDefinition */ public function dateTime($column, $precision = 0) { return $this->addColumn('dateTime', $column, compact('precision')); } /** * Create a new date-time column (with time zone) on the table. * * @param string $column * @param int $precision * @return \Illuminate\Database\Schema\ColumnDefinition */ public function dateTimeTz($column, $precision = 0) { return $this->addColumn('dateTimeTz', $column, compact('precision')); } /** * Create a new time column on the table. * * @param string $column * @param int $precision * @return \Illuminate\Database\Schema\ColumnDefinition */ public function time($column, $precision = 0) { return $this->addColumn('time', $column, compact('precision')); } /** * Create a new time column (with time zone) on the table. * * @param string $column * @param int $precision * @return \Illuminate\Database\Schema\ColumnDefinition */ public function timeTz($column, $precision = 0) { return $this->addColumn('timeTz', $column, compact('precision')); } /** * Create a new timestamp column on the table. * * @param string $column * @param int $precision * @return \Illuminate\Database\Schema\ColumnDefinition */ public function timestamp($column, $precision = 0) { return $this->addColumn('timestamp', $column, compact('precision')); } /** * Create a new timestamp (with time zone) column on the table. * * @param string $column * @param int $precision * @return \Illuminate\Database\Schema\ColumnDefinition */ public function timestampTz($column, $precision = 0) { return $this->addColumn('timestampTz', $column, compact('precision')); } /** * Add nullable creation and update timestamps to the table. * * @param int $precision * @return void */ public function timestamps($precision = 0) { $this->timestamp('created_at', $precision)->nullable(); $this->timestamp('updated_at', $precision)->nullable(); } /** * Add nullable creation and update timestamps to the table. * * Alias for self::timestamps(). * * @param int $precision * @return void */ public function nullableTimestamps($precision = 0) { $this->timestamps($precision); } /** * Add creation and update timestampTz columns to the table. * * @param int $precision * @return void */ public function timestampsTz($precision = 0) { $this->timestampTz('created_at', $precision)->nullable(); $this->timestampTz('updated_at', $precision)->nullable(); } /** * Add a "deleted at" timestamp for the table. * * @param string $column * @param int $precision * @return \Illuminate\Database\Schema\ColumnDefinition */ public function softDeletes($column = 'deleted_at', $precision = 0) { return $this->timestamp($column, $precision)->nullable(); } /** * Add a "deleted at" timestampTz for the table. * * @param string $column * @param int $precision * @return \Illuminate\Database\Schema\ColumnDefinition */ public function softDeletesTz($column = 'deleted_at', $precision = 0) { return $this->timestampTz($column, $precision)->nullable(); } /** * Create a new year column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function year($column) { return $this->addColumn('year', $column); } /** * Create a new binary column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function binary($column) { return $this->addColumn('binary', $column); } /** * Create a new uuid column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function uuid($column) { return $this->addColumn('uuid', $column); } /** * Create a new IP address column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function ipAddress($column) { return $this->addColumn('ipAddress', $column); } /** * Create a new MAC address column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function macAddress($column) { return $this->addColumn('macAddress', $column); } /** * Create a new geometry column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function geometry($column) { return $this->addColumn('geometry', $column); } /** * Create a new point column on the table. * * @param string $column * @param int|null $srid * @return \Illuminate\Database\Schema\ColumnDefinition */ public function point($column, $srid = null) { return $this->addColumn('point', $column, compact('srid')); } /** * Create a new linestring column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function lineString($column) { return $this->addColumn('linestring', $column); } /** * Create a new polygon column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function polygon($column) { return $this->addColumn('polygon', $column); } /** * Create a new geometrycollection column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function geometryCollection($column) { return $this->addColumn('geometrycollection', $column); } /** * Create a new multipoint column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function multiPoint($column) { return $this->addColumn('multipoint', $column); } /** * Create a new multilinestring column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function multiLineString($column) { return $this->addColumn('multilinestring', $column); } /** * Create a new multipolygon column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function multiPolygon($column) { return $this->addColumn('multipolygon', $column); } /** * Create a new multipolygon column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function multiPolygonZ($column) { return $this->addColumn('multipolygonz', $column); } /** * Create a new generated, computed column on the table. * * @param string $column * @param string $expression * @return \Illuminate\Database\Schema\ColumnDefinition */ public function computed($column, $expression) { return $this->addColumn('computed', $column, compact('expression')); } /** * Add the proper columns for a polymorphic table. * * @param string $name * @param string|null $indexName * @return void */ public function morphs($name, $indexName = null) { $this->string("{$name}_type"); $this->unsignedBigInteger("{$name}_id"); $this->index(["{$name}_type", "{$name}_id"], $indexName); } /** * Add nullable columns for a polymorphic table. * * @param string $name * @param string|null $indexName * @return void */ public function nullableMorphs($name, $indexName = null) { $this->string("{$name}_type")->nullable(); $this->unsignedBigInteger("{$name}_id")->nullable(); $this->index(["{$name}_type", "{$name}_id"], $indexName); } /** * Add the proper columns for a polymorphic table using UUIDs. * * @param string $name * @param string|null $indexName * @return void */ public function uuidMorphs($name, $indexName = null) { $this->string("{$name}_type"); $this->uuid("{$name}_id"); $this->index(["{$name}_type", "{$name}_id"], $indexName); } /** * Add nullable columns for a polymorphic table using UUIDs. * * @param string $name * @param string|null $indexName * @return void */ public function nullableUuidMorphs($name, $indexName = null) { $this->string("{$name}_type")->nullable(); $this->uuid("{$name}_id")->nullable(); $this->index(["{$name}_type", "{$name}_id"], $indexName); } /** * Adds the `remember_token` column to the table. * * @return \Illuminate\Database\Schema\ColumnDefinition */ public function rememberToken() { return $this->string('remember_token', 100)->nullable(); } /** * Add a new index command to the blueprint. * * @param string $type * @param string|array $columns * @param string $index * @param string|null $algorithm * @return \Illuminate\Support\Fluent */ protected function indexCommand($type, $columns, $index, $algorithm = null) { $columns = (array) $columns; // If no name was specified for this index, we will create one using a basic // convention of the table name, followed by the columns, followed by an // index type, such as primary or index, which makes the index unique. $index = $index ?: $this->createIndexName($type, $columns); return $this->addCommand( $type, compact('index', 'columns', 'algorithm') ); } /** * Create a new drop index command on the blueprint. * * @param string $command * @param string $type * @param string|array $index * @return \Illuminate\Support\Fluent */ protected function dropIndexCommand($command, $type, $index) { $columns = []; // If the given "index" is actually an array of columns, the developer means // to drop an index merely by specifying the columns involved without the // conventional name, so we will build the index name from the columns. if (is_array($index)) { $index = $this->createIndexName($type, $columns = $index); } return $this->indexCommand($command, $columns, $index); } /** * Create a default index name for the table. * * @param string $type * @param array $columns * @return string */ protected function createIndexName($type, array $columns) { $index = strtolower($this->prefix.$this->table.'_'.implode('_', $columns).'_'.$type); return str_replace(['-', '.'], '_', $index); } /** * Add a new column to the blueprint. * * @param string $type * @param string $name * @param array $parameters * @return \Illuminate\Database\Schema\ColumnDefinition */ public function addColumn($type, $name, array $parameters = []) { $this->columns[] = $column = new ColumnDefinition( array_merge(compact('type', 'name'), $parameters) ); return $column; } /** * Remove a column from the schema blueprint. * * @param string $name * @return $this */ public function removeColumn($name) { $this->columns = array_values(array_filter($this->columns, function ($c) use ($name) { return $c['name'] != $name; })); return $this; } /** * Add a new command to the blueprint. * * @param string $name * @param array $parameters * @return \Illuminate\Support\Fluent */ protected function addCommand($name, array $parameters = []) { $this->commands[] = $command = $this->createCommand($name, $parameters); return $command; } /** * Create a new Fluent command. * * @param string $name * @param array $parameters * @return \Illuminate\Support\Fluent */ protected function createCommand($name, array $parameters = []) { return new Fluent(array_merge(compact('name'), $parameters)); } /** * Get the table the blueprint describes. * * @return string */ public function getTable() { return $this->table; } /** * Get the columns on the blueprint. * * @return \Illuminate\Database\Schema\ColumnDefinition[] */ public function getColumns() { return $this->columns; } /** * Get the commands on the blueprint. * * @return \Illuminate\Support\Fluent[] */ public function getCommands() { return $this->commands; } /** * Get the columns on the blueprint that should be added. * * @return \Illuminate\Database\Schema\ColumnDefinition[] */ public function getAddedColumns() { return array_filter($this->columns, function ($column) { return ! $column->change; }); } /** * Get the columns on the blueprint that should be changed. * * @return \Illuminate\Database\Schema\ColumnDefinition[] */ public function getChangedColumns() { return array_filter($this->columns, function ($column) { return (bool) $column->change; }); } } database/Schema/Grammars/Grammar.php 0000644 00000020610 14736103231 0013357 0 ustar 00 <?php namespace Illuminate\Database\Schema\Grammars; use Doctrine\DBAL\Schema\AbstractSchemaManager as SchemaManager; use Doctrine\DBAL\Schema\TableDiff; use Illuminate\Database\Connection; use Illuminate\Database\Grammar as BaseGrammar; use Illuminate\Database\Query\Expression; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Fluent; use RuntimeException; abstract class Grammar extends BaseGrammar { /** * If this Grammar supports schema changes wrapped in a transaction. * * @var bool */ protected $transactions = false; /** * The commands to be executed outside of create or alter command. * * @var array */ protected $fluentCommands = []; /** * Compile a rename column command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @param \Illuminate\Database\Connection $connection * @return array */ public function compileRenameColumn(Blueprint $blueprint, Fluent $command, Connection $connection) { return RenameColumn::compile($this, $blueprint, $command, $connection); } /** * Compile a change column command into a series of SQL statements. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @param \Illuminate\Database\Connection $connection * @return array * * @throws \RuntimeException */ public function compileChange(Blueprint $blueprint, Fluent $command, Connection $connection) { return ChangeColumn::compile($this, $blueprint, $command, $connection); } /** * Compile a foreign key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileForeign(Blueprint $blueprint, Fluent $command) { // We need to prepare several of the elements of the foreign key definition // before we can create the SQL, such as wrapping the tables and convert // an array of columns to comma-delimited strings for the SQL queries. $sql = sprintf('alter table %s add constraint %s ', $this->wrapTable($blueprint), $this->wrap($command->index) ); // Once we have the initial portion of the SQL statement we will add on the // key name, table name, and referenced columns. These will complete the // main portion of the SQL statement and this SQL will almost be done. $sql .= sprintf('foreign key (%s) references %s (%s)', $this->columnize($command->columns), $this->wrapTable($command->on), $this->columnize((array) $command->references) ); // Once we have the basic foreign key creation statement constructed we can // build out the syntax for what should happen on an update or delete of // the affected columns, which will get something like "cascade", etc. if (! is_null($command->onDelete)) { $sql .= " on delete {$command->onDelete}"; } if (! is_null($command->onUpdate)) { $sql .= " on update {$command->onUpdate}"; } return $sql; } /** * Compile the blueprint's column definitions. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @return array */ protected function getColumns(Blueprint $blueprint) { $columns = []; foreach ($blueprint->getAddedColumns() as $column) { // Each of the column types have their own compiler functions which are tasked // with turning the column definition into its SQL format for this platform // used by the connection. The column's modifiers are compiled and added. $sql = $this->wrap($column).' '.$this->getType($column); $columns[] = $this->addModifiers($sql, $blueprint, $column); } return $columns; } /** * Get the SQL for the column data type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function getType(Fluent $column) { return $this->{'type'.ucfirst($column->type)}($column); } /** * Create the column definition for a generated, computed column type. * * @param \Illuminate\Support\Fluent $column * @return void * * @throws \RuntimeException */ protected function typeComputed(Fluent $column) { throw new RuntimeException('This database driver does not support the computed type.'); } /** * Add the column modifiers to the definition. * * @param string $sql * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string */ protected function addModifiers($sql, Blueprint $blueprint, Fluent $column) { foreach ($this->modifiers as $modifier) { if (method_exists($this, $method = "modify{$modifier}")) { $sql .= $this->{$method}($blueprint, $column); } } return $sql; } /** * Get the primary key command if it exists on the blueprint. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param string $name * @return \Illuminate\Support\Fluent|null */ protected function getCommandByName(Blueprint $blueprint, $name) { $commands = $this->getCommandsByName($blueprint, $name); if (count($commands) > 0) { return reset($commands); } } /** * Get all of the commands with a given name. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param string $name * @return array */ protected function getCommandsByName(Blueprint $blueprint, $name) { return array_filter($blueprint->getCommands(), function ($value) use ($name) { return $value->name == $name; }); } /** * Add a prefix to an array of values. * * @param string $prefix * @param array $values * @return array */ public function prefixArray($prefix, array $values) { return array_map(function ($value) use ($prefix) { return $prefix.' '.$value; }, $values); } /** * Wrap a table in keyword identifiers. * * @param mixed $table * @return string */ public function wrapTable($table) { return parent::wrapTable( $table instanceof Blueprint ? $table->getTable() : $table ); } /** * Wrap a value in keyword identifiers. * * @param \Illuminate\Database\Query\Expression|string $value * @param bool $prefixAlias * @return string */ public function wrap($value, $prefixAlias = false) { return parent::wrap( $value instanceof Fluent ? $value->name : $value, $prefixAlias ); } /** * Format a value so that it can be used in "default" clauses. * * @param mixed $value * @return string */ protected function getDefaultValue($value) { if ($value instanceof Expression) { return $value; } return is_bool($value) ? "'".(int) $value."'" : "'".(string) $value."'"; } /** * Create an empty Doctrine DBAL TableDiff from the Blueprint. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Doctrine\DBAL\Schema\AbstractSchemaManager $schema * @return \Doctrine\DBAL\Schema\TableDiff */ public function getDoctrineTableDiff(Blueprint $blueprint, SchemaManager $schema) { $table = $this->getTablePrefix().$blueprint->getTable(); return tap(new TableDiff($table), function ($tableDiff) use ($schema, $table) { $tableDiff->fromTable = $schema->listTableDetails($table); }); } /** * Get the fluent commands for the grammar. * * @return array */ public function getFluentCommands() { return $this->fluentCommands; } /** * Check if this Grammar supports schema changes wrapped in a transaction. * * @return bool */ public function supportsSchemaTransactions() { return $this->transactions; } } database/Schema/Grammars/SQLiteGrammar.php 0000644 00000055066 14736103231 0014456 0 ustar 00 <?php namespace Illuminate\Database\Schema\Grammars; use Doctrine\DBAL\Schema\Index; use Illuminate\Database\Connection; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Arr; use Illuminate\Support\Fluent; use RuntimeException; class SQLiteGrammar extends Grammar { /** * The possible column modifiers. * * @var array */ protected $modifiers = ['Nullable', 'Default', 'Increment']; /** * The columns available as serials. * * @var array */ protected $serials = ['bigInteger', 'integer', 'mediumInteger', 'smallInteger', 'tinyInteger']; /** * Compile the query to determine if a table exists. * * @return string */ public function compileTableExists() { return "select * from sqlite_master where type = 'table' and name = ?"; } /** * Compile the query to determine the list of columns. * * @param string $table * @return string */ public function compileColumnListing($table) { return 'pragma table_info('.$this->wrap(str_replace('.', '__', $table)).')'; } /** * Compile a create table command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileCreate(Blueprint $blueprint, Fluent $command) { return sprintf('%s table %s (%s%s%s)', $blueprint->temporary ? 'create temporary' : 'create', $this->wrapTable($blueprint), implode(', ', $this->getColumns($blueprint)), (string) $this->addForeignKeys($blueprint), (string) $this->addPrimaryKeys($blueprint) ); } /** * Get the foreign key syntax for a table creation statement. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @return string|null */ protected function addForeignKeys(Blueprint $blueprint) { $foreigns = $this->getCommandsByName($blueprint, 'foreign'); return collect($foreigns)->reduce(function ($sql, $foreign) { // Once we have all the foreign key commands for the table creation statement // we'll loop through each of them and add them to the create table SQL we // are building, since SQLite needs foreign keys on the tables creation. $sql .= $this->getForeignKey($foreign); if (! is_null($foreign->onDelete)) { $sql .= " on delete {$foreign->onDelete}"; } // If this foreign key specifies the action to be taken on update we will add // that to the statement here. We'll append it to this SQL and then return // the SQL so we can keep adding any other foreign constraints onto this. if (! is_null($foreign->onUpdate)) { $sql .= " on update {$foreign->onUpdate}"; } return $sql; }, ''); } /** * Get the SQL for the foreign key. * * @param \Illuminate\Support\Fluent $foreign * @return string */ protected function getForeignKey($foreign) { // We need to columnize the columns that the foreign key is being defined for // so that it is a properly formatted list. Once we have done this, we can // return the foreign key SQL declaration to the calling method for use. return sprintf(', foreign key(%s) references %s(%s)', $this->columnize($foreign->columns), $this->wrapTable($foreign->on), $this->columnize((array) $foreign->references) ); } /** * Get the primary key syntax for a table creation statement. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @return string|null */ protected function addPrimaryKeys(Blueprint $blueprint) { if (! is_null($primary = $this->getCommandByName($blueprint, 'primary'))) { return ", primary key ({$this->columnize($primary->columns)})"; } } /** * Compile alter table commands for adding columns. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return array */ public function compileAdd(Blueprint $blueprint, Fluent $command) { $columns = $this->prefixArray('add column', $this->getColumns($blueprint)); return collect($columns)->map(function ($column) use ($blueprint) { return 'alter table '.$this->wrapTable($blueprint).' '.$column; })->all(); } /** * Compile a unique key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileUnique(Blueprint $blueprint, Fluent $command) { return sprintf('create unique index %s on %s (%s)', $this->wrap($command->index), $this->wrapTable($blueprint), $this->columnize($command->columns) ); } /** * Compile a plain index key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileIndex(Blueprint $blueprint, Fluent $command) { return sprintf('create index %s on %s (%s)', $this->wrap($command->index), $this->wrapTable($blueprint), $this->columnize($command->columns) ); } /** * Compile a spatial index key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return void * * @throws \RuntimeException */ public function compileSpatialIndex(Blueprint $blueprint, Fluent $command) { throw new RuntimeException('The database driver in use does not support spatial indexes.'); } /** * Compile a foreign key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileForeign(Blueprint $blueprint, Fluent $command) { // Handled on table creation... } /** * Compile a drop table command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDrop(Blueprint $blueprint, Fluent $command) { return 'drop table '.$this->wrapTable($blueprint); } /** * Compile a drop table (if exists) command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropIfExists(Blueprint $blueprint, Fluent $command) { return 'drop table if exists '.$this->wrapTable($blueprint); } /** * Compile the SQL needed to drop all tables. * * @return string */ public function compileDropAllTables() { return "delete from sqlite_master where type in ('table', 'index', 'trigger')"; } /** * Compile the SQL needed to drop all views. * * @return string */ public function compileDropAllViews() { return "delete from sqlite_master where type in ('view')"; } /** * Compile the SQL needed to rebuild the database. * * @return string */ public function compileRebuild() { return 'vacuum'; } /** * Compile a drop column command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @param \Illuminate\Database\Connection $connection * @return array */ public function compileDropColumn(Blueprint $blueprint, Fluent $command, Connection $connection) { $tableDiff = $this->getDoctrineTableDiff( $blueprint, $schema = $connection->getDoctrineSchemaManager() ); foreach ($command->columns as $name) { $tableDiff->removedColumns[$name] = $connection->getDoctrineColumn( $this->getTablePrefix().$blueprint->getTable(), $name ); } return (array) $schema->getDatabasePlatform()->getAlterTableSQL($tableDiff); } /** * Compile a drop unique key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropUnique(Blueprint $blueprint, Fluent $command) { $index = $this->wrap($command->index); return "drop index {$index}"; } /** * Compile a drop index command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropIndex(Blueprint $blueprint, Fluent $command) { $index = $this->wrap($command->index); return "drop index {$index}"; } /** * Compile a drop spatial index command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return void * * @throws \RuntimeException */ public function compileDropSpatialIndex(Blueprint $blueprint, Fluent $command) { throw new RuntimeException('The database driver in use does not support spatial indexes.'); } /** * Compile a rename table command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileRename(Blueprint $blueprint, Fluent $command) { $from = $this->wrapTable($blueprint); return "alter table {$from} rename to ".$this->wrapTable($command->to); } /** * Compile a rename index command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @param \Illuminate\Database\Connection $connection * @return array * * @throws \RuntimeException */ public function compileRenameIndex(Blueprint $blueprint, Fluent $command, Connection $connection) { $schemaManager = $connection->getDoctrineSchemaManager(); $indexes = $schemaManager->listTableIndexes($this->getTablePrefix().$blueprint->getTable()); $index = Arr::get($indexes, $command->from); if (! $index) { throw new RuntimeException("Index [{$command->from}] does not exist."); } $newIndex = new Index( $command->to, $index->getColumns(), $index->isUnique(), $index->isPrimary(), $index->getFlags(), $index->getOptions() ); $platform = $schemaManager->getDatabasePlatform(); return [ $platform->getDropIndexSQL($command->from, $this->getTablePrefix().$blueprint->getTable()), $platform->getCreateIndexSQL($newIndex, $this->getTablePrefix().$blueprint->getTable()), ]; } /** * Compile the command to enable foreign key constraints. * * @return string */ public function compileEnableForeignKeyConstraints() { return 'PRAGMA foreign_keys = ON;'; } /** * Compile the command to disable foreign key constraints. * * @return string */ public function compileDisableForeignKeyConstraints() { return 'PRAGMA foreign_keys = OFF;'; } /** * Compile the SQL needed to enable a writable schema. * * @return string */ public function compileEnableWriteableSchema() { return 'PRAGMA writable_schema = 1;'; } /** * Compile the SQL needed to disable a writable schema. * * @return string */ public function compileDisableWriteableSchema() { return 'PRAGMA writable_schema = 0;'; } /** * Create the column definition for a char type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeChar(Fluent $column) { return 'varchar'; } /** * Create the column definition for a string type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeString(Fluent $column) { return 'varchar'; } /** * Create the column definition for a text type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeText(Fluent $column) { return 'text'; } /** * Create the column definition for a medium text type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeMediumText(Fluent $column) { return 'text'; } /** * Create the column definition for a long text type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeLongText(Fluent $column) { return 'text'; } /** * Create the column definition for a integer type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeInteger(Fluent $column) { return 'integer'; } /** * Create the column definition for a big integer type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeBigInteger(Fluent $column) { return 'integer'; } /** * Create the column definition for a medium integer type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeMediumInteger(Fluent $column) { return 'integer'; } /** * Create the column definition for a tiny integer type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeTinyInteger(Fluent $column) { return 'integer'; } /** * Create the column definition for a small integer type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeSmallInteger(Fluent $column) { return 'integer'; } /** * Create the column definition for a float type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeFloat(Fluent $column) { return 'float'; } /** * Create the column definition for a double type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeDouble(Fluent $column) { return 'float'; } /** * Create the column definition for a decimal type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeDecimal(Fluent $column) { return 'numeric'; } /** * Create the column definition for a boolean type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeBoolean(Fluent $column) { return 'tinyint(1)'; } /** * Create the column definition for an enumeration type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeEnum(Fluent $column) { return sprintf( 'varchar check ("%s" in (%s))', $column->name, $this->quoteString($column->allowed) ); } /** * Create the column definition for a json type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeJson(Fluent $column) { return 'text'; } /** * Create the column definition for a jsonb type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeJsonb(Fluent $column) { return 'text'; } /** * Create the column definition for a date type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeDate(Fluent $column) { return 'date'; } /** * Create the column definition for a date-time type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeDateTime(Fluent $column) { return $this->typeTimestamp($column); } /** * Create the column definition for a date-time (with time zone) type. * * Note: "SQLite does not have a storage class set aside for storing dates and/or times." * @link https://www.sqlite.org/datatype3.html * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeDateTimeTz(Fluent $column) { return $this->typeDateTime($column); } /** * Create the column definition for a time type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeTime(Fluent $column) { return 'time'; } /** * Create the column definition for a time (with time zone) type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeTimeTz(Fluent $column) { return $this->typeTime($column); } /** * Create the column definition for a timestamp type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeTimestamp(Fluent $column) { return $column->useCurrent ? 'datetime default CURRENT_TIMESTAMP' : 'datetime'; } /** * Create the column definition for a timestamp (with time zone) type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeTimestampTz(Fluent $column) { return $this->typeTimestamp($column); } /** * Create the column definition for a year type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeYear(Fluent $column) { return $this->typeInteger($column); } /** * Create the column definition for a binary type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeBinary(Fluent $column) { return 'blob'; } /** * Create the column definition for a uuid type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeUuid(Fluent $column) { return 'varchar'; } /** * Create the column definition for an IP address type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeIpAddress(Fluent $column) { return 'varchar'; } /** * Create the column definition for a MAC address type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeMacAddress(Fluent $column) { return 'varchar'; } /** * Create the column definition for a spatial Geometry type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typeGeometry(Fluent $column) { return 'geometry'; } /** * Create the column definition for a spatial Point type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typePoint(Fluent $column) { return 'point'; } /** * Create the column definition for a spatial LineString type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typeLineString(Fluent $column) { return 'linestring'; } /** * Create the column definition for a spatial Polygon type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typePolygon(Fluent $column) { return 'polygon'; } /** * Create the column definition for a spatial GeometryCollection type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typeGeometryCollection(Fluent $column) { return 'geometrycollection'; } /** * Create the column definition for a spatial MultiPoint type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typeMultiPoint(Fluent $column) { return 'multipoint'; } /** * Create the column definition for a spatial MultiLineString type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typeMultiLineString(Fluent $column) { return 'multilinestring'; } /** * Create the column definition for a spatial MultiPolygon type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typeMultiPolygon(Fluent $column) { return 'multipolygon'; } /** * Get the SQL for a nullable column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyNullable(Blueprint $blueprint, Fluent $column) { return $column->nullable ? ' null' : ' not null'; } /** * Get the SQL for a default column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyDefault(Blueprint $blueprint, Fluent $column) { if (! is_null($column->default)) { return ' default '.$this->getDefaultValue($column->default); } } /** * Get the SQL for an auto-increment column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyIncrement(Blueprint $blueprint, Fluent $column) { if (in_array($column->type, $this->serials) && $column->autoIncrement) { return ' primary key autoincrement'; } } } database/Schema/Grammars/ChangeColumn.php 0000644 00000016577 14736103231 0014355 0 ustar 00 <?php namespace Illuminate\Database\Schema\Grammars; use Doctrine\DBAL\Schema\AbstractSchemaManager as SchemaManager; use Doctrine\DBAL\Schema\Comparator; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Types\Type; use Illuminate\Database\Connection; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Fluent; use RuntimeException; class ChangeColumn { /** * Compile a change column command into a series of SQL statements. * * @param \Illuminate\Database\Schema\Grammars\Grammar $grammar * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @param \Illuminate\Database\Connection $connection * @return array * * @throws \RuntimeException */ public static function compile($grammar, Blueprint $blueprint, Fluent $command, Connection $connection) { if (! $connection->isDoctrineAvailable()) { throw new RuntimeException(sprintf( 'Changing columns for table "%s" requires Doctrine DBAL; install "doctrine/dbal".', $blueprint->getTable() )); } $schema = $connection->getDoctrineSchemaManager(); $databasePlatform = $schema->getDatabasePlatform(); $databasePlatform->registerDoctrineTypeMapping('enum', 'string'); $tableDiff = static::getChangedDiff( $grammar, $blueprint, $schema ); if ($tableDiff !== false) { return (array) $databasePlatform->getAlterTableSQL($tableDiff); } return []; } /** * Get the Doctrine table difference for the given changes. * * @param \Illuminate\Database\Schema\Grammars\Grammar $grammar * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Doctrine\DBAL\Schema\AbstractSchemaManager $schema * @return \Doctrine\DBAL\Schema\TableDiff|bool */ protected static function getChangedDiff($grammar, Blueprint $blueprint, SchemaManager $schema) { $current = $schema->listTableDetails($grammar->getTablePrefix().$blueprint->getTable()); return (new Comparator)->diffTable( $current, static::getTableWithColumnChanges($blueprint, $current) ); } /** * Get a copy of the given Doctrine table after making the column changes. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Doctrine\DBAL\Schema\Table $table * @return \Doctrine\DBAL\Schema\Table */ protected static function getTableWithColumnChanges(Blueprint $blueprint, Table $table) { $table = clone $table; foreach ($blueprint->getChangedColumns() as $fluent) { $column = static::getDoctrineColumn($table, $fluent); // Here we will spin through each fluent column definition and map it to the proper // Doctrine column definitions - which is necessary because Laravel and Doctrine // use some different terminology for various column attributes on the tables. foreach ($fluent->getAttributes() as $key => $value) { if (! is_null($option = static::mapFluentOptionToDoctrine($key))) { if (method_exists($column, $method = 'set'.ucfirst($option))) { $column->{$method}(static::mapFluentValueToDoctrine($option, $value)); continue; } $column->setCustomSchemaOption($option, static::mapFluentValueToDoctrine($option, $value)); } } } return $table; } /** * Get the Doctrine column instance for a column change. * * @param \Doctrine\DBAL\Schema\Table $table * @param \Illuminate\Support\Fluent $fluent * @return \Doctrine\DBAL\Schema\Column */ protected static function getDoctrineColumn(Table $table, Fluent $fluent) { return $table->changeColumn( $fluent['name'], static::getDoctrineColumnChangeOptions($fluent) )->getColumn($fluent['name']); } /** * Get the Doctrine column change options. * * @param \Illuminate\Support\Fluent $fluent * @return array */ protected static function getDoctrineColumnChangeOptions(Fluent $fluent) { $options = ['type' => static::getDoctrineColumnType($fluent['type'])]; if (in_array($fluent['type'], ['text', 'mediumText', 'longText'])) { $options['length'] = static::calculateDoctrineTextLength($fluent['type']); } if (static::doesntNeedCharacterOptions($fluent['type'])) { $options['customSchemaOptions'] = [ 'collation' => '', 'charset' => '', ]; } return $options; } /** * Get the doctrine column type. * * @param string $type * @return \Doctrine\DBAL\Types\Type */ protected static function getDoctrineColumnType($type) { $type = strtolower($type); switch ($type) { case 'biginteger': $type = 'bigint'; break; case 'smallinteger': $type = 'smallint'; break; case 'mediumtext': case 'longtext': $type = 'text'; break; case 'binary': $type = 'blob'; break; case 'uuid': $type = 'guid'; break; } return Type::getType($type); } /** * Calculate the proper column length to force the Doctrine text type. * * @param string $type * @return int */ protected static function calculateDoctrineTextLength($type) { switch ($type) { case 'mediumText': return 65535 + 1; case 'longText': return 16777215 + 1; default: return 255 + 1; } } /** * Determine if the given type does not need character / collation options. * * @param string $type * @return bool */ protected static function doesntNeedCharacterOptions($type) { return in_array($type, [ 'bigInteger', 'binary', 'boolean', 'date', 'decimal', 'double', 'float', 'integer', 'json', 'mediumInteger', 'smallInteger', 'time', 'tinyInteger', ]); } /** * Get the matching Doctrine option for a given Fluent attribute name. * * @param string $attribute * @return string|null */ protected static function mapFluentOptionToDoctrine($attribute) { switch ($attribute) { case 'type': case 'name': return; case 'nullable': return 'notnull'; case 'total': return 'precision'; case 'places': return 'scale'; default: return $attribute; } } /** * Get the matching Doctrine value for a given Fluent attribute. * * @param string $option * @param mixed $value * @return mixed */ protected static function mapFluentValueToDoctrine($option, $value) { return $option === 'notnull' ? ! $value : $value; } } database/Schema/Grammars/PostgresGrammar.php 0000644 00000064275 14736103231 0015125 0 ustar 00 <?php namespace Illuminate\Database\Schema\Grammars; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Fluent; class PostgresGrammar extends Grammar { /** * If this Grammar supports schema changes wrapped in a transaction. * * @var bool */ protected $transactions = true; /** * The possible column modifiers. * * @var array */ protected $modifiers = ['Collate', 'Increment', 'Nullable', 'Default', 'VirtualAs', 'StoredAs']; /** * The columns available as serials. * * @var array */ protected $serials = ['bigInteger', 'integer', 'mediumInteger', 'smallInteger', 'tinyInteger']; /** * The commands to be executed outside of create or alter command. * * @var array */ protected $fluentCommands = ['Comment']; /** * Compile the query to determine if a table exists. * * @return string */ public function compileTableExists() { return "select * from information_schema.tables where table_schema = ? and table_name = ? and table_type = 'BASE TABLE'"; } /** * Compile the query to determine the list of columns. * * @return string */ public function compileColumnListing() { return 'select column_name from information_schema.columns where table_schema = ? and table_name = ?'; } /** * Compile a create table command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileCreate(Blueprint $blueprint, Fluent $command) { return sprintf('%s table %s (%s)', $blueprint->temporary ? 'create temporary' : 'create', $this->wrapTable($blueprint), implode(', ', $this->getColumns($blueprint)) ); } /** * Compile a column addition command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileAdd(Blueprint $blueprint, Fluent $command) { return sprintf('alter table %s %s', $this->wrapTable($blueprint), implode(', ', $this->prefixArray('add column', $this->getColumns($blueprint))) ); } /** * Compile a primary key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compilePrimary(Blueprint $blueprint, Fluent $command) { $columns = $this->columnize($command->columns); return 'alter table '.$this->wrapTable($blueprint)." add primary key ({$columns})"; } /** * Compile a unique key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileUnique(Blueprint $blueprint, Fluent $command) { return sprintf('alter table %s add constraint %s unique (%s)', $this->wrapTable($blueprint), $this->wrap($command->index), $this->columnize($command->columns) ); } /** * Compile a plain index key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileIndex(Blueprint $blueprint, Fluent $command) { return sprintf('create index %s on %s%s (%s)', $this->wrap($command->index), $this->wrapTable($blueprint), $command->algorithm ? ' using '.$command->algorithm : '', $this->columnize($command->columns) ); } /** * Compile a spatial index key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileSpatialIndex(Blueprint $blueprint, Fluent $command) { $command->algorithm = 'gist'; return $this->compileIndex($blueprint, $command); } /** * Compile a foreign key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileForeign(Blueprint $blueprint, Fluent $command) { $sql = parent::compileForeign($blueprint, $command); if (! is_null($command->deferrable)) { $sql .= $command->deferrable ? ' deferrable' : ' not deferrable'; } if ($command->deferrable && ! is_null($command->initiallyImmediate)) { $sql .= $command->initiallyImmediate ? ' initially immediate' : ' initially deferred'; } if (! is_null($command->notValid)) { $sql .= ' not valid'; } return $sql; } /** * Compile a drop table command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDrop(Blueprint $blueprint, Fluent $command) { return 'drop table '.$this->wrapTable($blueprint); } /** * Compile a drop table (if exists) command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropIfExists(Blueprint $blueprint, Fluent $command) { return 'drop table if exists '.$this->wrapTable($blueprint); } /** * Compile the SQL needed to drop all tables. * * @param array $tables * @return string */ public function compileDropAllTables($tables) { return 'drop table "'.implode('","', $tables).'" cascade'; } /** * Compile the SQL needed to drop all views. * * @param array $views * @return string */ public function compileDropAllViews($views) { return 'drop view "'.implode('","', $views).'" cascade'; } /** * Compile the SQL needed to drop all types. * * @param array $types * @return string */ public function compileDropAllTypes($types) { return 'drop type "'.implode('","', $types).'" cascade'; } /** * Compile the SQL needed to retrieve all table names. * * @param string|array $schema * @return string */ public function compileGetAllTables($schema) { return "select tablename from pg_catalog.pg_tables where schemaname in ('".implode("','", (array) $schema)."')"; } /** * Compile the SQL needed to retrieve all view names. * * @param string|array $schema * @return string */ public function compileGetAllViews($schema) { return "select viewname from pg_catalog.pg_views where schemaname in ('".implode("','", (array) $schema)."')"; } /** * Compile the SQL needed to retrieve all type names. * * @return string */ public function compileGetAllTypes() { return 'select distinct pg_type.typname from pg_type inner join pg_enum on pg_enum.enumtypid = pg_type.oid'; } /** * Compile a drop column command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropColumn(Blueprint $blueprint, Fluent $command) { $columns = $this->prefixArray('drop column', $this->wrapArray($command->columns)); return 'alter table '.$this->wrapTable($blueprint).' '.implode(', ', $columns); } /** * Compile a drop primary key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropPrimary(Blueprint $blueprint, Fluent $command) { $index = $this->wrap("{$blueprint->getTable()}_pkey"); return 'alter table '.$this->wrapTable($blueprint)." drop constraint {$index}"; } /** * Compile a drop unique key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropUnique(Blueprint $blueprint, Fluent $command) { $index = $this->wrap($command->index); return "alter table {$this->wrapTable($blueprint)} drop constraint {$index}"; } /** * Compile a drop index command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropIndex(Blueprint $blueprint, Fluent $command) { return "drop index {$this->wrap($command->index)}"; } /** * Compile a drop spatial index command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropSpatialIndex(Blueprint $blueprint, Fluent $command) { return $this->compileDropIndex($blueprint, $command); } /** * Compile a drop foreign key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropForeign(Blueprint $blueprint, Fluent $command) { $index = $this->wrap($command->index); return "alter table {$this->wrapTable($blueprint)} drop constraint {$index}"; } /** * Compile a rename table command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileRename(Blueprint $blueprint, Fluent $command) { $from = $this->wrapTable($blueprint); return "alter table {$from} rename to ".$this->wrapTable($command->to); } /** * Compile a rename index command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileRenameIndex(Blueprint $blueprint, Fluent $command) { return sprintf('alter index %s rename to %s', $this->wrap($command->from), $this->wrap($command->to) ); } /** * Compile the command to enable foreign key constraints. * * @return string */ public function compileEnableForeignKeyConstraints() { return 'SET CONSTRAINTS ALL IMMEDIATE;'; } /** * Compile the command to disable foreign key constraints. * * @return string */ public function compileDisableForeignKeyConstraints() { return 'SET CONSTRAINTS ALL DEFERRED;'; } /** * Compile a comment command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileComment(Blueprint $blueprint, Fluent $command) { return sprintf('comment on column %s.%s is %s', $this->wrapTable($blueprint), $this->wrap($command->column->name), "'".str_replace("'", "''", $command->value)."'" ); } /** * Create the column definition for a char type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeChar(Fluent $column) { return "char({$column->length})"; } /** * Create the column definition for a string type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeString(Fluent $column) { return "varchar({$column->length})"; } /** * Create the column definition for a text type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeText(Fluent $column) { return 'text'; } /** * Create the column definition for a medium text type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeMediumText(Fluent $column) { return 'text'; } /** * Create the column definition for a long text type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeLongText(Fluent $column) { return 'text'; } /** * Create the column definition for an integer type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeInteger(Fluent $column) { return $this->generatableColumn('integer', $column); } /** * Create the column definition for a big integer type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeBigInteger(Fluent $column) { return $this->generatableColumn('bigint', $column); } /** * Create the column definition for a medium integer type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeMediumInteger(Fluent $column) { return $this->generatableColumn('integer', $column); } /** * Create the column definition for a tiny integer type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeTinyInteger(Fluent $column) { return $this->generatableColumn('smallint', $column); } /** * Create the column definition for a small integer type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeSmallInteger(Fluent $column) { return $this->generatableColumn('smallint', $column); } /** * Create the column definition for a generatable column. * * @param string $type * @param \Illuminate\Support\Fluent $column * @return string */ protected function generatableColumn($type, Fluent $column) { if (! $column->autoIncrement && is_null($column->generatedAs)) { return $type; } if ($column->autoIncrement && is_null($column->generatedAs)) { return with([ 'integer' => 'serial', 'bigint' => 'bigserial', 'smallint' => 'smallserial', ])[$type]; } $options = ''; if (! is_bool($column->generatedAs) && ! empty($column->generatedAs)) { $options = sprintf(' (%s)', $column->generatedAs); } return sprintf( '%s generated %s as identity%s', $type, $column->always ? 'always' : 'by default', $options ); } /** * Create the column definition for a float type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeFloat(Fluent $column) { return $this->typeDouble($column); } /** * Create the column definition for a double type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeDouble(Fluent $column) { return 'double precision'; } /** * Create the column definition for a real type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeReal(Fluent $column) { return 'real'; } /** * Create the column definition for a decimal type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeDecimal(Fluent $column) { return "decimal({$column->total}, {$column->places})"; } /** * Create the column definition for a boolean type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeBoolean(Fluent $column) { return 'boolean'; } /** * Create the column definition for an enumeration type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeEnum(Fluent $column) { return sprintf( 'varchar(255) check ("%s" in (%s))', $column->name, $this->quoteString($column->allowed) ); } /** * Create the column definition for a json type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeJson(Fluent $column) { return 'json'; } /** * Create the column definition for a jsonb type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeJsonb(Fluent $column) { return 'jsonb'; } /** * Create the column definition for a date type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeDate(Fluent $column) { return 'date'; } /** * Create the column definition for a date-time type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeDateTime(Fluent $column) { return $this->typeTimestamp($column); } /** * Create the column definition for a date-time (with time zone) type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeDateTimeTz(Fluent $column) { return $this->typeTimestampTz($column); } /** * Create the column definition for a time type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeTime(Fluent $column) { return 'time'.(is_null($column->precision) ? '' : "($column->precision)").' without time zone'; } /** * Create the column definition for a time (with time zone) type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeTimeTz(Fluent $column) { return 'time'.(is_null($column->precision) ? '' : "($column->precision)").' with time zone'; } /** * Create the column definition for a timestamp type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeTimestamp(Fluent $column) { $columnType = 'timestamp'.(is_null($column->precision) ? '' : "($column->precision)").' without time zone'; return $column->useCurrent ? "$columnType default CURRENT_TIMESTAMP" : $columnType; } /** * Create the column definition for a timestamp (with time zone) type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeTimestampTz(Fluent $column) { $columnType = 'timestamp'.(is_null($column->precision) ? '' : "($column->precision)").' with time zone'; return $column->useCurrent ? "$columnType default CURRENT_TIMESTAMP" : $columnType; } /** * Create the column definition for a year type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeYear(Fluent $column) { return $this->typeInteger($column); } /** * Create the column definition for a binary type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeBinary(Fluent $column) { return 'bytea'; } /** * Create the column definition for a uuid type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeUuid(Fluent $column) { return 'uuid'; } /** * Create the column definition for an IP address type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeIpAddress(Fluent $column) { return 'inet'; } /** * Create the column definition for a MAC address type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeMacAddress(Fluent $column) { return 'macaddr'; } /** * Create the column definition for a spatial Geometry type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeGeometry(Fluent $column) { return $this->formatPostGisType('geometry', $column); } /** * Create the column definition for a spatial Point type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typePoint(Fluent $column) { return $this->formatPostGisType('point', $column); } /** * Create the column definition for a spatial LineString type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeLineString(Fluent $column) { return $this->formatPostGisType('linestring', $column); } /** * Create the column definition for a spatial Polygon type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typePolygon(Fluent $column) { return $this->formatPostGisType('polygon', $column); } /** * Create the column definition for a spatial GeometryCollection type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeGeometryCollection(Fluent $column) { return $this->formatPostGisType('geometrycollection', $column); } /** * Create the column definition for a spatial MultiPoint type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeMultiPoint(Fluent $column) { return $this->formatPostGisType('multipoint', $column); } /** * Create the column definition for a spatial MultiLineString type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typeMultiLineString(Fluent $column) { return $this->formatPostGisType('multilinestring', $column); } /** * Create the column definition for a spatial MultiPolygon type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeMultiPolygon(Fluent $column) { return $this->formatPostGisType('multipolygon', $column); } /** * Create the column definition for a spatial MultiPolygonZ type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeMultiPolygonZ(Fluent $column) { return $this->formatPostGisType('multipolygonz', $column); } /** * Format the column definition for a PostGIS spatial type. * * @param string $type * @param \Illuminate\Support\Fluent $column * @return string */ private function formatPostGisType($type, Fluent $column) { if ($column->isGeometry === null) { return sprintf('geography(%s, %s)', $type, $column->projection ?? '4326'); } if ($column->projection !== null) { return sprintf('geometry(%s, %s)', $type, $column->projection); } return "geometry({$type})"; } /** * Get the SQL for a collation column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyCollate(Blueprint $blueprint, Fluent $column) { if (! is_null($column->collation)) { return ' collate '.$this->wrapValue($column->collation); } } /** * Get the SQL for a nullable column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyNullable(Blueprint $blueprint, Fluent $column) { return $column->nullable ? ' null' : ' not null'; } /** * Get the SQL for a default column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyDefault(Blueprint $blueprint, Fluent $column) { if (! is_null($column->default)) { return ' default '.$this->getDefaultValue($column->default); } } /** * Get the SQL for an auto-increment column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyIncrement(Blueprint $blueprint, Fluent $column) { if ((in_array($column->type, $this->serials) || ($column->generatedAs !== null)) && $column->autoIncrement) { return ' primary key'; } } /** * Get the SQL for a generated virtual column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyVirtualAs(Blueprint $blueprint, Fluent $column) { if ($column->virtualAs !== null) { return " generated always as ({$column->virtualAs})"; } } /** * Get the SQL for a generated stored column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyStoredAs(Blueprint $blueprint, Fluent $column) { if ($column->storedAs !== null) { return " generated always as ({$column->storedAs}) stored"; } } } database/Schema/Grammars/MySqlGrammar.php 0000644 00000070620 14736103231 0014353 0 ustar 00 <?php namespace Illuminate\Database\Schema\Grammars; use Illuminate\Database\Connection; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Fluent; use RuntimeException; class MySqlGrammar extends Grammar { /** * The possible column modifiers. * * @var array */ protected $modifiers = [ 'Unsigned', 'Charset', 'Collate', 'VirtualAs', 'StoredAs', 'Nullable', 'Srid', 'Default', 'Increment', 'Comment', 'After', 'First', ]; /** * The possible column serials. * * @var array */ protected $serials = ['bigInteger', 'integer', 'mediumInteger', 'smallInteger', 'tinyInteger']; /** * Compile the query to determine the list of tables. * * @return string */ public function compileTableExists() { return "select * from information_schema.tables where table_schema = ? and table_name = ? and table_type = 'BASE TABLE'"; } /** * Compile the query to determine the list of columns. * * @return string */ public function compileColumnListing() { return 'select column_name as `column_name` from information_schema.columns where table_schema = ? and table_name = ?'; } /** * Compile a create table command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @param \Illuminate\Database\Connection $connection * @return string */ public function compileCreate(Blueprint $blueprint, Fluent $command, Connection $connection) { $sql = $this->compileCreateTable( $blueprint, $command, $connection ); // Once we have the primary SQL, we can add the encoding option to the SQL for // the table. Then, we can check if a storage engine has been supplied for // the table. If so, we will add the engine declaration to the SQL query. $sql = $this->compileCreateEncoding( $sql, $connection, $blueprint ); // Finally, we will append the engine configuration onto this SQL statement as // the final thing we do before returning this finished SQL. Once this gets // added the query will be ready to execute against the real connections. return $this->compileCreateEngine( $sql, $connection, $blueprint ); } /** * Create the main create table clause. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @param \Illuminate\Database\Connection $connection * @return string */ protected function compileCreateTable($blueprint, $command, $connection) { return sprintf('%s table %s (%s)', $blueprint->temporary ? 'create temporary' : 'create', $this->wrapTable($blueprint), implode(', ', $this->getColumns($blueprint)) ); } /** * Append the character set specifications to a command. * * @param string $sql * @param \Illuminate\Database\Connection $connection * @param \Illuminate\Database\Schema\Blueprint $blueprint * @return string */ protected function compileCreateEncoding($sql, Connection $connection, Blueprint $blueprint) { // First we will set the character set if one has been set on either the create // blueprint itself or on the root configuration for the connection that the // table is being created on. We will add these to the create table query. if (isset($blueprint->charset)) { $sql .= ' default character set '.$blueprint->charset; } elseif (! is_null($charset = $connection->getConfig('charset'))) { $sql .= ' default character set '.$charset; } // Next we will add the collation to the create table statement if one has been // added to either this create table blueprint or the configuration for this // connection that the query is targeting. We'll add it to this SQL query. if (isset($blueprint->collation)) { $sql .= " collate '{$blueprint->collation}'"; } elseif (! is_null($collation = $connection->getConfig('collation'))) { $sql .= " collate '{$collation}'"; } return $sql; } /** * Append the engine specifications to a command. * * @param string $sql * @param \Illuminate\Database\Connection $connection * @param \Illuminate\Database\Schema\Blueprint $blueprint * @return string */ protected function compileCreateEngine($sql, Connection $connection, Blueprint $blueprint) { if (isset($blueprint->engine)) { return $sql.' engine = '.$blueprint->engine; } elseif (! is_null($engine = $connection->getConfig('engine'))) { return $sql.' engine = '.$engine; } return $sql; } /** * Compile an add column command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileAdd(Blueprint $blueprint, Fluent $command) { $columns = $this->prefixArray('add', $this->getColumns($blueprint)); return 'alter table '.$this->wrapTable($blueprint).' '.implode(', ', $columns); } /** * Compile a primary key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compilePrimary(Blueprint $blueprint, Fluent $command) { $command->name(null); return $this->compileKey($blueprint, $command, 'primary key'); } /** * Compile a unique key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileUnique(Blueprint $blueprint, Fluent $command) { return $this->compileKey($blueprint, $command, 'unique'); } /** * Compile a plain index key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileIndex(Blueprint $blueprint, Fluent $command) { return $this->compileKey($blueprint, $command, 'index'); } /** * Compile a spatial index key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileSpatialIndex(Blueprint $blueprint, Fluent $command) { return $this->compileKey($blueprint, $command, 'spatial index'); } /** * Compile an index creation command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @param string $type * @return string */ protected function compileKey(Blueprint $blueprint, Fluent $command, $type) { return sprintf('alter table %s add %s %s%s(%s)', $this->wrapTable($blueprint), $type, $this->wrap($command->index), $command->algorithm ? ' using '.$command->algorithm : '', $this->columnize($command->columns) ); } /** * Compile a drop table command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDrop(Blueprint $blueprint, Fluent $command) { return 'drop table '.$this->wrapTable($blueprint); } /** * Compile a drop table (if exists) command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropIfExists(Blueprint $blueprint, Fluent $command) { return 'drop table if exists '.$this->wrapTable($blueprint); } /** * Compile a drop column command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropColumn(Blueprint $blueprint, Fluent $command) { $columns = $this->prefixArray('drop', $this->wrapArray($command->columns)); return 'alter table '.$this->wrapTable($blueprint).' '.implode(', ', $columns); } /** * Compile a drop primary key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropPrimary(Blueprint $blueprint, Fluent $command) { return 'alter table '.$this->wrapTable($blueprint).' drop primary key'; } /** * Compile a drop unique key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropUnique(Blueprint $blueprint, Fluent $command) { $index = $this->wrap($command->index); return "alter table {$this->wrapTable($blueprint)} drop index {$index}"; } /** * Compile a drop index command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropIndex(Blueprint $blueprint, Fluent $command) { $index = $this->wrap($command->index); return "alter table {$this->wrapTable($blueprint)} drop index {$index}"; } /** * Compile a drop spatial index command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropSpatialIndex(Blueprint $blueprint, Fluent $command) { return $this->compileDropIndex($blueprint, $command); } /** * Compile a drop foreign key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropForeign(Blueprint $blueprint, Fluent $command) { $index = $this->wrap($command->index); return "alter table {$this->wrapTable($blueprint)} drop foreign key {$index}"; } /** * Compile a rename table command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileRename(Blueprint $blueprint, Fluent $command) { $from = $this->wrapTable($blueprint); return "rename table {$from} to ".$this->wrapTable($command->to); } /** * Compile a rename index command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileRenameIndex(Blueprint $blueprint, Fluent $command) { return sprintf('alter table %s rename index %s to %s', $this->wrapTable($blueprint), $this->wrap($command->from), $this->wrap($command->to) ); } /** * Compile the SQL needed to drop all tables. * * @param array $tables * @return string */ public function compileDropAllTables($tables) { return 'drop table '.implode(',', $this->wrapArray($tables)); } /** * Compile the SQL needed to drop all views. * * @param array $views * @return string */ public function compileDropAllViews($views) { return 'drop view '.implode(',', $this->wrapArray($views)); } /** * Compile the SQL needed to retrieve all table names. * * @return string */ public function compileGetAllTables() { return 'SHOW FULL TABLES WHERE table_type = \'BASE TABLE\''; } /** * Compile the SQL needed to retrieve all view names. * * @return string */ public function compileGetAllViews() { return 'SHOW FULL TABLES WHERE table_type = \'VIEW\''; } /** * Compile the command to enable foreign key constraints. * * @return string */ public function compileEnableForeignKeyConstraints() { return 'SET FOREIGN_KEY_CHECKS=1;'; } /** * Compile the command to disable foreign key constraints. * * @return string */ public function compileDisableForeignKeyConstraints() { return 'SET FOREIGN_KEY_CHECKS=0;'; } /** * Create the column definition for a char type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeChar(Fluent $column) { return "char({$column->length})"; } /** * Create the column definition for a string type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeString(Fluent $column) { return "varchar({$column->length})"; } /** * Create the column definition for a text type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeText(Fluent $column) { return 'text'; } /** * Create the column definition for a medium text type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeMediumText(Fluent $column) { return 'mediumtext'; } /** * Create the column definition for a long text type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeLongText(Fluent $column) { return 'longtext'; } /** * Create the column definition for a big integer type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeBigInteger(Fluent $column) { return 'bigint'; } /** * Create the column definition for an integer type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeInteger(Fluent $column) { return 'int'; } /** * Create the column definition for a medium integer type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeMediumInteger(Fluent $column) { return 'mediumint'; } /** * Create the column definition for a tiny integer type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeTinyInteger(Fluent $column) { return 'tinyint'; } /** * Create the column definition for a small integer type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeSmallInteger(Fluent $column) { return 'smallint'; } /** * Create the column definition for a float type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeFloat(Fluent $column) { return $this->typeDouble($column); } /** * Create the column definition for a double type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeDouble(Fluent $column) { if ($column->total && $column->places) { return "double({$column->total}, {$column->places})"; } return 'double'; } /** * Create the column definition for a decimal type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeDecimal(Fluent $column) { return "decimal({$column->total}, {$column->places})"; } /** * Create the column definition for a boolean type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeBoolean(Fluent $column) { return 'tinyint(1)'; } /** * Create the column definition for an enumeration type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeEnum(Fluent $column) { return sprintf('enum(%s)', $this->quoteString($column->allowed)); } /** * Create the column definition for a set enumeration type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeSet(Fluent $column) { return sprintf('set(%s)', $this->quoteString($column->allowed)); } /** * Create the column definition for a json type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeJson(Fluent $column) { return 'json'; } /** * Create the column definition for a jsonb type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeJsonb(Fluent $column) { return 'json'; } /** * Create the column definition for a date type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeDate(Fluent $column) { return 'date'; } /** * Create the column definition for a date-time type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeDateTime(Fluent $column) { $columnType = $column->precision ? "datetime($column->precision)" : 'datetime'; return $column->useCurrent ? "$columnType default CURRENT_TIMESTAMP" : $columnType; } /** * Create the column definition for a date-time (with time zone) type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeDateTimeTz(Fluent $column) { return $this->typeDateTime($column); } /** * Create the column definition for a time type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeTime(Fluent $column) { return $column->precision ? "time($column->precision)" : 'time'; } /** * Create the column definition for a time (with time zone) type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeTimeTz(Fluent $column) { return $this->typeTime($column); } /** * Create the column definition for a timestamp type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeTimestamp(Fluent $column) { $columnType = $column->precision ? "timestamp($column->precision)" : 'timestamp'; $defaultCurrent = $column->precision ? "CURRENT_TIMESTAMP($column->precision)" : 'CURRENT_TIMESTAMP'; return $column->useCurrent ? "$columnType default $defaultCurrent" : $columnType; } /** * Create the column definition for a timestamp (with time zone) type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeTimestampTz(Fluent $column) { return $this->typeTimestamp($column); } /** * Create the column definition for a year type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeYear(Fluent $column) { return 'year'; } /** * Create the column definition for a binary type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeBinary(Fluent $column) { return 'blob'; } /** * Create the column definition for a uuid type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeUuid(Fluent $column) { return 'char(36)'; } /** * Create the column definition for an IP address type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeIpAddress(Fluent $column) { return 'varchar(45)'; } /** * Create the column definition for a MAC address type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeMacAddress(Fluent $column) { return 'varchar(17)'; } /** * Create the column definition for a spatial Geometry type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typeGeometry(Fluent $column) { return 'geometry'; } /** * Create the column definition for a spatial Point type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typePoint(Fluent $column) { return 'point'; } /** * Create the column definition for a spatial LineString type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typeLineString(Fluent $column) { return 'linestring'; } /** * Create the column definition for a spatial Polygon type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typePolygon(Fluent $column) { return 'polygon'; } /** * Create the column definition for a spatial GeometryCollection type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typeGeometryCollection(Fluent $column) { return 'geometrycollection'; } /** * Create the column definition for a spatial MultiPoint type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typeMultiPoint(Fluent $column) { return 'multipoint'; } /** * Create the column definition for a spatial MultiLineString type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typeMultiLineString(Fluent $column) { return 'multilinestring'; } /** * Create the column definition for a spatial MultiPolygon type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typeMultiPolygon(Fluent $column) { return 'multipolygon'; } /** * Create the column definition for a generated, computed column type. * * @param \Illuminate\Support\Fluent $column * @return void * * @throws \RuntimeException */ protected function typeComputed(Fluent $column) { throw new RuntimeException('This database driver requires a type, see the virtualAs / storedAs modifiers.'); } /** * Get the SQL for a generated virtual column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyVirtualAs(Blueprint $blueprint, Fluent $column) { if (! is_null($column->virtualAs)) { return " as ({$column->virtualAs})"; } } /** * Get the SQL for a generated stored column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyStoredAs(Blueprint $blueprint, Fluent $column) { if (! is_null($column->storedAs)) { return " as ({$column->storedAs}) stored"; } } /** * Get the SQL for an unsigned column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyUnsigned(Blueprint $blueprint, Fluent $column) { if ($column->unsigned) { return ' unsigned'; } } /** * Get the SQL for a character set column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyCharset(Blueprint $blueprint, Fluent $column) { if (! is_null($column->charset)) { return ' character set '.$column->charset; } } /** * Get the SQL for a collation column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyCollate(Blueprint $blueprint, Fluent $column) { if (! is_null($column->collation)) { return " collate '{$column->collation}'"; } } /** * Get the SQL for a nullable column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyNullable(Blueprint $blueprint, Fluent $column) { if (is_null($column->virtualAs) && is_null($column->storedAs)) { return $column->nullable ? ' null' : ' not null'; } if ($column->nullable === false) { return ' not null'; } } /** * Get the SQL for a default column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyDefault(Blueprint $blueprint, Fluent $column) { if (! is_null($column->default)) { return ' default '.$this->getDefaultValue($column->default); } } /** * Get the SQL for an auto-increment column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyIncrement(Blueprint $blueprint, Fluent $column) { if (in_array($column->type, $this->serials) && $column->autoIncrement) { return ' auto_increment primary key'; } } /** * Get the SQL for a "first" column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyFirst(Blueprint $blueprint, Fluent $column) { if (! is_null($column->first)) { return ' first'; } } /** * Get the SQL for an "after" column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyAfter(Blueprint $blueprint, Fluent $column) { if (! is_null($column->after)) { return ' after '.$this->wrap($column->after); } } /** * Get the SQL for a "comment" column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyComment(Blueprint $blueprint, Fluent $column) { if (! is_null($column->comment)) { return " comment '".addslashes($column->comment)."'"; } } /** * Get the SQL for a SRID column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifySrid(Blueprint $blueprint, Fluent $column) { if (! is_null($column->srid) && is_int($column->srid) && $column->srid > 0) { return ' srid '.$column->srid; } } /** * Wrap a single string in keyword identifiers. * * @param string $value * @return string */ protected function wrapValue($value) { if ($value !== '*') { return '`'.str_replace('`', '``', $value).'`'; } return $value; } } database/Schema/Grammars/RenameColumn.php 0000644 00000005014 14736103231 0014357 0 ustar 00 <?php namespace Illuminate\Database\Schema\Grammars; use Doctrine\DBAL\Schema\AbstractSchemaManager as SchemaManager; use Doctrine\DBAL\Schema\Column; use Doctrine\DBAL\Schema\TableDiff; use Illuminate\Database\Connection; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Fluent; class RenameColumn { /** * Compile a rename column command. * * @param \Illuminate\Database\Schema\Grammars\Grammar $grammar * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @param \Illuminate\Database\Connection $connection * @return array */ public static function compile(Grammar $grammar, Blueprint $blueprint, Fluent $command, Connection $connection) { $schema = $connection->getDoctrineSchemaManager(); $databasePlatform = $schema->getDatabasePlatform(); $databasePlatform->registerDoctrineTypeMapping('enum', 'string'); $column = $connection->getDoctrineColumn( $grammar->getTablePrefix().$blueprint->getTable(), $command->from ); return (array) $databasePlatform->getAlterTableSQL(static::getRenamedDiff( $grammar, $blueprint, $command, $column, $schema )); } /** * Get a new column instance with the new column name. * * @param \Illuminate\Database\Schema\Grammars\Grammar $grammar * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @param \Doctrine\DBAL\Schema\Column $column * @param \Doctrine\DBAL\Schema\AbstractSchemaManager $schema * @return \Doctrine\DBAL\Schema\TableDiff */ protected static function getRenamedDiff(Grammar $grammar, Blueprint $blueprint, Fluent $command, Column $column, SchemaManager $schema) { return static::setRenamedColumns( $grammar->getDoctrineTableDiff($blueprint, $schema), $command, $column ); } /** * Set the renamed columns on the table diff. * * @param \Doctrine\DBAL\Schema\TableDiff $tableDiff * @param \Illuminate\Support\Fluent $command * @param \Doctrine\DBAL\Schema\Column $column * @return \Doctrine\DBAL\Schema\TableDiff */ protected static function setRenamedColumns(TableDiff $tableDiff, Fluent $command, Column $column) { $tableDiff->renamedColumns = [ $command->from => new Column($command->to, $column->getType(), $column->toArray()), ]; return $tableDiff; } } database/Schema/Grammars/SqlServerGrammar.php 0000644 00000057012 14736103231 0015234 0 ustar 00 <?php namespace Illuminate\Database\Schema\Grammars; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Fluent; class SqlServerGrammar extends Grammar { /** * If this Grammar supports schema changes wrapped in a transaction. * * @var bool */ protected $transactions = true; /** * The possible column modifiers. * * @var array */ protected $modifiers = ['Increment', 'Collate', 'Nullable', 'Default', 'Persisted']; /** * The columns available as serials. * * @var array */ protected $serials = ['tinyInteger', 'smallInteger', 'mediumInteger', 'integer', 'bigInteger']; /** * Compile the query to determine if a table exists. * * @return string */ public function compileTableExists() { return "select * from sysobjects where type = 'U' and name = ?"; } /** * Compile the query to determine the list of columns. * * @param string $table * @return string */ public function compileColumnListing($table) { return "select col.name from sys.columns as col join sys.objects as obj on col.object_id = obj.object_id where obj.type = 'U' and obj.name = '$table'"; } /** * Compile a create table command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileCreate(Blueprint $blueprint, Fluent $command) { $columns = implode(', ', $this->getColumns($blueprint)); return 'create table '.$this->wrapTable($blueprint)." ($columns)"; } /** * Compile a column addition table command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileAdd(Blueprint $blueprint, Fluent $command) { return sprintf('alter table %s add %s', $this->wrapTable($blueprint), implode(', ', $this->getColumns($blueprint)) ); } /** * Compile a primary key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compilePrimary(Blueprint $blueprint, Fluent $command) { return sprintf('alter table %s add constraint %s primary key (%s)', $this->wrapTable($blueprint), $this->wrap($command->index), $this->columnize($command->columns) ); } /** * Compile a unique key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileUnique(Blueprint $blueprint, Fluent $command) { return sprintf('create unique index %s on %s (%s)', $this->wrap($command->index), $this->wrapTable($blueprint), $this->columnize($command->columns) ); } /** * Compile a plain index key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileIndex(Blueprint $blueprint, Fluent $command) { return sprintf('create index %s on %s (%s)', $this->wrap($command->index), $this->wrapTable($blueprint), $this->columnize($command->columns) ); } /** * Compile a spatial index key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileSpatialIndex(Blueprint $blueprint, Fluent $command) { return sprintf('create spatial index %s on %s (%s)', $this->wrap($command->index), $this->wrapTable($blueprint), $this->columnize($command->columns) ); } /** * Compile a drop table command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDrop(Blueprint $blueprint, Fluent $command) { return 'drop table '.$this->wrapTable($blueprint); } /** * Compile a drop table (if exists) command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropIfExists(Blueprint $blueprint, Fluent $command) { return sprintf('if exists (select * from INFORMATION_SCHEMA.TABLES where TABLE_NAME = %s) drop table %s', "'".str_replace("'", "''", $this->getTablePrefix().$blueprint->getTable())."'", $this->wrapTable($blueprint) ); } /** * Compile the SQL needed to drop all tables. * * @return string */ public function compileDropAllTables() { return "EXEC sp_msforeachtable 'DROP TABLE ?'"; } /** * Compile a drop column command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropColumn(Blueprint $blueprint, Fluent $command) { $columns = $this->wrapArray($command->columns); $dropExistingConstraintsSql = $this->compileDropDefaultConstraint($blueprint, $command).';'; return $dropExistingConstraintsSql.'alter table '.$this->wrapTable($blueprint).' drop column '.implode(', ', $columns); } /** * Compile a drop default constraint command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropDefaultConstraint(Blueprint $blueprint, Fluent $command) { $columns = "'".implode("','", $command->columns)."'"; $tableName = $this->getTablePrefix().$blueprint->getTable(); $sql = "DECLARE @sql NVARCHAR(MAX) = '';"; $sql .= "SELECT @sql += 'ALTER TABLE [dbo].[{$tableName}] DROP CONSTRAINT ' + OBJECT_NAME([default_object_id]) + ';' "; $sql .= 'FROM SYS.COLUMNS '; $sql .= "WHERE [object_id] = OBJECT_ID('[dbo].[{$tableName}]') AND [name] in ({$columns}) AND [default_object_id] <> 0;"; $sql .= 'EXEC(@sql)'; return $sql; } /** * Compile a drop primary key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropPrimary(Blueprint $blueprint, Fluent $command) { $index = $this->wrap($command->index); return "alter table {$this->wrapTable($blueprint)} drop constraint {$index}"; } /** * Compile a drop unique key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropUnique(Blueprint $blueprint, Fluent $command) { $index = $this->wrap($command->index); return "drop index {$index} on {$this->wrapTable($blueprint)}"; } /** * Compile a drop index command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropIndex(Blueprint $blueprint, Fluent $command) { $index = $this->wrap($command->index); return "drop index {$index} on {$this->wrapTable($blueprint)}"; } /** * Compile a drop spatial index command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropSpatialIndex(Blueprint $blueprint, Fluent $command) { return $this->compileDropIndex($blueprint, $command); } /** * Compile a drop foreign key command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileDropForeign(Blueprint $blueprint, Fluent $command) { $index = $this->wrap($command->index); return "alter table {$this->wrapTable($blueprint)} drop constraint {$index}"; } /** * Compile a rename table command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileRename(Blueprint $blueprint, Fluent $command) { $from = $this->wrapTable($blueprint); return "sp_rename {$from}, ".$this->wrapTable($command->to); } /** * Compile a rename index command. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command * @return string */ public function compileRenameIndex(Blueprint $blueprint, Fluent $command) { return sprintf("sp_rename N'%s', %s, N'INDEX'", $this->wrap($blueprint->getTable().'.'.$command->from), $this->wrap($command->to) ); } /** * Compile the command to enable foreign key constraints. * * @return string */ public function compileEnableForeignKeyConstraints() { return 'EXEC sp_msforeachtable @command1="print \'?\'", @command2="ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all";'; } /** * Compile the command to disable foreign key constraints. * * @return string */ public function compileDisableForeignKeyConstraints() { return 'EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all";'; } /** * Compile the command to drop all foreign keys. * * @return string */ public function compileDropAllForeignKeys() { return "DECLARE @sql NVARCHAR(MAX) = N''; SELECT @sql += 'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(parent_object_id)) + '.' + + QUOTENAME(OBJECT_NAME(parent_object_id)) + ' DROP CONSTRAINT ' + QUOTENAME(name) + ';' FROM sys.foreign_keys; EXEC sp_executesql @sql;"; } /** * Compile the command to drop all views. * * @return string */ public function compileDropAllViews() { return "DECLARE @sql NVARCHAR(MAX) = N''; SELECT @sql += 'DROP VIEW ' + QUOTENAME(OBJECT_SCHEMA_NAME(object_id)) + '.' + QUOTENAME(name) + ';' FROM sys.views; EXEC sp_executesql @sql;"; } /** * Create the column definition for a char type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeChar(Fluent $column) { return "nchar({$column->length})"; } /** * Create the column definition for a string type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeString(Fluent $column) { return "nvarchar({$column->length})"; } /** * Create the column definition for a text type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeText(Fluent $column) { return 'nvarchar(max)'; } /** * Create the column definition for a medium text type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeMediumText(Fluent $column) { return 'nvarchar(max)'; } /** * Create the column definition for a long text type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeLongText(Fluent $column) { return 'nvarchar(max)'; } /** * Create the column definition for an integer type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeInteger(Fluent $column) { return 'int'; } /** * Create the column definition for a big integer type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeBigInteger(Fluent $column) { return 'bigint'; } /** * Create the column definition for a medium integer type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeMediumInteger(Fluent $column) { return 'int'; } /** * Create the column definition for a tiny integer type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeTinyInteger(Fluent $column) { return 'tinyint'; } /** * Create the column definition for a small integer type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeSmallInteger(Fluent $column) { return 'smallint'; } /** * Create the column definition for a float type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeFloat(Fluent $column) { return 'float'; } /** * Create the column definition for a double type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeDouble(Fluent $column) { return 'float'; } /** * Create the column definition for a decimal type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeDecimal(Fluent $column) { return "decimal({$column->total}, {$column->places})"; } /** * Create the column definition for a boolean type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeBoolean(Fluent $column) { return 'bit'; } /** * Create the column definition for an enumeration type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeEnum(Fluent $column) { return sprintf( 'nvarchar(255) check ("%s" in (%s))', $column->name, $this->quoteString($column->allowed) ); } /** * Create the column definition for a json type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeJson(Fluent $column) { return 'nvarchar(max)'; } /** * Create the column definition for a jsonb type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeJsonb(Fluent $column) { return 'nvarchar(max)'; } /** * Create the column definition for a date type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeDate(Fluent $column) { return 'date'; } /** * Create the column definition for a date-time type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeDateTime(Fluent $column) { return $this->typeTimestamp($column); } /** * Create the column definition for a date-time (with time zone) type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeDateTimeTz(Fluent $column) { return $this->typeTimestampTz($column); } /** * Create the column definition for a time type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeTime(Fluent $column) { return $column->precision ? "time($column->precision)" : 'time'; } /** * Create the column definition for a time (with time zone) type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeTimeTz(Fluent $column) { return $this->typeTime($column); } /** * Create the column definition for a timestamp type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeTimestamp(Fluent $column) { $columnType = $column->precision ? "datetime2($column->precision)" : 'datetime'; return $column->useCurrent ? "$columnType default CURRENT_TIMESTAMP" : $columnType; } /** * Create the column definition for a timestamp (with time zone) type. * * @link https://docs.microsoft.com/en-us/sql/t-sql/data-types/datetimeoffset-transact-sql?view=sql-server-ver15 * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeTimestampTz(Fluent $column) { $columnType = $column->precision ? "datetimeoffset($column->precision)" : 'datetimeoffset'; return $column->useCurrent ? "$columnType default CURRENT_TIMESTAMP" : $columnType; } /** * Create the column definition for a year type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeYear(Fluent $column) { return $this->typeInteger($column); } /** * Create the column definition for a binary type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeBinary(Fluent $column) { return 'varbinary(max)'; } /** * Create the column definition for a uuid type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeUuid(Fluent $column) { return 'uniqueidentifier'; } /** * Create the column definition for an IP address type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeIpAddress(Fluent $column) { return 'nvarchar(45)'; } /** * Create the column definition for a MAC address type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeMacAddress(Fluent $column) { return 'nvarchar(17)'; } /** * Create the column definition for a spatial Geometry type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typeGeometry(Fluent $column) { return 'geography'; } /** * Create the column definition for a spatial Point type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typePoint(Fluent $column) { return 'geography'; } /** * Create the column definition for a spatial LineString type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typeLineString(Fluent $column) { return 'geography'; } /** * Create the column definition for a spatial Polygon type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typePolygon(Fluent $column) { return 'geography'; } /** * Create the column definition for a spatial GeometryCollection type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typeGeometryCollection(Fluent $column) { return 'geography'; } /** * Create the column definition for a spatial MultiPoint type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typeMultiPoint(Fluent $column) { return 'geography'; } /** * Create the column definition for a spatial MultiLineString type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typeMultiLineString(Fluent $column) { return 'geography'; } /** * Create the column definition for a spatial MultiPolygon type. * * @param \Illuminate\Support\Fluent $column * @return string */ public function typeMultiPolygon(Fluent $column) { return 'geography'; } /** * Create the column definition for a generated, computed column type. * * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function typeComputed(Fluent $column) { return "as ({$column->expression})"; } /** * Get the SQL for a collation column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyCollate(Blueprint $blueprint, Fluent $column) { if (! is_null($column->collation)) { return ' collate '.$column->collation; } } /** * Get the SQL for a nullable column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyNullable(Blueprint $blueprint, Fluent $column) { if ($column->type !== 'computed') { return $column->nullable ? ' null' : ' not null'; } } /** * Get the SQL for a default column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyDefault(Blueprint $blueprint, Fluent $column) { if (! is_null($column->default)) { return ' default '.$this->getDefaultValue($column->default); } } /** * Get the SQL for an auto-increment column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyIncrement(Blueprint $blueprint, Fluent $column) { if (in_array($column->type, $this->serials) && $column->autoIncrement) { return ' identity primary key'; } } /** * Get the SQL for a generated stored column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column * @return string|null */ protected function modifyPersisted(Blueprint $blueprint, Fluent $column) { if ($column->persisted) { return ' persisted'; } } /** * Wrap a table in keyword identifiers. * * @param \Illuminate\Database\Query\Expression|string $table * @return string */ public function wrapTable($table) { if ($table instanceof Blueprint && $table->temporary) { $this->setTablePrefix('#'); } return parent::wrapTable($table); } /** * Quote the given string literal. * * @param string|array $value * @return string */ public function quoteString($value) { if (is_array($value)) { return implode(', ', array_map([$this, __FUNCTION__], $value)); } return "N'$value'"; } } database/Schema/SQLiteBuilder.php 0000644 00000002430 14736103231 0012670 0 ustar 00 <?php namespace Illuminate\Database\Schema; class SQLiteBuilder extends Builder { /** * Drop all tables from the database. * * @return void */ public function dropAllTables() { if ($this->connection->getDatabaseName() !== ':memory:') { return $this->refreshDatabaseFile(); } $this->connection->select($this->grammar->compileEnableWriteableSchema()); $this->connection->select($this->grammar->compileDropAllTables()); $this->connection->select($this->grammar->compileDisableWriteableSchema()); $this->connection->select($this->grammar->compileRebuild()); } /** * Drop all views from the database. * * @return void */ public function dropAllViews() { $this->connection->select($this->grammar->compileEnableWriteableSchema()); $this->connection->select($this->grammar->compileDropAllViews()); $this->connection->select($this->grammar->compileDisableWriteableSchema()); $this->connection->select($this->grammar->compileRebuild()); } /** * Empty the database file. * * @return void */ public function refreshDatabaseFile() { file_put_contents($this->connection->getDatabaseName(), ''); } } database/Schema/ForeignKeyDefinition.php 0000644 00000001575 14736103231 0014304 0 ustar 00 <?php namespace Illuminate\Database\Schema; use Illuminate\Support\Fluent; /** * @method ForeignKeyDefinition deferrable(bool $value = true) Set the foreign key as deferrable (PostgreSQL) * @method ForeignKeyDefinition initiallyImmediate(bool $value = true) Set the default time to check the constraint (PostgreSQL) * @method ForeignKeyDefinition on(string $table) Specify the referenced table * @method ForeignKeyDefinition onDelete(string $action) Add an ON DELETE action * @method ForeignKeyDefinition onUpdate(string $action) Add an ON UPDATE action * @method ForeignKeyDefinition references(string|array $columns) Specify the referenced column(s) */ class ForeignKeyDefinition extends Fluent { /** * Indicate that deletes should cascade. * * @return $this */ public function cascadeOnDelete() { return $this->onDelete('cascade'); } } database/Schema/Builder.php 0000644 00000021363 14736103231 0011614 0 ustar 00 <?php namespace Illuminate\Database\Schema; use Closure; use Doctrine\DBAL\Types\Type; use Illuminate\Database\Connection; use LogicException; use RuntimeException; class Builder { /** * The database connection instance. * * @var \Illuminate\Database\Connection */ protected $connection; /** * The schema grammar instance. * * @var \Illuminate\Database\Schema\Grammars\Grammar */ protected $grammar; /** * The Blueprint resolver callback. * * @var \Closure */ protected $resolver; /** * The default string length for migrations. * * @var int */ public static $defaultStringLength = 255; /** * Create a new database Schema manager. * * @param \Illuminate\Database\Connection $connection * @return void */ public function __construct(Connection $connection) { $this->connection = $connection; $this->grammar = $connection->getSchemaGrammar(); } /** * Set the default string length for migrations. * * @param int $length * @return void */ public static function defaultStringLength($length) { static::$defaultStringLength = $length; } /** * Determine if the given table exists. * * @param string $table * @return bool */ public function hasTable($table) { $table = $this->connection->getTablePrefix().$table; return count($this->connection->selectFromWriteConnection( $this->grammar->compileTableExists(), [$table] )) > 0; } /** * Determine if the given table has a given column. * * @param string $table * @param string $column * @return bool */ public function hasColumn($table, $column) { return in_array( strtolower($column), array_map('strtolower', $this->getColumnListing($table)) ); } /** * Determine if the given table has given columns. * * @param string $table * @param array $columns * @return bool */ public function hasColumns($table, array $columns) { $tableColumns = array_map('strtolower', $this->getColumnListing($table)); foreach ($columns as $column) { if (! in_array(strtolower($column), $tableColumns)) { return false; } } return true; } /** * Get the data type for the given column name. * * @param string $table * @param string $column * @return string */ public function getColumnType($table, $column) { $table = $this->connection->getTablePrefix().$table; return $this->connection->getDoctrineColumn($table, $column)->getType()->getName(); } /** * Get the column listing for a given table. * * @param string $table * @return array */ public function getColumnListing($table) { $results = $this->connection->selectFromWriteConnection($this->grammar->compileColumnListing( $this->connection->getTablePrefix().$table )); return $this->connection->getPostProcessor()->processColumnListing($results); } /** * Modify a table on the schema. * * @param string $table * @param \Closure $callback * @return void */ public function table($table, Closure $callback) { $this->build($this->createBlueprint($table, $callback)); } /** * Create a new table on the schema. * * @param string $table * @param \Closure $callback * @return void */ public function create($table, Closure $callback) { $this->build(tap($this->createBlueprint($table), function ($blueprint) use ($callback) { $blueprint->create(); $callback($blueprint); })); } /** * Drop a table from the schema. * * @param string $table * @return void */ public function drop($table) { $this->build(tap($this->createBlueprint($table), function ($blueprint) { $blueprint->drop(); })); } /** * Drop a table from the schema if it exists. * * @param string $table * @return void */ public function dropIfExists($table) { $this->build(tap($this->createBlueprint($table), function ($blueprint) { $blueprint->dropIfExists(); })); } /** * Drop all tables from the database. * * @return void * * @throws \LogicException */ public function dropAllTables() { throw new LogicException('This database driver does not support dropping all tables.'); } /** * Drop all views from the database. * * @return void * * @throws \LogicException */ public function dropAllViews() { throw new LogicException('This database driver does not support dropping all views.'); } /** * Drop all types from the database. * * @return void * * @throws \LogicException */ public function dropAllTypes() { throw new LogicException('This database driver does not support dropping all types.'); } /** * Get all of the table names for the database. * * @return void * * @throws \LogicException */ public function getAllTables() { throw new LogicException('This database driver does not support getting all tables.'); } /** * Rename a table on the schema. * * @param string $from * @param string $to * @return void */ public function rename($from, $to) { $this->build(tap($this->createBlueprint($from), function ($blueprint) use ($to) { $blueprint->rename($to); })); } /** * Enable foreign key constraints. * * @return bool */ public function enableForeignKeyConstraints() { return $this->connection->statement( $this->grammar->compileEnableForeignKeyConstraints() ); } /** * Disable foreign key constraints. * * @return bool */ public function disableForeignKeyConstraints() { return $this->connection->statement( $this->grammar->compileDisableForeignKeyConstraints() ); } /** * Execute the blueprint to build / modify the table. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @return void */ protected function build(Blueprint $blueprint) { $blueprint->build($this->connection, $this->grammar); } /** * Create a new command set with a Closure. * * @param string $table * @param \Closure|null $callback * @return \Illuminate\Database\Schema\Blueprint */ protected function createBlueprint($table, Closure $callback = null) { $prefix = $this->connection->getConfig('prefix_indexes') ? $this->connection->getConfig('prefix') : ''; if (isset($this->resolver)) { return call_user_func($this->resolver, $table, $callback, $prefix); } return new Blueprint($table, $callback, $prefix); } /** * Register a custom Doctrine mapping type. * * @param string $class * @param string $name * @param string $type * @return void * * @throws \Doctrine\DBAL\DBALException * @throws \RuntimeException */ public function registerCustomDoctrineType($class, $name, $type) { if (! $this->connection->isDoctrineAvailable()) { throw new RuntimeException( 'Registering a custom Doctrine type requires Doctrine DBAL (doctrine/dbal).' ); } if (! Type::hasType($name)) { Type::addType($name, $class); $this->connection ->getDoctrineSchemaManager() ->getDatabasePlatform() ->registerDoctrineTypeMapping($type, $name); } } /** * Get the database connection instance. * * @return \Illuminate\Database\Connection */ public function getConnection() { return $this->connection; } /** * Set the database connection instance. * * @param \Illuminate\Database\Connection $connection * @return $this */ public function setConnection(Connection $connection) { $this->connection = $connection; return $this; } /** * Set the Schema Blueprint resolver callback. * * @param \Closure $resolver * @return void */ public function blueprintResolver(Closure $resolver) { $this->resolver = $resolver; } } database/Capsule/Manager.php 0000644 00000012400 14736103231 0011764 0 ustar 00 <?php namespace Illuminate\Database\Capsule; use Illuminate\Container\Container; use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Database\Connectors\ConnectionFactory; use Illuminate\Database\DatabaseManager; use Illuminate\Database\Eloquent\Model as Eloquent; use Illuminate\Support\Traits\CapsuleManagerTrait; use PDO; class Manager { use CapsuleManagerTrait; /** * The database manager instance. * * @var \Illuminate\Database\DatabaseManager */ protected $manager; /** * Create a new database capsule manager. * * @param \Illuminate\Container\Container|null $container * @return void */ public function __construct(Container $container = null) { $this->setupContainer($container ?: new Container); // Once we have the container setup, we will setup the default configuration // options in the container "config" binding. This will make the database // manager work correctly out of the box without extreme configuration. $this->setupDefaultConfiguration(); $this->setupManager(); } /** * Setup the default database configuration options. * * @return void */ protected function setupDefaultConfiguration() { $this->container['config']['database.fetch'] = PDO::FETCH_OBJ; $this->container['config']['database.default'] = 'default'; } /** * Build the database manager instance. * * @return void */ protected function setupManager() { $factory = new ConnectionFactory($this->container); $this->manager = new DatabaseManager($this->container, $factory); } /** * Get a connection instance from the global manager. * * @param string|null $connection * @return \Illuminate\Database\Connection */ public static function connection($connection = null) { return static::$instance->getConnection($connection); } /** * Get a fluent query builder instance. * * @param \Closure|\Illuminate\Database\Query\Builder|string $table * @param string|null $as * @param string|null $connection * @return \Illuminate\Database\Query\Builder */ public static function table($table, $as = null, $connection = null) { return static::$instance->connection($connection)->table($table, $as); } /** * Get a schema builder instance. * * @param string|null $connection * @return \Illuminate\Database\Schema\Builder */ public static function schema($connection = null) { return static::$instance->connection($connection)->getSchemaBuilder(); } /** * Get a registered connection instance. * * @param string|null $name * @return \Illuminate\Database\Connection */ public function getConnection($name = null) { return $this->manager->connection($name); } /** * Register a connection with the manager. * * @param array $config * @param string $name * @return void */ public function addConnection(array $config, $name = 'default') { $connections = $this->container['config']['database.connections']; $connections[$name] = $config; $this->container['config']['database.connections'] = $connections; } /** * Bootstrap Eloquent so it is ready for usage. * * @return void */ public function bootEloquent() { Eloquent::setConnectionResolver($this->manager); // If we have an event dispatcher instance, we will go ahead and register it // with the Eloquent ORM, allowing for model callbacks while creating and // updating "model" instances; however, it is not necessary to operate. if ($dispatcher = $this->getEventDispatcher()) { Eloquent::setEventDispatcher($dispatcher); } } /** * Set the fetch mode for the database connections. * * @param int $fetchMode * @return $this */ public function setFetchMode($fetchMode) { $this->container['config']['database.fetch'] = $fetchMode; return $this; } /** * Get the database manager instance. * * @return \Illuminate\Database\DatabaseManager */ public function getDatabaseManager() { return $this->manager; } /** * Get the current event dispatcher instance. * * @return \Illuminate\Contracts\Events\Dispatcher|null */ public function getEventDispatcher() { if ($this->container->bound('events')) { return $this->container['events']; } } /** * Set the event dispatcher instance to be used by connections. * * @param \Illuminate\Contracts\Events\Dispatcher $dispatcher * @return void */ public function setEventDispatcher(Dispatcher $dispatcher) { $this->container->instance('events', $dispatcher); } /** * Dynamically pass methods to the default connection. * * @param string $method * @param array $parameters * @return mixed */ public static function __callStatic($method, $parameters) { return static::connection()->$method(...$parameters); } } database/DatabaseServiceProvider.php 0000644 00000006344 14736103231 0013570 0 ustar 00 <?php namespace Illuminate\Database; use Faker\Factory as FakerFactory; use Faker\Generator as FakerGenerator; use Illuminate\Contracts\Queue\EntityResolver; use Illuminate\Database\Connectors\ConnectionFactory; use Illuminate\Database\Eloquent\Factory as EloquentFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\QueueEntityResolver; use Illuminate\Support\ServiceProvider; class DatabaseServiceProvider extends ServiceProvider { /** * The array of resolved Faker instances. * * @var array */ protected static $fakers = []; /** * Bootstrap the application events. * * @return void */ public function boot() { Model::setConnectionResolver($this->app['db']); Model::setEventDispatcher($this->app['events']); } /** * Register the service provider. * * @return void */ public function register() { Model::clearBootedModels(); $this->registerConnectionServices(); $this->registerEloquentFactory(); $this->registerQueueableEntityResolver(); } /** * Register the primary database bindings. * * @return void */ protected function registerConnectionServices() { // The connection factory is used to create the actual connection instances on // the database. We will inject the factory into the manager so that it may // make the connections while they are actually needed and not of before. $this->app->singleton('db.factory', function ($app) { return new ConnectionFactory($app); }); // The database manager is used to resolve various connections, since multiple // connections might be managed. It also implements the connection resolver // interface which may be used by other components requiring connections. $this->app->singleton('db', function ($app) { return new DatabaseManager($app, $app['db.factory']); }); $this->app->bind('db.connection', function ($app) { return $app['db']->connection(); }); } /** * Register the Eloquent factory instance in the container. * * @return void */ protected function registerEloquentFactory() { $this->app->singleton(FakerGenerator::class, function ($app, $parameters) { $locale = $parameters['locale'] ?? $app['config']->get('app.faker_locale', 'en_US'); if (! isset(static::$fakers[$locale])) { static::$fakers[$locale] = FakerFactory::create($locale); } static::$fakers[$locale]->unique(true); return static::$fakers[$locale]; }); $this->app->singleton(EloquentFactory::class, function ($app) { return EloquentFactory::construct( $app->make(FakerGenerator::class), $this->app->databasePath('factories') ); }); } /** * Register the queueable entity resolver implementation. * * @return void */ protected function registerQueueableEntityResolver() { $this->app->singleton(EntityResolver::class, function () { return new QueueEntityResolver; }); } } database/README.md 0000644 00000004260 14736103231 0007571 0 ustar 00 ## Illuminate Database The Illuminate Database component is a full database toolkit for PHP, providing an expressive query builder, ActiveRecord style ORM, and schema builder. It currently supports MySQL, Postgres, SQL Server, and SQLite. It also serves as the database layer of the Laravel PHP framework. ### Usage Instructions First, create a new "Capsule" manager instance. Capsule aims to make configuring the library for usage outside of the Laravel framework as easy as possible. ```PHP use Illuminate\Database\Capsule\Manager as Capsule; $capsule = new Capsule; $capsule->addConnection([ 'driver' => 'mysql', 'host' => 'localhost', 'database' => 'database', 'username' => 'root', 'password' => 'password', 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => '', ]); // Set the event dispatcher used by Eloquent models... (optional) use Illuminate\Events\Dispatcher; use Illuminate\Container\Container; $capsule->setEventDispatcher(new Dispatcher(new Container)); // Make this Capsule instance available globally via static methods... (optional) $capsule->setAsGlobal(); // Setup the Eloquent ORM... (optional; unless you've used setEventDispatcher()) $capsule->bootEloquent(); ``` > `composer require "illuminate/events"` required when you need to use observers with Eloquent. Once the Capsule instance has been registered. You may use it like so: **Using The Query Builder** ```PHP $users = Capsule::table('users')->where('votes', '>', 100)->get(); ``` Other core methods may be accessed directly from the Capsule in the same manner as from the DB facade: ```PHP $results = Capsule::select('select * from users where id = ?', [1]); ``` **Using The Schema Builder** ```PHP Capsule::schema()->create('users', function ($table) { $table->increments('id'); $table->string('email')->unique(); $table->timestamps(); }); ``` **Using The Eloquent ORM** ```PHP class User extends Illuminate\Database\Eloquent\Model {} $users = User::where('votes', '>', 1)->get(); ``` For further documentation on using the various database facilities this library provides, consult the [Laravel framework documentation](https://laravel.com/docs). database/PostgresConnection.php 0000644 00000004550 14736103231 0012653 0 ustar 00 <?php namespace Illuminate\Database; use Doctrine\DBAL\Driver\PDOPgSql\Driver as DoctrineDriver; use Illuminate\Database\Query\Grammars\PostgresGrammar as QueryGrammar; use Illuminate\Database\Query\Processors\PostgresProcessor; use Illuminate\Database\Schema\Grammars\PostgresGrammar as SchemaGrammar; use Illuminate\Database\Schema\PostgresBuilder; use PDO; class PostgresConnection extends Connection { /** * Bind values to their parameters in the given statement. * * @param \PDOStatement $statement * @param array $bindings * @return void */ public function bindValues($statement, $bindings) { foreach ($bindings as $key => $value) { if (is_int($value)) { $pdoParam = PDO::PARAM_INT; } elseif (is_resource($value)) { $pdoParam = PDO::PARAM_LOB; } else { $pdoParam = PDO::PARAM_STR; } $statement->bindValue( is_string($key) ? $key : $key + 1, $value, $pdoParam ); } } /** * Get the default query grammar instance. * * @return \Illuminate\Database\Query\Grammars\PostgresGrammar */ protected function getDefaultQueryGrammar() { return $this->withTablePrefix(new QueryGrammar); } /** * Get a schema builder instance for the connection. * * @return \Illuminate\Database\Schema\PostgresBuilder */ public function getSchemaBuilder() { if (is_null($this->schemaGrammar)) { $this->useDefaultSchemaGrammar(); } return new PostgresBuilder($this); } /** * Get the default schema grammar instance. * * @return \Illuminate\Database\Schema\Grammars\PostgresGrammar */ protected function getDefaultSchemaGrammar() { return $this->withTablePrefix(new SchemaGrammar); } /** * Get the default post processor instance. * * @return \Illuminate\Database\Query\Processors\PostgresProcessor */ protected function getDefaultPostProcessor() { return new PostgresProcessor; } /** * Get the Doctrine DBAL driver. * * @return \Doctrine\DBAL\Driver\PDOPgSql\Driver */ protected function getDoctrineDriver() { return new DoctrineDriver; } } database/DetectsLostConnections.php 0000644 00000003505 14736103231 0013464 0 ustar 00 <?php namespace Illuminate\Database; use Illuminate\Support\Str; use Throwable; trait DetectsLostConnections { /** * Determine if the given exception was caused by a lost connection. * * @param \Throwable $e * @return bool */ protected function causedByLostConnection(Throwable $e) { $message = $e->getMessage(); return Str::contains($message, [ 'server has gone away', 'no connection to the server', 'Lost connection', 'is dead or not enabled', 'Error while sending', 'decryption failed or bad record mac', 'server closed the connection unexpectedly', 'SSL connection has been closed unexpectedly', 'Error writing data to the connection', 'Resource deadlock avoided', 'Transaction() on null', 'child connection forced to terminate due to client_idle_limit', 'query_wait_timeout', 'reset by peer', 'Physical connection is not usable', 'TCP Provider: Error code 0x68', 'ORA-03114', 'Packets out of order. Expected', 'Adaptive Server connection failed', 'Communication link failure', 'connection is no longer usable', 'Login timeout expired', 'Connection refused', 'running with the --read-only option so it cannot execute this statement', 'The connection is broken and recovery is not possible. The connection is marked by the client driver as unrecoverable. No attempt was made to restore the connection.', 'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Try again', 'SQLSTATE[HY000]: General error: 7 SSL SYSCALL error: EOF detected', ]); } } database/SeedServiceProvider.php 0000644 00000002046 14736103231 0012737 0 ustar 00 <?php namespace Illuminate\Database; use Illuminate\Support\ServiceProvider; use Illuminate\Database\Console\Seeds\SeedCommand; class SeedServiceProvider extends ServiceProvider { /** * Indicates if loading of the provider is deferred. * * @var bool */ protected $defer = true; /** * Register the service provider. * * @return void */ public function register() { $this->app->singleton('seeder', function () { return new Seeder; }); $this->registerSeedCommand(); $this->commands('command.seed'); } /** * Register the seed console command. * * @return void */ protected function registerSeedCommand() { $this->app->singleton('command.seed', function ($app) { return new SeedCommand($app['db']); }); } /** * Get the services provided by the provider. * * @return array */ public function provides() { return ['seeder', 'command.seed']; } } database/Connectors/SQLiteConnector.php 0000644 00000002461 14736103231 0014155 0 ustar 00 <?php namespace Illuminate\Database\Connectors; use InvalidArgumentException; class SQLiteConnector extends Connector implements ConnectorInterface { /** * Establish a database connection. * * @param array $config * @return \PDO * * @throws \InvalidArgumentException */ public function connect(array $config) { $options = $this->getOptions($config); // SQLite supports "in-memory" databases that only last as long as the owning // connection does. These are useful for tests or for short lifetime store // querying. In-memory databases may only have a single open connection. if ($config['database'] === ':memory:') { return $this->createConnection('sqlite::memory:', $config, $options); } $path = realpath($config['database']); // Here we'll verify that the SQLite database exists before going any further // as the developer probably wants to know if the database exists and this // SQLite driver will not throw any exception if it does not by default. if ($path === false) { throw new InvalidArgumentException("Database ({$config['database']}) does not exist."); } return $this->createConnection("sqlite:{$path}", $config, $options); } } database/Connectors/ConnectorInterface.php 0000644 00000000360 14736103231 0014710 0 ustar 00 <?php namespace Illuminate\Database\Connectors; interface ConnectorInterface { /** * Establish a database connection. * * @param array $config * @return \PDO */ public function connect(array $config); } database/Connectors/SqlServerConnector.php 0000644 00000013054 14736103231 0014742 0 ustar 00 <?php namespace Illuminate\Database\Connectors; use Illuminate\Support\Arr; use PDO; class SqlServerConnector extends Connector implements ConnectorInterface { /** * The PDO connection options. * * @var array */ protected $options = [ PDO::ATTR_CASE => PDO::CASE_NATURAL, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL, PDO::ATTR_STRINGIFY_FETCHES => false, ]; /** * Establish a database connection. * * @param array $config * @return \PDO */ public function connect(array $config) { $options = $this->getOptions($config); return $this->createConnection($this->getDsn($config), $config, $options); } /** * Create a DSN string from a configuration. * * @param array $config * @return string */ protected function getDsn(array $config) { // First we will create the basic DSN setup as well as the port if it is in // in the configuration options. This will give us the basic DSN we will // need to establish the PDO connections and return them back for use. if ($this->prefersOdbc($config)) { return $this->getOdbcDsn($config); } if (in_array('sqlsrv', $this->getAvailableDrivers())) { return $this->getSqlSrvDsn($config); } else { return $this->getDblibDsn($config); } } /** * Determine if the database configuration prefers ODBC. * * @param array $config * @return bool */ protected function prefersOdbc(array $config) { return in_array('odbc', $this->getAvailableDrivers()) && ($config['odbc'] ?? null) === true; } /** * Get the DSN string for a DbLib connection. * * @param array $config * @return string */ protected function getDblibDsn(array $config) { return $this->buildConnectString('dblib', array_merge([ 'host' => $this->buildHostString($config, ':'), 'dbname' => $config['database'], ], Arr::only($config, ['appname', 'charset', 'version']))); } /** * Get the DSN string for an ODBC connection. * * @param array $config * @return string */ protected function getOdbcDsn(array $config) { return isset($config['odbc_datasource_name']) ? 'odbc:'.$config['odbc_datasource_name'] : ''; } /** * Get the DSN string for a SqlSrv connection. * * @param array $config * @return string */ protected function getSqlSrvDsn(array $config) { $arguments = [ 'Server' => $this->buildHostString($config, ','), ]; if (isset($config['database'])) { $arguments['Database'] = $config['database']; } if (isset($config['readonly'])) { $arguments['ApplicationIntent'] = 'ReadOnly'; } if (isset($config['pooling']) && $config['pooling'] === false) { $arguments['ConnectionPooling'] = '0'; } if (isset($config['appname'])) { $arguments['APP'] = $config['appname']; } if (isset($config['encrypt'])) { $arguments['Encrypt'] = $config['encrypt']; } if (isset($config['trust_server_certificate'])) { $arguments['TrustServerCertificate'] = $config['trust_server_certificate']; } if (isset($config['multiple_active_result_sets']) && $config['multiple_active_result_sets'] === false) { $arguments['MultipleActiveResultSets'] = 'false'; } if (isset($config['transaction_isolation'])) { $arguments['TransactionIsolation'] = $config['transaction_isolation']; } if (isset($config['multi_subnet_failover'])) { $arguments['MultiSubnetFailover'] = $config['multi_subnet_failover']; } if (isset($config['column_encryption'])) { $arguments['ColumnEncryption'] = $config['column_encryption']; } if (isset($config['key_store_authentication'])) { $arguments['KeyStoreAuthentication'] = $config['key_store_authentication']; } if (isset($config['key_store_principal_id'])) { $arguments['KeyStorePrincipalId'] = $config['key_store_principal_id']; } if (isset($config['key_store_secret'])) { $arguments['KeyStoreSecret'] = $config['key_store_secret']; } return $this->buildConnectString('sqlsrv', $arguments); } /** * Build a connection string from the given arguments. * * @param string $driver * @param array $arguments * @return string */ protected function buildConnectString($driver, array $arguments) { return $driver.':'.implode(';', array_map(function ($key) use ($arguments) { return sprintf('%s=%s', $key, $arguments[$key]); }, array_keys($arguments))); } /** * Build a host string from the given configuration. * * @param array $config * @param string $separator * @return string */ protected function buildHostString(array $config, $separator) { if (empty($config['port'])) { return $config['host']; } return $config['host'].$separator.$config['port']; } /** * Get the available PDO drivers. * * @return array */ protected function getAvailableDrivers() { return PDO::getAvailableDrivers(); } } database/Connectors/Connector.php 0000644 00000006545 14736103231 0013102 0 ustar 00 <?php namespace Illuminate\Database\Connectors; use Doctrine\DBAL\Driver\PDOConnection; use Exception; use Illuminate\Database\DetectsLostConnections; use PDO; use Throwable; class Connector { use DetectsLostConnections; /** * The default PDO connection options. * * @var array */ protected $options = [ PDO::ATTR_CASE => PDO::CASE_NATURAL, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL, PDO::ATTR_STRINGIFY_FETCHES => false, PDO::ATTR_EMULATE_PREPARES => false, ]; /** * Create a new PDO connection. * * @param string $dsn * @param array $config * @param array $options * @return \PDO * * @throws \Exception */ public function createConnection($dsn, array $config, array $options) { [$username, $password] = [ $config['username'] ?? null, $config['password'] ?? null, ]; try { return $this->createPdoConnection( $dsn, $username, $password, $options ); } catch (Exception $e) { return $this->tryAgainIfCausedByLostConnection( $e, $dsn, $username, $password, $options ); } } /** * Create a new PDO connection instance. * * @param string $dsn * @param string $username * @param string $password * @param array $options * @return \PDO */ protected function createPdoConnection($dsn, $username, $password, $options) { if (class_exists(PDOConnection::class) && ! $this->isPersistentConnection($options)) { return new PDOConnection($dsn, $username, $password, $options); } return new PDO($dsn, $username, $password, $options); } /** * Determine if the connection is persistent. * * @param array $options * @return bool */ protected function isPersistentConnection($options) { return isset($options[PDO::ATTR_PERSISTENT]) && $options[PDO::ATTR_PERSISTENT]; } /** * Handle an exception that occurred during connect execution. * * @param \Throwable $e * @param string $dsn * @param string $username * @param string $password * @param array $options * @return \PDO * * @throws \Exception */ protected function tryAgainIfCausedByLostConnection(Throwable $e, $dsn, $username, $password, $options) { if ($this->causedByLostConnection($e)) { return $this->createPdoConnection($dsn, $username, $password, $options); } throw $e; } /** * Get the PDO options based on the configuration. * * @param array $config * @return array */ public function getOptions(array $config) { $options = $config['options'] ?? []; return array_diff_key($this->options, $options) + $options; } /** * Get the default PDO connection options. * * @return array */ public function getDefaultOptions() { return $this->options; } /** * Set the default PDO connection options. * * @param array $options * @return void */ public function setDefaultOptions(array $options) { $this->options = $options; } } database/Connectors/ConnectionFactory.php 0000644 00000017556 14736103231 0014603 0 ustar 00 <?php namespace Illuminate\Database\Connectors; use Illuminate\Contracts\Container\Container; use Illuminate\Database\Connection; use Illuminate\Database\MySqlConnection; use Illuminate\Database\PostgresConnection; use Illuminate\Database\SQLiteConnection; use Illuminate\Database\SqlServerConnection; use Illuminate\Support\Arr; use InvalidArgumentException; use PDOException; class ConnectionFactory { /** * The IoC container instance. * * @var \Illuminate\Contracts\Container\Container */ protected $container; /** * Create a new connection factory instance. * * @param \Illuminate\Contracts\Container\Container $container * @return void */ public function __construct(Container $container) { $this->container = $container; } /** * Establish a PDO connection based on the configuration. * * @param array $config * @param string|null $name * @return \Illuminate\Database\Connection */ public function make(array $config, $name = null) { $config = $this->parseConfig($config, $name); if (isset($config['read'])) { return $this->createReadWriteConnection($config); } return $this->createSingleConnection($config); } /** * Parse and prepare the database configuration. * * @param array $config * @param string $name * @return array */ protected function parseConfig(array $config, $name) { return Arr::add(Arr::add($config, 'prefix', ''), 'name', $name); } /** * Create a single database connection instance. * * @param array $config * @return \Illuminate\Database\Connection */ protected function createSingleConnection(array $config) { $pdo = $this->createPdoResolver($config); return $this->createConnection( $config['driver'], $pdo, $config['database'], $config['prefix'], $config ); } /** * Create a read / write database connection instance. * * @param array $config * @return \Illuminate\Database\Connection */ protected function createReadWriteConnection(array $config) { $connection = $this->createSingleConnection($this->getWriteConfig($config)); return $connection->setReadPdo($this->createReadPdo($config)); } /** * Create a new PDO instance for reading. * * @param array $config * @return \Closure */ protected function createReadPdo(array $config) { return $this->createPdoResolver($this->getReadConfig($config)); } /** * Get the read configuration for a read / write connection. * * @param array $config * @return array */ protected function getReadConfig(array $config) { return $this->mergeReadWriteConfig( $config, $this->getReadWriteConfig($config, 'read') ); } /** * Get the write configuration for a read / write connection. * * @param array $config * @return array */ protected function getWriteConfig(array $config) { return $this->mergeReadWriteConfig( $config, $this->getReadWriteConfig($config, 'write') ); } /** * Get a read / write level configuration. * * @param array $config * @param string $type * @return array */ protected function getReadWriteConfig(array $config, $type) { return isset($config[$type][0]) ? Arr::random($config[$type]) : $config[$type]; } /** * Merge a configuration for a read / write connection. * * @param array $config * @param array $merge * @return array */ protected function mergeReadWriteConfig(array $config, array $merge) { return Arr::except(array_merge($config, $merge), ['read', 'write']); } /** * Create a new Closure that resolves to a PDO instance. * * @param array $config * @return \Closure */ protected function createPdoResolver(array $config) { return array_key_exists('host', $config) ? $this->createPdoResolverWithHosts($config) : $this->createPdoResolverWithoutHosts($config); } /** * Create a new Closure that resolves to a PDO instance with a specific host or an array of hosts. * * @param array $config * @return \Closure */ protected function createPdoResolverWithHosts(array $config) { return function () use ($config) { foreach (Arr::shuffle($hosts = $this->parseHosts($config)) as $key => $host) { $config['host'] = $host; try { return $this->createConnector($config)->connect($config); } catch (PDOException $e) { continue; } } throw $e; }; } /** * Parse the hosts configuration item into an array. * * @param array $config * @return array * * @throws \InvalidArgumentException */ protected function parseHosts(array $config) { $hosts = Arr::wrap($config['host']); if (empty($hosts)) { throw new InvalidArgumentException('Database hosts array is empty.'); } return $hosts; } /** * Create a new Closure that resolves to a PDO instance where there is no configured host. * * @param array $config * @return \Closure */ protected function createPdoResolverWithoutHosts(array $config) { return function () use ($config) { return $this->createConnector($config)->connect($config); }; } /** * Create a connector instance based on the configuration. * * @param array $config * @return \Illuminate\Database\Connectors\ConnectorInterface * * @throws \InvalidArgumentException */ public function createConnector(array $config) { if (! isset($config['driver'])) { throw new InvalidArgumentException('A driver must be specified.'); } if ($this->container->bound($key = "db.connector.{$config['driver']}")) { return $this->container->make($key); } switch ($config['driver']) { case 'mysql': return new MySqlConnector; case 'pgsql': return new PostgresConnector; case 'sqlite': return new SQLiteConnector; case 'sqlsrv': return new SqlServerConnector; } throw new InvalidArgumentException("Unsupported driver [{$config['driver']}]."); } /** * Create a new connection instance. * * @param string $driver * @param \PDO|\Closure $connection * @param string $database * @param string $prefix * @param array $config * @return \Illuminate\Database\Connection * * @throws \InvalidArgumentException */ protected function createConnection($driver, $connection, $database, $prefix = '', array $config = []) { if ($resolver = Connection::getResolver($driver)) { return $resolver($connection, $database, $prefix, $config); } switch ($driver) { case 'mysql': return new MySqlConnection($connection, $database, $prefix, $config); case 'pgsql': return new PostgresConnection($connection, $database, $prefix, $config); case 'sqlite': return new SQLiteConnection($connection, $database, $prefix, $config); case 'sqlsrv': return new SqlServerConnection($connection, $database, $prefix, $config); } throw new InvalidArgumentException("Unsupported driver [{$driver}]."); } } database/Connectors/PostgresConnector.php 0000644 00000011760 14736103231 0014624 0 ustar 00 <?php namespace Illuminate\Database\Connectors; use PDO; class PostgresConnector extends Connector implements ConnectorInterface { /** * The default PDO connection options. * * @var array */ protected $options = [ PDO::ATTR_CASE => PDO::CASE_NATURAL, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL, PDO::ATTR_STRINGIFY_FETCHES => false, ]; /** * Establish a database connection. * * @param array $config * @return \PDO */ public function connect(array $config) { // First we'll create the basic DSN and connection instance connecting to the // using the configuration option specified by the developer. We will also // set the default character set on the connections to UTF-8 by default. $connection = $this->createConnection( $this->getDsn($config), $config, $this->getOptions($config) ); $this->configureEncoding($connection, $config); // Next, we will check to see if a timezone has been specified in this config // and if it has we will issue a statement to modify the timezone with the // database. Setting this DB timezone is an optional configuration item. $this->configureTimezone($connection, $config); $this->configureSchema($connection, $config); // Postgres allows an application_name to be set by the user and this name is // used to when monitoring the application with pg_stat_activity. So we'll // determine if the option has been specified and run a statement if so. $this->configureApplicationName($connection, $config); return $connection; } /** * Set the connection character set and collation. * * @param \PDO $connection * @param array $config * @return void */ protected function configureEncoding($connection, $config) { if (! isset($config['charset'])) { return; } $connection->prepare("set names '{$config['charset']}'")->execute(); } /** * Set the timezone on the connection. * * @param \PDO $connection * @param array $config * @return void */ protected function configureTimezone($connection, array $config) { if (isset($config['timezone'])) { $timezone = $config['timezone']; $connection->prepare("set time zone '{$timezone}'")->execute(); } } /** * Set the schema on the connection. * * @param \PDO $connection * @param array $config * @return void */ protected function configureSchema($connection, $config) { if (isset($config['schema'])) { $schema = $this->formatSchema($config['schema']); $connection->prepare("set search_path to {$schema}")->execute(); } } /** * Format the schema for the DSN. * * @param array|string $schema * @return string */ protected function formatSchema($schema) { if (is_array($schema)) { return '"'.implode('", "', $schema).'"'; } return '"'.$schema.'"'; } /** * Set the schema on the connection. * * @param \PDO $connection * @param array $config * @return void */ protected function configureApplicationName($connection, $config) { if (isset($config['application_name'])) { $applicationName = $config['application_name']; $connection->prepare("set application_name to '$applicationName'")->execute(); } } /** * Create a DSN string from a configuration. * * @param array $config * @return string */ protected function getDsn(array $config) { // First we will create the basic DSN setup as well as the port if it is in // in the configuration options. This will give us the basic DSN we will // need to establish the PDO connections and return them back for use. extract($config, EXTR_SKIP); $host = isset($host) ? "host={$host};" : ''; $dsn = "pgsql:{$host}dbname={$database}"; // If a port was specified, we will add it to this Postgres DSN connections // format. Once we have done that we are ready to return this connection // string back out for usage, as this has been fully constructed here. if (isset($config['port'])) { $dsn .= ";port={$port}"; } return $this->addSslOptions($dsn, $config); } /** * Add the SSL options to the DSN. * * @param string $dsn * @param array $config * @return string */ protected function addSslOptions($dsn, array $config) { foreach (['sslmode', 'sslcert', 'sslkey', 'sslrootcert'] as $option) { if (isset($config[$option])) { $dsn .= ";{$option}={$config[$option]}"; } } return $dsn; } } database/Connectors/MySqlConnector.php 0000644 00000012567 14736103231 0014071 0 ustar 00 <?php namespace Illuminate\Database\Connectors; use PDO; class MySqlConnector extends Connector implements ConnectorInterface { /** * Establish a database connection. * * @param array $config * @return \PDO */ public function connect(array $config) { $dsn = $this->getDsn($config); $options = $this->getOptions($config); // We need to grab the PDO options that should be used while making the brand // new connection instance. The PDO options control various aspects of the // connection's behavior, and some might be specified by the developers. $connection = $this->createConnection($dsn, $config, $options); if (! empty($config['database'])) { $connection->exec("use `{$config['database']}`;"); } $this->configureEncoding($connection, $config); // Next, we will check to see if a timezone has been specified in this config // and if it has we will issue a statement to modify the timezone with the // database. Setting this DB timezone is an optional configuration item. $this->configureTimezone($connection, $config); $this->setModes($connection, $config); return $connection; } /** * Set the connection character set and collation. * * @param \PDO $connection * @param array $config * @return void */ protected function configureEncoding($connection, array $config) { if (! isset($config['charset'])) { return $connection; } $connection->prepare( "set names '{$config['charset']}'".$this->getCollation($config) )->execute(); } /** * Get the collation for the configuration. * * @param array $config * @return string */ protected function getCollation(array $config) { return isset($config['collation']) ? " collate '{$config['collation']}'" : ''; } /** * Set the timezone on the connection. * * @param \PDO $connection * @param array $config * @return void */ protected function configureTimezone($connection, array $config) { if (isset($config['timezone'])) { $connection->prepare('set time_zone="'.$config['timezone'].'"')->execute(); } } /** * Create a DSN string from a configuration. * * Chooses socket or host/port based on the 'unix_socket' config value. * * @param array $config * @return string */ protected function getDsn(array $config) { return $this->hasSocket($config) ? $this->getSocketDsn($config) : $this->getHostDsn($config); } /** * Determine if the given configuration array has a UNIX socket value. * * @param array $config * @return bool */ protected function hasSocket(array $config) { return isset($config['unix_socket']) && ! empty($config['unix_socket']); } /** * Get the DSN string for a socket configuration. * * @param array $config * @return string */ protected function getSocketDsn(array $config) { return "mysql:unix_socket={$config['unix_socket']};dbname={$config['database']}"; } /** * Get the DSN string for a host / port configuration. * * @param array $config * @return string */ protected function getHostDsn(array $config) { extract($config, EXTR_SKIP); return isset($port) ? "mysql:host={$host};port={$port};dbname={$database}" : "mysql:host={$host};dbname={$database}"; } /** * Set the modes for the connection. * * @param \PDO $connection * @param array $config * @return void */ protected function setModes(PDO $connection, array $config) { if (isset($config['modes'])) { $this->setCustomModes($connection, $config); } elseif (isset($config['strict'])) { if ($config['strict']) { $connection->prepare($this->strictMode($connection, $config))->execute(); } else { $connection->prepare("set session sql_mode='NO_ENGINE_SUBSTITUTION'")->execute(); } } } /** * Set the custom modes on the connection. * * @param \PDO $connection * @param array $config * @return void */ protected function setCustomModes(PDO $connection, array $config) { $modes = implode(',', $config['modes']); $connection->prepare("set session sql_mode='{$modes}'")->execute(); } /** * Get the query to enable strict mode. * * @param \PDO $connection * @param array $config * @return string */ protected function strictMode(PDO $connection, $config) { $version = $config['version'] ?? $connection->getAttribute(PDO::ATTR_SERVER_VERSION); if (version_compare($version, '8.0.11') >= 0) { return "set session sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'"; } return "set session sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'"; } } database/Seeder.php 0000644 00000006054 14736103231 0010235 0 ustar 00 <?php namespace Illuminate\Database; use Illuminate\Console\Command; use Illuminate\Container\Container; use Illuminate\Support\Arr; use InvalidArgumentException; abstract class Seeder { /** * The container instance. * * @var \Illuminate\Container\Container */ protected $container; /** * The console command instance. * * @var \Illuminate\Console\Command */ protected $command; /** * Seed the given connection from the given path. * * @param array|string $class * @param bool $silent * @return $this */ public function call($class, $silent = false) { $classes = Arr::wrap($class); foreach ($classes as $class) { $seeder = $this->resolve($class); $name = get_class($seeder); if ($silent === false && isset($this->command)) { $this->command->getOutput()->writeln("<comment>Seeding:</comment> {$name}"); } $startTime = microtime(true); $seeder->__invoke(); $runTime = round(microtime(true) - $startTime, 2); if ($silent === false && isset($this->command)) { $this->command->getOutput()->writeln("<info>Seeded:</info> {$name} ({$runTime} seconds)"); } } return $this; } /** * Silently seed the given connection from the given path. * * @param array|string $class * @return void */ public function callSilent($class) { $this->call($class, true); } /** * Resolve an instance of the given seeder class. * * @param string $class * @return \Illuminate\Database\Seeder */ protected function resolve($class) { if (isset($this->container)) { $instance = $this->container->make($class); $instance->setContainer($this->container); } else { $instance = new $class; } if (isset($this->command)) { $instance->setCommand($this->command); } return $instance; } /** * Set the IoC container instance. * * @param \Illuminate\Container\Container $container * @return $this */ public function setContainer(Container $container) { $this->container = $container; return $this; } /** * Set the console command instance. * * @param \Illuminate\Console\Command $command * @return $this */ public function setCommand(Command $command) { $this->command = $command; return $this; } /** * Run the database seeds. * * @return mixed * * @throws \InvalidArgumentException */ public function __invoke() { if (! method_exists($this, 'run')) { throw new InvalidArgumentException('Method [run] missing from '.get_class($this)); } return isset($this->container) ? $this->container->call([$this, 'run']) : $this->run(); } } database/QueryException.php 0000644 00000003137 14736103231 0012011 0 ustar 00 <?php namespace Illuminate\Database; use Illuminate\Support\Str; use PDOException; use Throwable; class QueryException extends PDOException { /** * The SQL for the query. * * @var string */ protected $sql; /** * The bindings for the query. * * @var array */ protected $bindings; /** * Create a new query exception instance. * * @param string $sql * @param array $bindings * @param \Throwable $previous * @return void */ public function __construct($sql, array $bindings, Throwable $previous) { parent::__construct('', 0, $previous); $this->sql = $sql; $this->bindings = $bindings; $this->code = $previous->getCode(); $this->message = $this->formatMessage($sql, $bindings, $previous); if ($previous instanceof PDOException) { $this->errorInfo = $previous->errorInfo; } } /** * Format the SQL error message. * * @param string $sql * @param array $bindings * @param \Throwable $previous * @return string */ protected function formatMessage($sql, $bindings, Throwable $previous) { return $previous->getMessage().' (SQL: '.Str::replaceArray('?', $bindings, $sql).')'; } /** * Get the SQL for the query. * * @return string */ public function getSql() { return $this->sql; } /** * Get the bindings for the query. * * @return array */ public function getBindings() { return $this->bindings; } } database/Concerns/BuildsQueries.php 0000644 00000014723 14736103231 0013362 0 ustar 00 <?php namespace Illuminate\Database\Concerns; use Illuminate\Container\Container; use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\Paginator; trait BuildsQueries { /** * Chunk the results of the query. * * @param int $count * @param callable $callback * @return bool */ public function chunk($count, callable $callback) { $this->enforceOrderBy(); $page = 1; do { // We'll execute the query for the given page and get the results. If there are // no results we can just break and return from here. When there are results // we will call the callback with the current chunk of these results here. $results = $this->forPage($page, $count)->get(); $countResults = $results->count(); if ($countResults == 0) { break; } // On each chunk result set, we will pass them to the callback and then let the // developer take care of everything within the callback, which allows us to // keep the memory low for spinning through large result sets for working. if ($callback($results, $page) === false) { return false; } unset($results); $page++; } while ($countResults == $count); return true; } /** * Execute a callback over each item while chunking. * * @param callable $callback * @param int $count * @return bool */ public function each(callable $callback, $count = 1000) { return $this->chunk($count, function ($results) use ($callback) { foreach ($results as $key => $value) { if ($callback($value, $key) === false) { return false; } } }); } /** * Chunk the results of a query by comparing IDs. * * @param int $count * @param callable $callback * @param string|null $column * @param string|null $alias * @return bool */ public function chunkById($count, callable $callback, $column = null, $alias = null) { $column = $column ?? $this->defaultKeyName(); $alias = $alias ?? $column; $lastId = null; do { $clone = clone $this; // We'll execute the query for the given page and get the results. If there are // no results we can just break and return from here. When there are results // we will call the callback with the current chunk of these results here. $results = $clone->forPageAfterId($count, $lastId, $column)->get(); $countResults = $results->count(); if ($countResults == 0) { break; } // On each chunk result set, we will pass them to the callback and then let the // developer take care of everything within the callback, which allows us to // keep the memory low for spinning through large result sets for working. if ($callback($results) === false) { return false; } $lastId = $results->last()->{$alias}; unset($results); } while ($countResults == $count); return true; } /** * Execute a callback over each item while chunking by id. * * @param callable $callback * @param int $count * @param string|null $column * @param string|null $alias * @return bool */ public function eachById(callable $callback, $count = 1000, $column = null, $alias = null) { return $this->chunkById($count, function ($results) use ($callback) { foreach ($results as $key => $value) { if ($callback($value, $key) === false) { return false; } } }, $column, $alias); } /** * Execute the query and get the first result. * * @param array|string $columns * @return \Illuminate\Database\Eloquent\Model|object|static|null */ public function first($columns = ['*']) { return $this->take(1)->get($columns)->first(); } /** * Apply the callback's query changes if the given "value" is true. * * @param mixed $value * @param callable $callback * @param callable|null $default * @return mixed|$this */ public function when($value, $callback, $default = null) { if ($value) { return $callback($this, $value) ?: $this; } elseif ($default) { return $default($this, $value) ?: $this; } return $this; } /** * Pass the query to a given callback. * * @param callable $callback * @return \Illuminate\Database\Query\Builder */ public function tap($callback) { return $this->when(true, $callback); } /** * Apply the callback's query changes if the given "value" is false. * * @param mixed $value * @param callable $callback * @param callable|null $default * @return mixed|$this */ public function unless($value, $callback, $default = null) { if (! $value) { return $callback($this, $value) ?: $this; } elseif ($default) { return $default($this, $value) ?: $this; } return $this; } /** * Create a new length-aware paginator instance. * * @param \Illuminate\Support\Collection $items * @param int $total * @param int $perPage * @param int $currentPage * @param array $options * @return \Illuminate\Pagination\LengthAwarePaginator */ protected function paginator($items, $total, $perPage, $currentPage, $options) { return Container::getInstance()->makeWith(LengthAwarePaginator::class, compact( 'items', 'total', 'perPage', 'currentPage', 'options' )); } /** * Create a new simple paginator instance. * * @param \Illuminate\Support\Collection $items * @param int $perPage * @param int $currentPage * @param array $options * @return \Illuminate\Pagination\Paginator */ protected function simplePaginator($items, $perPage, $currentPage, $options) { return Container::getInstance()->makeWith(Paginator::class, compact( 'items', 'perPage', 'currentPage', 'options' )); } } database/Concerns/ManagesTransactions.php 0000644 00000016703 14736103231 0014546 0 ustar 00 <?php namespace Illuminate\Database\Concerns; use Closure; use Throwable; trait ManagesTransactions { /** * Execute a Closure within a transaction. * * @param \Closure $callback * @param int $attempts * @return mixed * * @throws \Throwable */ public function transaction(Closure $callback, $attempts = 1) { for ($currentAttempt = 1; $currentAttempt <= $attempts; $currentAttempt++) { $this->beginTransaction(); // We'll simply execute the given callback within a try / catch block and if we // catch any exception we can rollback this transaction so that none of this // gets actually persisted to a database or stored in a permanent fashion. try { $callbackResult = $callback($this); } // If we catch an exception we'll rollback this transaction and try again if we // are not out of attempts. If we are out of attempts we will just throw the // exception back out and let the developer handle an uncaught exceptions. catch (Throwable $e) { $this->handleTransactionException( $e, $currentAttempt, $attempts ); continue; } try { $this->commit(); } catch (Throwable $e) { $this->handleCommitTransactionException( $e, $currentAttempt, $attempts ); continue; } return $callbackResult; } } /** * Handle an exception encountered when running a transacted statement. * * @param \Throwable $e * @param int $currentAttempt * @param int $maxAttempts * @return void * * @throws \Throwable */ protected function handleTransactionException(Throwable $e, $currentAttempt, $maxAttempts) { // On a deadlock, MySQL rolls back the entire transaction so we can't just // retry the query. We have to throw this exception all the way out and // let the developer handle it in another way. We will decrement too. if ($this->causedByConcurrencyError($e) && $this->transactions > 1) { $this->transactions--; throw $e; } // If there was an exception we will rollback this transaction and then we // can check if we have exceeded the maximum attempt count for this and // if we haven't we will return and try this query again in our loop. $this->rollBack(); if ($this->causedByConcurrencyError($e) && $currentAttempt < $maxAttempts) { return; } throw $e; } /** * Start a new database transaction. * * @return void * * @throws \Throwable */ public function beginTransaction() { $this->createTransaction(); $this->transactions++; $this->fireConnectionEvent('beganTransaction'); } /** * Create a transaction within the database. * * @return void * * @throws \Throwable */ protected function createTransaction() { if ($this->transactions == 0) { $this->reconnectIfMissingConnection(); try { $this->getPdo()->beginTransaction(); } catch (Throwable $e) { $this->handleBeginTransactionException($e); } } elseif ($this->transactions >= 1 && $this->queryGrammar->supportsSavepoints()) { $this->createSavepoint(); } } /** * Create a save point within the database. * * @return void * * @throws \Throwable */ protected function createSavepoint() { $this->getPdo()->exec( $this->queryGrammar->compileSavepoint('trans'.($this->transactions + 1)) ); } /** * Handle an exception from a transaction beginning. * * @param \Throwable $e * @return void * * @throws \Throwable */ protected function handleBeginTransactionException(Throwable $e) { if ($this->causedByLostConnection($e)) { $this->reconnect(); $this->getPdo()->beginTransaction(); } else { throw $e; } } /** * Commit the active database transaction. * * @return void * * @throws \Throwable */ public function commit() { if ($this->transactions == 1) { $this->getPdo()->commit(); } $this->transactions = max(0, $this->transactions - 1); $this->fireConnectionEvent('committed'); } /** * Handle an exception encountered when committing a transaction. * * @param \Throwable $e * @param int $currentAttempt * @param int $maxAttempts * @return void * * @throws \Throwable */ protected function handleCommitTransactionException(Throwable $e, $currentAttempt, $maxAttempts) { $this->transactions--; if ($this->causedByConcurrencyError($e) && $currentAttempt < $maxAttempts) { return; } if ($this->causedByLostConnection($e)) { $this->transactions = 0; } throw $e; } /** * Rollback the active database transaction. * * @param int|null $toLevel * @return void * * @throws \Throwable */ public function rollBack($toLevel = null) { // We allow developers to rollback to a certain transaction level. We will verify // that this given transaction level is valid before attempting to rollback to // that level. If it's not we will just return out and not attempt anything. $toLevel = is_null($toLevel) ? $this->transactions - 1 : $toLevel; if ($toLevel < 0 || $toLevel >= $this->transactions) { return; } // Next, we will actually perform this rollback within this database and fire the // rollback event. We will also set the current transaction level to the given // level that was passed into this method so it will be right from here out. try { $this->performRollBack($toLevel); } catch (Throwable $e) { $this->handleRollBackException($e); } $this->transactions = $toLevel; $this->fireConnectionEvent('rollingBack'); } /** * Perform a rollback within the database. * * @param int $toLevel * @return void * * @throws \Throwable */ protected function performRollBack($toLevel) { if ($toLevel == 0) { $this->getPdo()->rollBack(); } elseif ($this->queryGrammar->supportsSavepoints()) { $this->getPdo()->exec( $this->queryGrammar->compileSavepointRollBack('trans'.($toLevel + 1)) ); } } /** * Handle an exception from a rollback. * * @param \Throwable $e * @return void * * @throws \Throwable */ protected function handleRollBackException(Throwable $e) { if ($this->causedByLostConnection($e)) { $this->transactions = 0; } throw $e; } /** * Get the number of active transactions. * * @return int */ public function transactionLevel() { return $this->transactions; } } database/Query/JsonExpression.php 0000644 00000002637 14736103231 0013127 0 ustar 00 <?php namespace Illuminate\Database\Query; use InvalidArgumentException; class JsonExpression extends Expression { /** * The value of the expression. * * @var mixed */ protected $value; /** * Create a new raw query expression. * * @param mixed $value * @return void */ public function __construct($value) { $this->value = $this->getJsonBindingParameter($value); } /** * Translate the given value into the appropriate JSON binding parameter. * * @param mixed $value * @return string */ protected function getJsonBindingParameter($value) { switch ($type = gettype($value)) { case 'boolean': return $value ? 'true' : 'false'; case 'integer': case 'double': return $value; case 'string': return '?'; case 'object': case 'array': return '?'; } throw new InvalidArgumentException('JSON value is of illegal type: '.$type); } /** * Get the value of the expression. * * @return mixed */ public function getValue() { return $this->value; } /** * Get the value of the expression. * * @return string */ public function __toString() { return (string) $this->getValue(); } } database/Query/JoinClause.php 0000644 00000007064 14736103231 0012171 0 ustar 00 <?php namespace Illuminate\Database\Query; use Closure; class JoinClause extends Builder { /** * The type of join being performed. * * @var string */ public $type; /** * The table the join clause is joining to. * * @var string */ public $table; /** * The connection of the parent query builder. * * @var \Illuminate\Database\ConnectionInterface */ protected $parentConnection; /** * The grammar of the parent query builder. * * @var \Illuminate\Database\Query\Grammars\Grammar */ protected $parentGrammar; /** * The processor of the parent query builder. * * @var \Illuminate\Database\Query\Processors\Processor */ protected $parentProcessor; /** * The class name of the parent query builder. * * @var string */ protected $parentClass; /** * Create a new join clause instance. * * @param \Illuminate\Database\Query\Builder $parentQuery * @param string $type * @param string $table * @return void */ public function __construct(Builder $parentQuery, $type, $table) { $this->type = $type; $this->table = $table; $this->parentClass = get_class($parentQuery); $this->parentGrammar = $parentQuery->getGrammar(); $this->parentProcessor = $parentQuery->getProcessor(); $this->parentConnection = $parentQuery->getConnection(); parent::__construct( $this->parentConnection, $this->parentGrammar, $this->parentProcessor ); } /** * Add an "on" clause to the join. * * On clauses can be chained, e.g. * * $join->on('contacts.user_id', '=', 'users.id') * ->on('contacts.info_id', '=', 'info.id') * * will produce the following SQL: * * on `contacts`.`user_id` = `users`.`id` and `contacts`.`info_id` = `info`.`id` * * @param \Closure|string $first * @param string|null $operator * @param string|null $second * @param string $boolean * @return $this * * @throws \InvalidArgumentException */ public function on($first, $operator = null, $second = null, $boolean = 'and') { if ($first instanceof Closure) { return $this->whereNested($first, $boolean); } return $this->whereColumn($first, $operator, $second, $boolean); } /** * Add an "or on" clause to the join. * * @param \Closure|string $first * @param string|null $operator * @param string|null $second * @return \Illuminate\Database\Query\JoinClause */ public function orOn($first, $operator = null, $second = null) { return $this->on($first, $operator, $second, 'or'); } /** * Get a new instance of the join clause builder. * * @return \Illuminate\Database\Query\JoinClause */ public function newQuery() { return new static($this->newParentQuery(), $this->type, $this->table); } /** * Create a new query instance for sub-query. * * @return \Illuminate\Database\Query\Builder */ protected function forSubQuery() { return $this->newParentQuery()->newQuery(); } /** * Create a new parent query instance. * * @return \Illuminate\Database\Query\Builder */ protected function newParentQuery() { $class = $this->parentClass; return new $class($this->parentConnection, $this->parentGrammar, $this->parentProcessor); } } database/Query/Grammars/Grammar.php 0000644 00000103643 14736103231 0013274 0 ustar 00 <?php namespace Illuminate\Database\Query\Grammars; use Illuminate\Database\Grammar as BaseGrammar; use Illuminate\Database\Query\Builder; use Illuminate\Database\Query\JoinClause; use Illuminate\Support\Arr; use Illuminate\Support\Str; use RuntimeException; class Grammar extends BaseGrammar { /** * The grammar specific operators. * * @var array */ protected $operators = []; /** * The components that make up a select clause. * * @var array */ protected $selectComponents = [ 'aggregate', 'columns', 'from', 'joins', 'wheres', 'groups', 'havings', 'orders', 'limit', 'offset', 'lock', ]; /** * Compile a select query into SQL. * * @param \Illuminate\Database\Query\Builder $query * @return string */ public function compileSelect(Builder $query) { if ($query->unions && $query->aggregate) { return $this->compileUnionAggregate($query); } // If the query does not have any columns set, we'll set the columns to the // * character to just get all of the columns from the database. Then we // can build the query and concatenate all the pieces together as one. $original = $query->columns; if (is_null($query->columns)) { $query->columns = ['*']; } // To compile the query, we'll spin through each component of the query and // see if that component exists. If it does we'll just call the compiler // function for the component which is responsible for making the SQL. $sql = trim($this->concatenate( $this->compileComponents($query)) ); if ($query->unions) { $sql = $this->wrapUnion($sql).' '.$this->compileUnions($query); } $query->columns = $original; return $sql; } /** * Compile the components necessary for a select clause. * * @param \Illuminate\Database\Query\Builder $query * @return array */ protected function compileComponents(Builder $query) { $sql = []; foreach ($this->selectComponents as $component) { if (isset($query->$component)) { $method = 'compile'.ucfirst($component); $sql[$component] = $this->$method($query, $query->$component); } } return $sql; } /** * Compile an aggregated select clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $aggregate * @return string */ protected function compileAggregate(Builder $query, $aggregate) { $column = $this->columnize($aggregate['columns']); // If the query has a "distinct" constraint and we're not asking for all columns // we need to prepend "distinct" onto the column name so that the query takes // it into account when it performs the aggregating operations on the data. if (is_array($query->distinct)) { $column = 'distinct '.$this->columnize($query->distinct); } elseif ($query->distinct && $column !== '*') { $column = 'distinct '.$column; } return 'select '.$aggregate['function'].'('.$column.') as aggregate'; } /** * Compile the "select *" portion of the query. * * @param \Illuminate\Database\Query\Builder $query * @param array $columns * @return string|null */ protected function compileColumns(Builder $query, $columns) { // If the query is actually performing an aggregating select, we will let that // compiler handle the building of the select clauses, as it will need some // more syntax that is best handled by that function to keep things neat. if (! is_null($query->aggregate)) { return; } if ($query->distinct) { $select = 'select distinct '; } else { $select = 'select '; } return $select.$this->columnize($columns); } /** * Compile the "from" portion of the query. * * @param \Illuminate\Database\Query\Builder $query * @param string $table * @return string */ protected function compileFrom(Builder $query, $table) { return 'from '.$this->wrapTable($table); } /** * Compile the "join" portions of the query. * * @param \Illuminate\Database\Query\Builder $query * @param array $joins * @return string */ protected function compileJoins(Builder $query, $joins) { return collect($joins)->map(function ($join) use ($query) { $table = $this->wrapTable($join->table); $nestedJoins = is_null($join->joins) ? '' : ' '.$this->compileJoins($query, $join->joins); $tableAndNestedJoins = is_null($join->joins) ? $table : '('.$table.$nestedJoins.')'; return trim("{$join->type} join {$tableAndNestedJoins} {$this->compileWheres($join)}"); })->implode(' '); } /** * Compile the "where" portions of the query. * * @param \Illuminate\Database\Query\Builder $query * @return string */ protected function compileWheres(Builder $query) { // Each type of where clauses has its own compiler function which is responsible // for actually creating the where clauses SQL. This helps keep the code nice // and maintainable since each clause has a very small method that it uses. if (is_null($query->wheres)) { return ''; } // If we actually have some where clauses, we will strip off the first boolean // operator, which is added by the query builders for convenience so we can // avoid checking for the first clauses in each of the compilers methods. if (count($sql = $this->compileWheresToArray($query)) > 0) { return $this->concatenateWhereClauses($query, $sql); } return ''; } /** * Get an array of all the where clauses for the query. * * @param \Illuminate\Database\Query\Builder $query * @return array */ protected function compileWheresToArray($query) { return collect($query->wheres)->map(function ($where) use ($query) { return $where['boolean'].' '.$this->{"where{$where['type']}"}($query, $where); })->all(); } /** * Format the where clause statements into one string. * * @param \Illuminate\Database\Query\Builder $query * @param array $sql * @return string */ protected function concatenateWhereClauses($query, $sql) { $conjunction = $query instanceof JoinClause ? 'on' : 'where'; return $conjunction.' '.$this->removeLeadingBoolean(implode(' ', $sql)); } /** * Compile a raw where clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereRaw(Builder $query, $where) { return $where['sql']; } /** * Compile a basic where clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereBasic(Builder $query, $where) { $value = $this->parameter($where['value']); return $this->wrap($where['column']).' '.$where['operator'].' '.$value; } /** * Compile a "where in" clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereIn(Builder $query, $where) { if (! empty($where['values'])) { return $this->wrap($where['column']).' in ('.$this->parameterize($where['values']).')'; } return '0 = 1'; } /** * Compile a "where not in" clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereNotIn(Builder $query, $where) { if (! empty($where['values'])) { return $this->wrap($where['column']).' not in ('.$this->parameterize($where['values']).')'; } return '1 = 1'; } /** * Compile a "where not in raw" clause. * * For safety, whereIntegerInRaw ensures this method is only used with integer values. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereNotInRaw(Builder $query, $where) { if (! empty($where['values'])) { return $this->wrap($where['column']).' not in ('.implode(', ', $where['values']).')'; } return '1 = 1'; } /** * Compile a "where in raw" clause. * * For safety, whereIntegerInRaw ensures this method is only used with integer values. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereInRaw(Builder $query, $where) { if (! empty($where['values'])) { return $this->wrap($where['column']).' in ('.implode(', ', $where['values']).')'; } return '0 = 1'; } /** * Compile a "where null" clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereNull(Builder $query, $where) { return $this->wrap($where['column']).' is null'; } /** * Compile a "where not null" clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereNotNull(Builder $query, $where) { return $this->wrap($where['column']).' is not null'; } /** * Compile a "between" where clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereBetween(Builder $query, $where) { $between = $where['not'] ? 'not between' : 'between'; $min = $this->parameter(reset($where['values'])); $max = $this->parameter(end($where['values'])); return $this->wrap($where['column']).' '.$between.' '.$min.' and '.$max; } /** * Compile a "where date" clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereDate(Builder $query, $where) { return $this->dateBasedWhere('date', $query, $where); } /** * Compile a "where time" clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereTime(Builder $query, $where) { return $this->dateBasedWhere('time', $query, $where); } /** * Compile a "where day" clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereDay(Builder $query, $where) { return $this->dateBasedWhere('day', $query, $where); } /** * Compile a "where month" clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereMonth(Builder $query, $where) { return $this->dateBasedWhere('month', $query, $where); } /** * Compile a "where year" clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereYear(Builder $query, $where) { return $this->dateBasedWhere('year', $query, $where); } /** * Compile a date based where clause. * * @param string $type * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function dateBasedWhere($type, Builder $query, $where) { $value = $this->parameter($where['value']); return $type.'('.$this->wrap($where['column']).') '.$where['operator'].' '.$value; } /** * Compile a where clause comparing two columns.. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereColumn(Builder $query, $where) { return $this->wrap($where['first']).' '.$where['operator'].' '.$this->wrap($where['second']); } /** * Compile a nested where clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereNested(Builder $query, $where) { // Here we will calculate what portion of the string we need to remove. If this // is a join clause query, we need to remove the "on" portion of the SQL and // if it is a normal query we need to take the leading "where" of queries. $offset = $query instanceof JoinClause ? 3 : 6; return '('.substr($this->compileWheres($where['query']), $offset).')'; } /** * Compile a where condition with a sub-select. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereSub(Builder $query, $where) { $select = $this->compileSelect($where['query']); return $this->wrap($where['column']).' '.$where['operator']." ($select)"; } /** * Compile a where exists clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereExists(Builder $query, $where) { return 'exists ('.$this->compileSelect($where['query']).')'; } /** * Compile a where exists clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereNotExists(Builder $query, $where) { return 'not exists ('.$this->compileSelect($where['query']).')'; } /** * Compile a where row values condition. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereRowValues(Builder $query, $where) { $columns = $this->columnize($where['columns']); $values = $this->parameterize($where['values']); return '('.$columns.') '.$where['operator'].' ('.$values.')'; } /** * Compile a "where JSON boolean" clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereJsonBoolean(Builder $query, $where) { $column = $this->wrapJsonBooleanSelector($where['column']); $value = $this->wrapJsonBooleanValue( $this->parameter($where['value']) ); return $column.' '.$where['operator'].' '.$value; } /** * Compile a "where JSON contains" clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereJsonContains(Builder $query, $where) { $not = $where['not'] ? 'not ' : ''; return $not.$this->compileJsonContains( $where['column'], $this->parameter($where['value']) ); } /** * Compile a "JSON contains" statement into SQL. * * @param string $column * @param string $value * @return string * * @throws \RuntimeException */ protected function compileJsonContains($column, $value) { throw new RuntimeException('This database engine does not support JSON contains operations.'); } /** * Prepare the binding for a "JSON contains" statement. * * @param mixed $binding * @return string */ public function prepareBindingForJsonContains($binding) { return json_encode($binding); } /** * Compile a "where JSON length" clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereJsonLength(Builder $query, $where) { return $this->compileJsonLength( $where['column'], $where['operator'], $this->parameter($where['value']) ); } /** * Compile a "JSON length" statement into SQL. * * @param string $column * @param string $operator * @param string $value * @return string * * @throws \RuntimeException */ protected function compileJsonLength($column, $operator, $value) { throw new RuntimeException('This database engine does not support JSON length operations.'); } /** * Compile the "group by" portions of the query. * * @param \Illuminate\Database\Query\Builder $query * @param array $groups * @return string */ protected function compileGroups(Builder $query, $groups) { return 'group by '.$this->columnize($groups); } /** * Compile the "having" portions of the query. * * @param \Illuminate\Database\Query\Builder $query * @param array $havings * @return string */ protected function compileHavings(Builder $query, $havings) { $sql = implode(' ', array_map([$this, 'compileHaving'], $havings)); return 'having '.$this->removeLeadingBoolean($sql); } /** * Compile a single having clause. * * @param array $having * @return string */ protected function compileHaving(array $having) { // If the having clause is "raw", we can just return the clause straight away // without doing any more processing on it. Otherwise, we will compile the // clause into SQL based on the components that make it up from builder. if ($having['type'] === 'Raw') { return $having['boolean'].' '.$having['sql']; } elseif ($having['type'] === 'between') { return $this->compileHavingBetween($having); } return $this->compileBasicHaving($having); } /** * Compile a basic having clause. * * @param array $having * @return string */ protected function compileBasicHaving($having) { $column = $this->wrap($having['column']); $parameter = $this->parameter($having['value']); return $having['boolean'].' '.$column.' '.$having['operator'].' '.$parameter; } /** * Compile a "between" having clause. * * @param array $having * @return string */ protected function compileHavingBetween($having) { $between = $having['not'] ? 'not between' : 'between'; $column = $this->wrap($having['column']); $min = $this->parameter(head($having['values'])); $max = $this->parameter(last($having['values'])); return $having['boolean'].' '.$column.' '.$between.' '.$min.' and '.$max; } /** * Compile the "order by" portions of the query. * * @param \Illuminate\Database\Query\Builder $query * @param array $orders * @return string */ protected function compileOrders(Builder $query, $orders) { if (! empty($orders)) { return 'order by '.implode(', ', $this->compileOrdersToArray($query, $orders)); } return ''; } /** * Compile the query orders to an array. * * @param \Illuminate\Database\Query\Builder $query * @param array $orders * @return array */ protected function compileOrdersToArray(Builder $query, $orders) { return array_map(function ($order) { return $order['sql'] ?? $this->wrap($order['column']).' '.$order['direction']; }, $orders); } /** * Compile the random statement into SQL. * * @param string $seed * @return string */ public function compileRandom($seed) { return 'RANDOM()'; } /** * Compile the "limit" portions of the query. * * @param \Illuminate\Database\Query\Builder $query * @param int $limit * @return string */ protected function compileLimit(Builder $query, $limit) { return 'limit '.(int) $limit; } /** * Compile the "offset" portions of the query. * * @param \Illuminate\Database\Query\Builder $query * @param int $offset * @return string */ protected function compileOffset(Builder $query, $offset) { return 'offset '.(int) $offset; } /** * Compile the "union" queries attached to the main query. * * @param \Illuminate\Database\Query\Builder $query * @return string */ protected function compileUnions(Builder $query) { $sql = ''; foreach ($query->unions as $union) { $sql .= $this->compileUnion($union); } if (! empty($query->unionOrders)) { $sql .= ' '.$this->compileOrders($query, $query->unionOrders); } if (isset($query->unionLimit)) { $sql .= ' '.$this->compileLimit($query, $query->unionLimit); } if (isset($query->unionOffset)) { $sql .= ' '.$this->compileOffset($query, $query->unionOffset); } return ltrim($sql); } /** * Compile a single union statement. * * @param array $union * @return string */ protected function compileUnion(array $union) { $conjunction = $union['all'] ? ' union all ' : ' union '; return $conjunction.$this->wrapUnion($union['query']->toSql()); } /** * Wrap a union subquery in parentheses. * * @param string $sql * @return string */ protected function wrapUnion($sql) { return '('.$sql.')'; } /** * Compile a union aggregate query into SQL. * * @param \Illuminate\Database\Query\Builder $query * @return string */ protected function compileUnionAggregate(Builder $query) { $sql = $this->compileAggregate($query, $query->aggregate); $query->aggregate = null; return $sql.' from ('.$this->compileSelect($query).') as '.$this->wrapTable('temp_table'); } /** * Compile an exists statement into SQL. * * @param \Illuminate\Database\Query\Builder $query * @return string */ public function compileExists(Builder $query) { $select = $this->compileSelect($query); return "select exists({$select}) as {$this->wrap('exists')}"; } /** * Compile an insert statement into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param array $values * @return string */ public function compileInsert(Builder $query, array $values) { // Essentially we will force every insert to be treated as a batch insert which // simply makes creating the SQL easier for us since we can utilize the same // basic routine regardless of an amount of records given to us to insert. $table = $this->wrapTable($query->from); if (empty($values)) { return "insert into {$table} default values"; } if (! is_array(reset($values))) { $values = [$values]; } $columns = $this->columnize(array_keys(reset($values))); // We need to build a list of parameter place-holders of values that are bound // to the query. Each insert should have the exact same amount of parameter // bindings so we will loop through the record and parameterize them all. $parameters = collect($values)->map(function ($record) { return '('.$this->parameterize($record).')'; })->implode(', '); return "insert into $table ($columns) values $parameters"; } /** * Compile an insert ignore statement into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param array $values * @return string * * @throws \RuntimeException */ public function compileInsertOrIgnore(Builder $query, array $values) { throw new RuntimeException('This database engine does not support inserting while ignoring errors.'); } /** * Compile an insert and get ID statement into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param array $values * @param string $sequence * @return string */ public function compileInsertGetId(Builder $query, $values, $sequence) { return $this->compileInsert($query, $values); } /** * Compile an insert statement using a subquery into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param array $columns * @param string $sql * @return string */ public function compileInsertUsing(Builder $query, array $columns, string $sql) { return "insert into {$this->wrapTable($query->from)} ({$this->columnize($columns)}) $sql"; } /** * Compile an update statement into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param array $values * @return string */ public function compileUpdate(Builder $query, array $values) { $table = $this->wrapTable($query->from); $columns = $this->compileUpdateColumns($query, $values); $where = $this->compileWheres($query); return trim( isset($query->joins) ? $this->compileUpdateWithJoins($query, $table, $columns, $where) : $this->compileUpdateWithoutJoins($query, $table, $columns, $where) ); } /** * Compile the columns for an update statement. * * @param \Illuminate\Database\Query\Builder $query * @param array $values * @return string */ protected function compileUpdateColumns(Builder $query, array $values) { return collect($values)->map(function ($value, $key) { return $this->wrap($key).' = '.$this->parameter($value); })->implode(', '); } /** * Compile an update statement without joins into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param string $table * @param string $columns * @param string $where * @return string */ protected function compileUpdateWithoutJoins(Builder $query, $table, $columns, $where) { return "update {$table} set {$columns} {$where}"; } /** * Compile an update statement with joins into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param string $table * @param string $columns * @param string $where * @return string */ protected function compileUpdateWithJoins(Builder $query, $table, $columns, $where) { $joins = $this->compileJoins($query, $query->joins); return "update {$table} {$joins} set {$columns} {$where}"; } /** * Prepare the bindings for an update statement. * * @param array $bindings * @param array $values * @return array */ public function prepareBindingsForUpdate(array $bindings, array $values) { $cleanBindings = Arr::except($bindings, ['select', 'join']); return array_values( array_merge($bindings['join'], $values, Arr::flatten($cleanBindings)) ); } /** * Compile a delete statement into SQL. * * @param \Illuminate\Database\Query\Builder $query * @return string */ public function compileDelete(Builder $query) { $table = $this->wrapTable($query->from); $where = $this->compileWheres($query); return trim( isset($query->joins) ? $this->compileDeleteWithJoins($query, $table, $where) : $this->compileDeleteWithoutJoins($query, $table, $where) ); } /** * Compile a delete statement without joins into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param string $table * @param string $where * @return string */ protected function compileDeleteWithoutJoins(Builder $query, $table, $where) { return "delete from {$table} {$where}"; } /** * Compile a delete statement with joins into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param string $table * @param string $where * @return string */ protected function compileDeleteWithJoins(Builder $query, $table, $where) { $alias = last(explode(' as ', $table)); $joins = $this->compileJoins($query, $query->joins); return "delete {$alias} from {$table} {$joins} {$where}"; } /** * Prepare the bindings for a delete statement. * * @param array $bindings * @return array */ public function prepareBindingsForDelete(array $bindings) { return Arr::flatten( Arr::except($bindings, 'select') ); } /** * Compile a truncate table statement into SQL. * * @param \Illuminate\Database\Query\Builder $query * @return array */ public function compileTruncate(Builder $query) { return ['truncate table '.$this->wrapTable($query->from) => []]; } /** * Compile the lock into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param bool|string $value * @return string */ protected function compileLock(Builder $query, $value) { return is_string($value) ? $value : ''; } /** * Determine if the grammar supports savepoints. * * @return bool */ public function supportsSavepoints() { return true; } /** * Compile the SQL statement to define a savepoint. * * @param string $name * @return string */ public function compileSavepoint($name) { return 'SAVEPOINT '.$name; } /** * Compile the SQL statement to execute a savepoint rollback. * * @param string $name * @return string */ public function compileSavepointRollBack($name) { return 'ROLLBACK TO SAVEPOINT '.$name; } /** * Wrap a value in keyword identifiers. * * @param \Illuminate\Database\Query\Expression|string $value * @param bool $prefixAlias * @return string */ public function wrap($value, $prefixAlias = false) { if ($this->isExpression($value)) { return $this->getValue($value); } // If the value being wrapped has a column alias we will need to separate out // the pieces so we can wrap each of the segments of the expression on its // own, and then join these both back together using the "as" connector. if (stripos($value, ' as ') !== false) { return $this->wrapAliasedValue($value, $prefixAlias); } // If the given value is a JSON selector we will wrap it differently than a // traditional value. We will need to split this path and wrap each part // wrapped, etc. Otherwise, we will simply wrap the value as a string. if ($this->isJsonSelector($value)) { return $this->wrapJsonSelector($value); } return $this->wrapSegments(explode('.', $value)); } /** * Wrap the given JSON selector. * * @param string $value * @return string * * @throws \RuntimeException */ protected function wrapJsonSelector($value) { throw new RuntimeException('This database engine does not support JSON operations.'); } /** * Wrap the given JSON selector for boolean values. * * @param string $value * @return string */ protected function wrapJsonBooleanSelector($value) { return $this->wrapJsonSelector($value); } /** * Wrap the given JSON boolean value. * * @param string $value * @return string */ protected function wrapJsonBooleanValue($value) { return $value; } /** * Split the given JSON selector into the field and the optional path and wrap them separately. * * @param string $column * @return array */ protected function wrapJsonFieldAndPath($column) { $parts = explode('->', $column, 2); $field = $this->wrap($parts[0]); $path = count($parts) > 1 ? ', '.$this->wrapJsonPath($parts[1], '->') : ''; return [$field, $path]; } /** * Wrap the given JSON path. * * @param string $value * @param string $delimiter * @return string */ protected function wrapJsonPath($value, $delimiter = '->') { $value = preg_replace("/([\\\\]+)?\\'/", "\\'", $value); return '\'$."'.str_replace($delimiter, '"."', $value).'"\''; } /** * Determine if the given string is a JSON selector. * * @param string $value * @return bool */ protected function isJsonSelector($value) { return Str::contains($value, '->'); } /** * Concatenate an array of segments, removing empties. * * @param array $segments * @return string */ protected function concatenate($segments) { return implode(' ', array_filter($segments, function ($value) { return (string) $value !== ''; })); } /** * Remove the leading boolean from a statement. * * @param string $value * @return string */ protected function removeLeadingBoolean($value) { return preg_replace('/and |or /i', '', $value, 1); } /** * Get the grammar specific operators. * * @return array */ public function getOperators() { return $this->operators; } } database/Query/Grammars/SQLiteGrammar.php 0000644 00000020701 14736103231 0014347 0 ustar 00 <?php namespace Illuminate\Database\Query\Grammars; use Illuminate\Database\Query\Builder; use Illuminate\Support\Arr; use Illuminate\Support\Str; class SQLiteGrammar extends Grammar { /** * All of the available clause operators. * * @var array */ protected $operators = [ '=', '<', '>', '<=', '>=', '<>', '!=', 'like', 'not like', 'ilike', '&', '|', '<<', '>>', ]; /** * Compile the lock into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param bool|string $value * @return string */ protected function compileLock(Builder $query, $value) { return ''; } /** * Wrap a union subquery in parentheses. * * @param string $sql * @return string */ protected function wrapUnion($sql) { return 'select * from ('.$sql.')'; } /** * Compile a "where date" clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereDate(Builder $query, $where) { return $this->dateBasedWhere('%Y-%m-%d', $query, $where); } /** * Compile a "where day" clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereDay(Builder $query, $where) { return $this->dateBasedWhere('%d', $query, $where); } /** * Compile a "where month" clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereMonth(Builder $query, $where) { return $this->dateBasedWhere('%m', $query, $where); } /** * Compile a "where year" clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereYear(Builder $query, $where) { return $this->dateBasedWhere('%Y', $query, $where); } /** * Compile a "where time" clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereTime(Builder $query, $where) { return $this->dateBasedWhere('%H:%M:%S', $query, $where); } /** * Compile a date based where clause. * * @param string $type * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function dateBasedWhere($type, Builder $query, $where) { $value = $this->parameter($where['value']); return "strftime('{$type}', {$this->wrap($where['column'])}) {$where['operator']} cast({$value} as text)"; } /** * Compile a "JSON length" statement into SQL. * * @param string $column * @param string $operator * @param string $value * @return string */ protected function compileJsonLength($column, $operator, $value) { [$field, $path] = $this->wrapJsonFieldAndPath($column); return 'json_array_length('.$field.$path.') '.$operator.' '.$value; } /** * Compile an update statement into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param array $values * @return string */ public function compileUpdate(Builder $query, array $values) { if (isset($query->joins) || isset($query->limit)) { return $this->compileUpdateWithJoinsOrLimit($query, $values); } return parent::compileUpdate($query, $values); } /** * Compile an insert ignore statement into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param array $values * @return string */ public function compileInsertOrIgnore(Builder $query, array $values) { return Str::replaceFirst('insert', 'insert or ignore', $this->compileInsert($query, $values)); } /** * Compile the columns for an update statement. * * @param \Illuminate\Database\Query\Builder $query * @param array $values * @return string */ protected function compileUpdateColumns(Builder $query, array $values) { $jsonGroups = $this->groupJsonColumnsForUpdate($values); return collect($values)->reject(function ($value, $key) { return $this->isJsonSelector($key); })->merge($jsonGroups)->map(function ($value, $key) use ($jsonGroups) { $column = last(explode('.', $key)); $value = isset($jsonGroups[$key]) ? $this->compileJsonPatch($column, $value) : $this->parameter($value); return $this->wrap($column).' = '.$value; })->implode(', '); } /** * Group the nested JSON columns. * * @param array $values * @return array */ protected function groupJsonColumnsForUpdate(array $values) { $groups = []; foreach ($values as $key => $value) { if ($this->isJsonSelector($key)) { Arr::set($groups, str_replace('->', '.', Str::after($key, '.')), $value); } } return $groups; } /** * Compile a "JSON" patch statement into SQL. * * @param string $column * @param mixed $value * @return string */ protected function compileJsonPatch($column, $value) { return "json_patch(ifnull({$this->wrap($column)}, json('{}')), json({$this->parameter($value)}))"; } /** * Compile an update statement with joins or limit into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param array $values * @return string */ protected function compileUpdateWithJoinsOrLimit(Builder $query, array $values) { $table = $this->wrapTable($query->from); $columns = $this->compileUpdateColumns($query, $values); $alias = last(preg_split('/\s+as\s+/i', $query->from)); $selectSql = $this->compileSelect($query->select($alias.'.rowid')); return "update {$table} set {$columns} where {$this->wrap('rowid')} in ({$selectSql})"; } /** * Prepare the bindings for an update statement. * * @param array $bindings * @param array $values * @return array */ public function prepareBindingsForUpdate(array $bindings, array $values) { $groups = $this->groupJsonColumnsForUpdate($values); $values = collect($values)->reject(function ($value, $key) { return $this->isJsonSelector($key); })->merge($groups)->map(function ($value) { return is_array($value) ? json_encode($value) : $value; })->all(); $cleanBindings = Arr::except($bindings, 'select'); return array_values( array_merge($values, Arr::flatten($cleanBindings)) ); } /** * Compile a delete statement into SQL. * * @param \Illuminate\Database\Query\Builder $query * @return string */ public function compileDelete(Builder $query) { if (isset($query->joins) || isset($query->limit)) { return $this->compileDeleteWithJoinsOrLimit($query); } return parent::compileDelete($query); } /** * Compile a delete statement with joins or limit into SQL. * * @param \Illuminate\Database\Query\Builder $query * @return string */ protected function compileDeleteWithJoinsOrLimit(Builder $query) { $table = $this->wrapTable($query->from); $alias = last(preg_split('/\s+as\s+/i', $query->from)); $selectSql = $this->compileSelect($query->select($alias.'.rowid')); return "delete from {$table} where {$this->wrap('rowid')} in ({$selectSql})"; } /** * Compile a truncate table statement into SQL. * * @param \Illuminate\Database\Query\Builder $query * @return array */ public function compileTruncate(Builder $query) { return [ 'delete from sqlite_sequence where name = ?' => [$query->from], 'delete from '.$this->wrapTable($query->from) => [], ]; } /** * Wrap the given JSON selector. * * @param string $value * @return string */ protected function wrapJsonSelector($value) { [$field, $path] = $this->wrapJsonFieldAndPath($value); return 'json_extract('.$field.$path.')'; } } database/Query/Grammars/PostgresGrammar.php 0000644 00000025123 14736103231 0015017 0 ustar 00 <?php namespace Illuminate\Database\Query\Grammars; use Illuminate\Database\Query\Builder; use Illuminate\Support\Arr; use Illuminate\Support\Str; class PostgresGrammar extends Grammar { /** * All of the available clause operators. * * @var array */ protected $operators = [ '=', '<', '>', '<=', '>=', '<>', '!=', 'like', 'not like', 'between', 'ilike', 'not ilike', '~', '&', '|', '#', '<<', '>>', '<<=', '>>=', '&&', '@>', '<@', '?', '?|', '?&', '||', '-', '-', '#-', 'is distinct from', 'is not distinct from', ]; /** * {@inheritdoc} * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereBasic(Builder $query, $where) { if (Str::contains(strtolower($where['operator']), 'like')) { return sprintf( '%s::text %s %s', $this->wrap($where['column']), $where['operator'], $this->parameter($where['value']) ); } return parent::whereBasic($query, $where); } /** * Compile a "where date" clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereDate(Builder $query, $where) { $value = $this->parameter($where['value']); return $this->wrap($where['column']).'::date '.$where['operator'].' '.$value; } /** * Compile a "where time" clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereTime(Builder $query, $where) { $value = $this->parameter($where['value']); return $this->wrap($where['column']).'::time '.$where['operator'].' '.$value; } /** * Compile a date based where clause. * * @param string $type * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function dateBasedWhere($type, Builder $query, $where) { $value = $this->parameter($where['value']); return 'extract('.$type.' from '.$this->wrap($where['column']).') '.$where['operator'].' '.$value; } /** * Compile the "select *" portion of the query. * * @param \Illuminate\Database\Query\Builder $query * @param array $columns * @return string|null */ protected function compileColumns(Builder $query, $columns) { // If the query is actually performing an aggregating select, we will let that // compiler handle the building of the select clauses, as it will need some // more syntax that is best handled by that function to keep things neat. if (! is_null($query->aggregate)) { return; } if (is_array($query->distinct)) { $select = 'select distinct on ('.$this->columnize($query->distinct).') '; } elseif ($query->distinct) { $select = 'select distinct '; } else { $select = 'select '; } return $select.$this->columnize($columns); } /** * Compile a "JSON contains" statement into SQL. * * @param string $column * @param string $value * @return string */ protected function compileJsonContains($column, $value) { $column = str_replace('->>', '->', $this->wrap($column)); return '('.$column.')::jsonb @> '.$value; } /** * Compile a "JSON length" statement into SQL. * * @param string $column * @param string $operator * @param string $value * @return string */ protected function compileJsonLength($column, $operator, $value) { $column = str_replace('->>', '->', $this->wrap($column)); return 'json_array_length(('.$column.')::json) '.$operator.' '.$value; } /** * Compile the lock into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param bool|string $value * @return string */ protected function compileLock(Builder $query, $value) { if (! is_string($value)) { return $value ? 'for update' : 'for share'; } return $value; } /** * Compile an insert ignore statement into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param array $values * @return string */ public function compileInsertOrIgnore(Builder $query, array $values) { return $this->compileInsert($query, $values).' on conflict do nothing'; } /** * Compile an insert and get ID statement into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param array $values * @param string $sequence * @return string */ public function compileInsertGetId(Builder $query, $values, $sequence) { return $this->compileInsert($query, $values).' returning '.$this->wrap($sequence ?: 'id'); } /** * Compile an update statement into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param array $values * @return string */ public function compileUpdate(Builder $query, array $values) { if (isset($query->joins) || isset($query->limit)) { return $this->compileUpdateWithJoinsOrLimit($query, $values); } return parent::compileUpdate($query, $values); } /** * Compile the columns for an update statement. * * @param \Illuminate\Database\Query\Builder $query * @param array $values * @return string */ protected function compileUpdateColumns(Builder $query, array $values) { return collect($values)->map(function ($value, $key) { $column = last(explode('.', $key)); if ($this->isJsonSelector($key)) { return $this->compileJsonUpdateColumn($column, $value); } return $this->wrap($column).' = '.$this->parameter($value); })->implode(', '); } /** * Prepares a JSON column being updated using the JSONB_SET function. * * @param string $key * @param mixed $value * @return string */ protected function compileJsonUpdateColumn($key, $value) { $segments = explode('->', $key); $field = $this->wrap(array_shift($segments)); $path = '\'{"'.implode('","', $segments).'"}\''; return "{$field} = jsonb_set({$field}::jsonb, {$path}, {$this->parameter($value)})"; } /** * Compile an update statement with joins or limit into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param array $values * @return string */ protected function compileUpdateWithJoinsOrLimit(Builder $query, array $values) { $table = $this->wrapTable($query->from); $columns = $this->compileUpdateColumns($query, $values); $alias = last(preg_split('/\s+as\s+/i', $query->from)); $selectSql = $this->compileSelect($query->select($alias.'.ctid')); return "update {$table} set {$columns} where {$this->wrap('ctid')} in ({$selectSql})"; } /** * Prepare the bindings for an update statement. * * @param array $bindings * @param array $values * @return array */ public function prepareBindingsForUpdate(array $bindings, array $values) { $values = collect($values)->map(function ($value, $column) { return is_array($value) || ($this->isJsonSelector($column) && ! $this->isExpression($value)) ? json_encode($value) : $value; })->all(); $cleanBindings = Arr::except($bindings, 'select'); return array_values( array_merge($values, Arr::flatten($cleanBindings)) ); } /** * Compile a delete statement into SQL. * * @param \Illuminate\Database\Query\Builder $query * @return string */ public function compileDelete(Builder $query) { if (isset($query->joins) || isset($query->limit)) { return $this->compileDeleteWithJoinsOrLimit($query); } return parent::compileDelete($query); } /** * Compile a delete statement with joins or limit into SQL. * * @param \Illuminate\Database\Query\Builder $query * @return string */ protected function compileDeleteWithJoinsOrLimit(Builder $query) { $table = $this->wrapTable($query->from); $alias = last(preg_split('/\s+as\s+/i', $query->from)); $selectSql = $this->compileSelect($query->select($alias.'.ctid')); return "delete from {$table} where {$this->wrap('ctid')} in ({$selectSql})"; } /** * Compile a truncate table statement into SQL. * * @param \Illuminate\Database\Query\Builder $query * @return array */ public function compileTruncate(Builder $query) { return ['truncate '.$this->wrapTable($query->from).' restart identity cascade' => []]; } /** * Wrap the given JSON selector. * * @param string $value * @return string */ protected function wrapJsonSelector($value) { $path = explode('->', $value); $field = $this->wrapSegments(explode('.', array_shift($path))); $wrappedPath = $this->wrapJsonPathAttributes($path); $attribute = array_pop($wrappedPath); if (! empty($wrappedPath)) { return $field.'->'.implode('->', $wrappedPath).'->>'.$attribute; } return $field.'->>'.$attribute; } /** *Wrap the given JSON selector for boolean values. * * @param string $value * @return string */ protected function wrapJsonBooleanSelector($value) { $selector = str_replace( '->>', '->', $this->wrapJsonSelector($value) ); return '('.$selector.')::jsonb'; } /** * Wrap the given JSON boolean value. * * @param string $value * @return string */ protected function wrapJsonBooleanValue($value) { return "'".$value."'::jsonb"; } /** * Wrap the attributes of the give JSON path. * * @param array $path * @return array */ protected function wrapJsonPathAttributes($path) { return array_map(function ($attribute) { return filter_var($attribute, FILTER_VALIDATE_INT) !== false ? $attribute : "'$attribute'"; }, $path); } } database/Query/Grammars/MySqlGrammar.php 0000644 00000017242 14736103231 0014261 0 ustar 00 <?php namespace Illuminate\Database\Query\Grammars; use Illuminate\Database\Query\Builder; use Illuminate\Support\Str; class MySqlGrammar extends Grammar { /** * The grammar specific operators. * * @var array */ protected $operators = ['sounds like']; /** * Add a "where null" clause to the query. * * @param string|array $columns * @param string $boolean * @param bool $not * @return $this */ protected function whereNull(Builder $query, $where) { if ($this->isJsonSelector($where['column'])) { [$field, $path] = $this->wrapJsonFieldAndPath($where['column']); return '(json_extract('.$field.$path.') is null OR json_type(json_extract('.$field.$path.')) = \'NULL\')'; } return parent::whereNull($query, $where); } /** * Add a "where not null" clause to the query. * * @param string|array $columns * @param string $boolean * @return $this */ protected function whereNotNull(Builder $query, $where) { if ($this->isJsonSelector($where['column'])) { [$field, $path] = $this->wrapJsonFieldAndPath($where['column']); return '(json_extract('.$field.$path.') is not null AND json_type(json_extract('.$field.$path.')) != \'NULL\')'; } return parent::whereNotNull($query, $where); } /** * Compile an insert ignore statement into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param array $values * @return string */ public function compileInsertOrIgnore(Builder $query, array $values) { return Str::replaceFirst('insert', 'insert ignore', $this->compileInsert($query, $values)); } /** * Compile a "JSON contains" statement into SQL. * * @param string $column * @param string $value * @return string */ protected function compileJsonContains($column, $value) { [$field, $path] = $this->wrapJsonFieldAndPath($column); return 'json_contains('.$field.', '.$value.$path.')'; } /** * Compile a "JSON length" statement into SQL. * * @param string $column * @param string $operator * @param string $value * @return string */ protected function compileJsonLength($column, $operator, $value) { [$field, $path] = $this->wrapJsonFieldAndPath($column); return 'json_length('.$field.$path.') '.$operator.' '.$value; } /** * Compile the random statement into SQL. * * @param string $seed * @return string */ public function compileRandom($seed) { return 'RAND('.$seed.')'; } /** * Compile the lock into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param bool|string $value * @return string */ protected function compileLock(Builder $query, $value) { if (! is_string($value)) { return $value ? 'for update' : 'lock in share mode'; } return $value; } /** * Compile an insert statement into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param array $values * @return string */ public function compileInsert(Builder $query, array $values) { if (empty($values)) { $values = [[]]; } return parent::compileInsert($query, $values); } /** * Compile the columns for an update statement. * * @param \Illuminate\Database\Query\Builder $query * @param array $values * @return string */ protected function compileUpdateColumns(Builder $query, array $values) { return collect($values)->map(function ($value, $key) { if ($this->isJsonSelector($key)) { return $this->compileJsonUpdateColumn($key, $value); } return $this->wrap($key).' = '.$this->parameter($value); })->implode(', '); } /** * Prepare a JSON column being updated using the JSON_SET function. * * @param string $key * @param mixed $value * @return string */ protected function compileJsonUpdateColumn($key, $value) { if (is_bool($value)) { $value = $value ? 'true' : 'false'; } elseif (is_array($value)) { $value = 'cast(? as json)'; } else { $value = $this->parameter($value); } [$field, $path] = $this->wrapJsonFieldAndPath($key); return "{$field} = json_set({$field}{$path}, {$value})"; } /** * Compile an update statement without joins into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param string $table * @param string $columns * @param string $where * @return string */ protected function compileUpdateWithoutJoins(Builder $query, $table, $columns, $where) { $sql = parent::compileUpdateWithoutJoins($query, $table, $columns, $where); if (! empty($query->orders)) { $sql .= ' '.$this->compileOrders($query, $query->orders); } if (isset($query->limit)) { $sql .= ' '.$this->compileLimit($query, $query->limit); } return $sql; } /** * Prepare the bindings for an update statement. * * Booleans, integers, and doubles are inserted into JSON updates as raw values. * * @param array $bindings * @param array $values * @return array */ public function prepareBindingsForUpdate(array $bindings, array $values) { $values = collect($values)->reject(function ($value, $column) { return $this->isJsonSelector($column) && is_bool($value); })->map(function ($value) { return is_array($value) ? json_encode($value) : $value; })->all(); return parent::prepareBindingsForUpdate($bindings, $values); } /** * Compile a delete query that does not use joins. * * @param \Illuminate\Database\Query\Builder $query * @param string $table * @param string $where * @return string */ protected function compileDeleteWithoutJoins(Builder $query, $table, $where) { $sql = parent::compileDeleteWithoutJoins($query, $table, $where); // When using MySQL, delete statements may contain order by statements and limits // so we will compile both of those here. Once we have finished compiling this // we will return the completed SQL statement so it will be executed for us. if (! empty($query->orders)) { $sql .= ' '.$this->compileOrders($query, $query->orders); } if (isset($query->limit)) { $sql .= ' '.$this->compileLimit($query, $query->limit); } return $sql; } /** * Wrap a single string in keyword identifiers. * * @param string $value * @return string */ protected function wrapValue($value) { return $value === '*' ? $value : '`'.str_replace('`', '``', $value).'`'; } /** * Wrap the given JSON selector. * * @param string $value * @return string */ protected function wrapJsonSelector($value) { [$field, $path] = $this->wrapJsonFieldAndPath($value); return 'json_unquote(json_extract('.$field.$path.'))'; } /** * Wrap the given JSON selector for boolean values. * * @param string $value * @return string */ protected function wrapJsonBooleanSelector($value) { [$field, $path] = $this->wrapJsonFieldAndPath($value); return 'json_extract('.$field.$path.')'; } } database/Query/Grammars/SqlServerGrammar.php 0000644 00000027763 14736103231 0015153 0 ustar 00 <?php namespace Illuminate\Database\Query\Grammars; use Illuminate\Database\Query\Builder; use Illuminate\Support\Arr; use Illuminate\Support\Str; class SqlServerGrammar extends Grammar { /** * All of the available clause operators. * * @var array */ protected $operators = [ '=', '<', '>', '<=', '>=', '!<', '!>', '<>', '!=', 'like', 'not like', 'ilike', '&', '&=', '|', '|=', '^', '^=', ]; /** * Compile a select query into SQL. * * @param \Illuminate\Database\Query\Builder $query * @return string */ public function compileSelect(Builder $query) { if (! $query->offset) { return parent::compileSelect($query); } // If an offset is present on the query, we will need to wrap the query in // a big "ANSI" offset syntax block. This is very nasty compared to the // other database systems but is necessary for implementing features. if (is_null($query->columns)) { $query->columns = ['*']; } return $this->compileAnsiOffset( $query, $this->compileComponents($query) ); } /** * Compile the "select *" portion of the query. * * @param \Illuminate\Database\Query\Builder $query * @param array $columns * @return string|null */ protected function compileColumns(Builder $query, $columns) { if (! is_null($query->aggregate)) { return; } $select = $query->distinct ? 'select distinct ' : 'select '; // If there is a limit on the query, but not an offset, we will add the top // clause to the query, which serves as a "limit" type clause within the // SQL Server system similar to the limit keywords available in MySQL. if ($query->limit > 0 && $query->offset <= 0) { $select .= 'top '.$query->limit.' '; } return $select.$this->columnize($columns); } /** * Compile the "from" portion of the query. * * @param \Illuminate\Database\Query\Builder $query * @param string $table * @return string */ protected function compileFrom(Builder $query, $table) { $from = parent::compileFrom($query, $table); if (is_string($query->lock)) { return $from.' '.$query->lock; } if (! is_null($query->lock)) { return $from.' with(rowlock,'.($query->lock ? 'updlock,' : '').'holdlock)'; } return $from; } /** * Compile a "where date" clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereDate(Builder $query, $where) { $value = $this->parameter($where['value']); return 'cast('.$this->wrap($where['column']).' as date) '.$where['operator'].' '.$value; } /** * Compile a "where time" clause. * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string */ protected function whereTime(Builder $query, $where) { $value = $this->parameter($where['value']); return 'cast('.$this->wrap($where['column']).' as time) '.$where['operator'].' '.$value; } /** * Compile a "JSON contains" statement into SQL. * * @param string $column * @param string $value * @return string */ protected function compileJsonContains($column, $value) { [$field, $path] = $this->wrapJsonFieldAndPath($column); return $value.' in (select [value] from openjson('.$field.$path.'))'; } /** * Prepare the binding for a "JSON contains" statement. * * @param mixed $binding * @return string */ public function prepareBindingForJsonContains($binding) { return is_bool($binding) ? json_encode($binding) : $binding; } /** * Compile a "JSON length" statement into SQL. * * @param string $column * @param string $operator * @param string $value * @return string */ protected function compileJsonLength($column, $operator, $value) { [$field, $path] = $this->wrapJsonFieldAndPath($column); return '(select count(*) from openjson('.$field.$path.')) '.$operator.' '.$value; } /** * Create a full ANSI offset clause for the query. * * @param \Illuminate\Database\Query\Builder $query * @param array $components * @return string */ protected function compileAnsiOffset(Builder $query, $components) { // An ORDER BY clause is required to make this offset query work, so if one does // not exist we'll just create a dummy clause to trick the database and so it // does not complain about the queries for not having an "order by" clause. if (empty($components['orders'])) { $components['orders'] = 'order by (select 0)'; } // We need to add the row number to the query so we can compare it to the offset // and limit values given for the statements. So we will add an expression to // the "select" that will give back the row numbers on each of the records. $components['columns'] .= $this->compileOver($components['orders']); unset($components['orders']); // Next we need to calculate the constraints that should be placed on the query // to get the right offset and limit from our query but if there is no limit // set we will just handle the offset only since that is all that matters. $sql = $this->concatenate($components); return $this->compileTableExpression($sql, $query); } /** * Compile the over statement for a table expression. * * @param string $orderings * @return string */ protected function compileOver($orderings) { return ", row_number() over ({$orderings}) as row_num"; } /** * Compile a common table expression for a query. * * @param string $sql * @param \Illuminate\Database\Query\Builder $query * @return string */ protected function compileTableExpression($sql, $query) { $constraint = $this->compileRowConstraint($query); return "select * from ({$sql}) as temp_table where row_num {$constraint} order by row_num"; } /** * Compile the limit / offset row constraint for a query. * * @param \Illuminate\Database\Query\Builder $query * @return string */ protected function compileRowConstraint($query) { $start = $query->offset + 1; if ($query->limit > 0) { $finish = $query->offset + $query->limit; return "between {$start} and {$finish}"; } return ">= {$start}"; } /** * Compile a delete statement without joins into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param string $table * @param string $where * @return string */ protected function compileDeleteWithoutJoins(Builder $query, $table, $where) { $sql = parent::compileDeleteWithoutJoins($query, $table, $where); return ! is_null($query->limit) && $query->limit > 0 && $query->offset <= 0 ? Str::replaceFirst('delete', 'delete top ('.$query->limit.')', $sql) : $sql; } /** * Compile the random statement into SQL. * * @param string $seed * @return string */ public function compileRandom($seed) { return 'NEWID()'; } /** * Compile the "limit" portions of the query. * * @param \Illuminate\Database\Query\Builder $query * @param int $limit * @return string */ protected function compileLimit(Builder $query, $limit) { return ''; } /** * Compile the "offset" portions of the query. * * @param \Illuminate\Database\Query\Builder $query * @param int $offset * @return string */ protected function compileOffset(Builder $query, $offset) { return ''; } /** * Compile the lock into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param bool|string $value * @return string */ protected function compileLock(Builder $query, $value) { return ''; } /** * Wrap a union subquery in parentheses. * * @param string $sql * @return string */ protected function wrapUnion($sql) { return 'select * from ('.$sql.') as '.$this->wrapTable('temp_table'); } /** * Compile an exists statement into SQL. * * @param \Illuminate\Database\Query\Builder $query * @return string */ public function compileExists(Builder $query) { $existsQuery = clone $query; $existsQuery->columns = []; return $this->compileSelect($existsQuery->selectRaw('1 [exists]')->limit(1)); } /** * Compile an update statement with joins into SQL. * * @param \Illuminate\Database\Query\Builder $query * @param string $table * @param string $columns * @param string $where * @return string */ protected function compileUpdateWithJoins(Builder $query, $table, $columns, $where) { $alias = last(explode(' as ', $table)); $joins = $this->compileJoins($query, $query->joins); return "update {$alias} set {$columns} from {$table} {$joins} {$where}"; } /** * Prepare the bindings for an update statement. * * @param array $bindings * @param array $values * @return array */ public function prepareBindingsForUpdate(array $bindings, array $values) { $cleanBindings = Arr::except($bindings, 'select'); return array_values( array_merge($values, Arr::flatten($cleanBindings)) ); } /** * Compile the SQL statement to define a savepoint. * * @param string $name * @return string */ public function compileSavepoint($name) { return 'SAVE TRANSACTION '.$name; } /** * Compile the SQL statement to execute a savepoint rollback. * * @param string $name * @return string */ public function compileSavepointRollBack($name) { return 'ROLLBACK TRANSACTION '.$name; } /** * Get the format for database stored dates. * * @return string */ public function getDateFormat() { return 'Y-m-d H:i:s.v'; } /** * Wrap a single string in keyword identifiers. * * @param string $value * @return string */ protected function wrapValue($value) { return $value === '*' ? $value : '['.str_replace(']', ']]', $value).']'; } /** * Wrap the given JSON selector. * * @param string $value * @return string */ protected function wrapJsonSelector($value) { [$field, $path] = $this->wrapJsonFieldAndPath($value); return 'json_value('.$field.$path.')'; } /** * Wrap the given JSON boolean value. * * @param string $value * @return string */ protected function wrapJsonBooleanValue($value) { return "'".$value."'"; } /** * Wrap a table in keyword identifiers. * * @param \Illuminate\Database\Query\Expression|string $table * @return string */ public function wrapTable($table) { if (! $this->isExpression($table)) { return $this->wrapTableValuedFunction(parent::wrapTable($table)); } return $this->getValue($table); } /** * Wrap a table in keyword identifiers. * * @param string $table * @return string */ protected function wrapTableValuedFunction($table) { if (preg_match('/^(.+?)(\(.*?\))]$/', $table, $matches) === 1) { $table = $matches[1].']'.$matches[2]; } return $table; } } database/Query/Expression.php 0000644 00000001266 14736103231 0012272 0 ustar 00 <?php namespace Illuminate\Database\Query; class Expression { /** * The value of the expression. * * @var mixed */ protected $value; /** * Create a new raw query expression. * * @param mixed $value * @return void */ public function __construct($value) { $this->value = $value; } /** * Get the value of the expression. * * @return mixed */ public function getValue() { return $this->value; } /** * Get the value of the expression. * * @return string */ public function __toString() { return (string) $this->getValue(); } } database/Query/Processors/SQLiteProcessor.php 0000644 00000000625 14736103231 0015334 0 ustar 00 <?php namespace Illuminate\Database\Query\Processors; class SQLiteProcessor extends Processor { /** * Process the results of a column listing query. * * @param array $results * @return array */ public function processColumnListing($results) { return array_map(function ($result) { return ((object) $result)->name; }, $results); } } database/Query/Processors/PostgresProcessor.php 0000644 00000002032 14736103231 0015773 0 ustar 00 <?php namespace Illuminate\Database\Query\Processors; use Illuminate\Database\Query\Builder; class PostgresProcessor extends Processor { /** * Process an "insert get ID" query. * * @param \Illuminate\Database\Query\Builder $query * @param string $sql * @param array $values * @param string|null $sequence * @return int */ public function processInsertGetId(Builder $query, $sql, $values, $sequence = null) { $result = $query->getConnection()->selectFromWriteConnection($sql, $values)[0]; $sequence = $sequence ?: 'id'; $id = is_object($result) ? $result->{$sequence} : $result[$sequence]; return is_numeric($id) ? (int) $id : $id; } /** * Process the results of a column listing query. * * @param array $results * @return array */ public function processColumnListing($results) { return array_map(function ($result) { return ((object) $result)->column_name; }, $results); } } database/Query/Processors/Processor.php 0000644 00000002155 14736103231 0014252 0 ustar 00 <?php namespace Illuminate\Database\Query\Processors; use Illuminate\Database\Query\Builder; class Processor { /** * Process the results of a "select" query. * * @param \Illuminate\Database\Query\Builder $query * @param array $results * @return array */ public function processSelect(Builder $query, $results) { return $results; } /** * Process an "insert get ID" query. * * @param \Illuminate\Database\Query\Builder $query * @param string $sql * @param array $values * @param string|null $sequence * @return int */ public function processInsertGetId(Builder $query, $sql, $values, $sequence = null) { $query->getConnection()->insert($sql, $values); $id = $query->getConnection()->getPdo()->lastInsertId($sequence); return is_numeric($id) ? (int) $id : $id; } /** * Process the results of a column listing query. * * @param array $results * @return array */ public function processColumnListing($results) { return $results; } } database/Query/Processors/SqlServerProcessor.php 0000644 00000003435 14736103231 0016123 0 ustar 00 <?php namespace Illuminate\Database\Query\Processors; use Exception; use Illuminate\Database\Connection; use Illuminate\Database\Query\Builder; class SqlServerProcessor extends Processor { /** * Process an "insert get ID" query. * * @param \Illuminate\Database\Query\Builder $query * @param string $sql * @param array $values * @param string|null $sequence * @return int */ public function processInsertGetId(Builder $query, $sql, $values, $sequence = null) { $connection = $query->getConnection(); $connection->insert($sql, $values); if ($connection->getConfig('odbc') === true) { $id = $this->processInsertGetIdForOdbc($connection); } else { $id = $connection->getPdo()->lastInsertId(); } return is_numeric($id) ? (int) $id : $id; } /** * Process an "insert get ID" query for ODBC. * * @param \Illuminate\Database\Connection $connection * @return int * * @throws \Exception */ protected function processInsertGetIdForOdbc(Connection $connection) { $result = $connection->selectFromWriteConnection( 'SELECT CAST(COALESCE(SCOPE_IDENTITY(), @@IDENTITY) AS int) AS insertid' ); if (! $result) { throw new Exception('Unable to retrieve lastInsertID for ODBC.'); } $row = $result[0]; return is_object($row) ? $row->insertid : $row['insertid']; } /** * Process the results of a column listing query. * * @param array $results * @return array */ public function processColumnListing($results) { return array_map(function ($result) { return ((object) $result)->name; }, $results); } } database/Query/Processors/MySqlProcessor.php 0000644 00000000633 14736103231 0015237 0 ustar 00 <?php namespace Illuminate\Database\Query\Processors; class MySqlProcessor extends Processor { /** * Process the results of a column listing query. * * @param array $results * @return array */ public function processColumnListing($results) { return array_map(function ($result) { return ((object) $result)->column_name; }, $results); } } database/Query/Builder.php 0000644 00000252517 14736103231 0011530 0 ustar 00 <?php namespace Illuminate\Database\Query; use Closure; use DateTimeInterface; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Database\Concerns\BuildsQueries; use Illuminate\Database\ConnectionInterface; use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use Illuminate\Database\Query\Grammars\Grammar; use Illuminate\Database\Query\Processors\Processor; use Illuminate\Pagination\Paginator; use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\LazyCollection; use Illuminate\Support\Str; use Illuminate\Support\Traits\ForwardsCalls; use Illuminate\Support\Traits\Macroable; use InvalidArgumentException; use RuntimeException; class Builder { use BuildsQueries, ForwardsCalls, Macroable { __call as macroCall; } /** * The database connection instance. * * @var \Illuminate\Database\ConnectionInterface */ public $connection; /** * The database query grammar instance. * * @var \Illuminate\Database\Query\Grammars\Grammar */ public $grammar; /** * The database query post processor instance. * * @var \Illuminate\Database\Query\Processors\Processor */ public $processor; /** * The current query value bindings. * * @var array */ public $bindings = [ 'select' => [], 'from' => [], 'join' => [], 'where' => [], 'groupBy' => [], 'having' => [], 'order' => [], 'union' => [], 'unionOrder' => [], ]; /** * An aggregate function and column to be run. * * @var array */ public $aggregate; /** * The columns that should be returned. * * @var array */ public $columns; /** * Indicates if the query returns distinct results. * * Occasionally contains the columns that should be distinct. * * @var bool|array */ public $distinct = false; /** * The table which the query is targeting. * * @var string */ public $from; /** * The table joins for the query. * * @var array */ public $joins; /** * The where constraints for the query. * * @var array */ public $wheres = []; /** * The groupings for the query. * * @var array */ public $groups; /** * The having constraints for the query. * * @var array */ public $havings; /** * The orderings for the query. * * @var array */ public $orders; /** * The maximum number of records to return. * * @var int */ public $limit; /** * The number of records to skip. * * @var int */ public $offset; /** * The query union statements. * * @var array */ public $unions; /** * The maximum number of union records to return. * * @var int */ public $unionLimit; /** * The number of union records to skip. * * @var int */ public $unionOffset; /** * The orderings for the union query. * * @var array */ public $unionOrders; /** * Indicates whether row locking is being used. * * @var string|bool */ public $lock; /** * All of the available clause operators. * * @var array */ public $operators = [ '=', '<', '>', '<=', '>=', '<>', '!=', '<=>', 'like', 'like binary', 'not like', 'ilike', '&', '|', '^', '<<', '>>', 'rlike', 'not rlike', 'regexp', 'not regexp', '~', '~*', '!~', '!~*', 'similar to', 'not similar to', 'not ilike', '~~*', '!~~*', ]; /** * Whether use write pdo for select. * * @var bool */ public $useWritePdo = false; /** * Create a new query builder instance. * * @param \Illuminate\Database\ConnectionInterface $connection * @param \Illuminate\Database\Query\Grammars\Grammar|null $grammar * @param \Illuminate\Database\Query\Processors\Processor|null $processor * @return void */ public function __construct(ConnectionInterface $connection, Grammar $grammar = null, Processor $processor = null) { $this->connection = $connection; $this->grammar = $grammar ?: $connection->getQueryGrammar(); $this->processor = $processor ?: $connection->getPostProcessor(); } /** * Set the columns to be selected. * * @param array|mixed $columns * @return $this */ public function select($columns = ['*']) { $this->columns = []; $this->bindings['select'] = []; $columns = is_array($columns) ? $columns : func_get_args(); foreach ($columns as $as => $column) { if (is_string($as) && $this->isQueryable($column)) { $this->selectSub($column, $as); } else { $this->columns[] = $column; } } return $this; } /** * Add a subselect expression to the query. * * @param \Closure|\Illuminate\Database\Query\Builder|string $query * @param string $as * @return $this * * @throws \InvalidArgumentException */ public function selectSub($query, $as) { [$query, $bindings] = $this->createSub($query); return $this->selectRaw( '('.$query.') as '.$this->grammar->wrap($as), $bindings ); } /** * Add a new "raw" select expression to the query. * * @param string $expression * @param array $bindings * @return $this */ public function selectRaw($expression, array $bindings = []) { $this->addSelect(new Expression($expression)); if ($bindings) { $this->addBinding($bindings, 'select'); } return $this; } /** * Makes "from" fetch from a subquery. * * @param \Closure|\Illuminate\Database\Query\Builder|string $query * @param string $as * @return $this * * @throws \InvalidArgumentException */ public function fromSub($query, $as) { [$query, $bindings] = $this->createSub($query); return $this->fromRaw('('.$query.') as '.$this->grammar->wrapTable($as), $bindings); } /** * Add a raw from clause to the query. * * @param string $expression * @param mixed $bindings * @return $this */ public function fromRaw($expression, $bindings = []) { $this->from = new Expression($expression); $this->addBinding($bindings, 'from'); return $this; } /** * Creates a subquery and parse it. * * @param \Closure|\Illuminate\Database\Query\Builder|string $query * @return array */ protected function createSub($query) { // If the given query is a Closure, we will execute it while passing in a new // query instance to the Closure. This will give the developer a chance to // format and work with the query before we cast it to a raw SQL string. if ($query instanceof Closure) { $callback = $query; $callback($query = $this->forSubQuery()); } return $this->parseSub($query); } /** * Parse the subquery into SQL and bindings. * * @param mixed $query * @return array * * @throws \InvalidArgumentException */ protected function parseSub($query) { if ($query instanceof self || $query instanceof EloquentBuilder) { return [$query->toSql(), $query->getBindings()]; } elseif (is_string($query)) { return [$query, []]; } else { throw new InvalidArgumentException( 'A subquery must be a query builder instance, a Closure, or a string.' ); } } /** * Add a new select column to the query. * * @param array|mixed $column * @return $this */ public function addSelect($column) { $columns = is_array($column) ? $column : func_get_args(); foreach ($columns as $as => $column) { if (is_string($as) && $this->isQueryable($column)) { if (is_null($this->columns)) { $this->select($this->from.'.*'); } $this->selectSub($column, $as); } else { $this->columns[] = $column; } } return $this; } /** * Force the query to only return distinct results. * * @return $this */ public function distinct() { $columns = func_get_args(); if (count($columns) > 0) { $this->distinct = is_array($columns[0]) || is_bool($columns[0]) ? $columns[0] : $columns; } else { $this->distinct = true; } return $this; } /** * Set the table which the query is targeting. * * @param \Closure|\Illuminate\Database\Query\Builder|string $table * @param string|null $as * @return $this */ public function from($table, $as = null) { if ($this->isQueryable($table)) { return $this->fromSub($table, $as); } $this->from = $as ? "{$table} as {$as}" : $table; return $this; } /** * Add a join clause to the query. * * @param string $table * @param \Closure|string $first * @param string|null $operator * @param string|null $second * @param string $type * @param bool $where * @return $this */ public function join($table, $first, $operator = null, $second = null, $type = 'inner', $where = false) { $join = $this->newJoinClause($this, $type, $table); // If the first "column" of the join is really a Closure instance the developer // is trying to build a join with a complex "on" clause containing more than // one condition, so we'll add the join and call a Closure with the query. if ($first instanceof Closure) { $first($join); $this->joins[] = $join; $this->addBinding($join->getBindings(), 'join'); } // If the column is simply a string, we can assume the join simply has a basic // "on" clause with a single condition. So we will just build the join with // this simple join clauses attached to it. There is not a join callback. else { $method = $where ? 'where' : 'on'; $this->joins[] = $join->$method($first, $operator, $second); $this->addBinding($join->getBindings(), 'join'); } return $this; } /** * Add a "join where" clause to the query. * * @param string $table * @param \Closure|string $first * @param string $operator * @param string $second * @param string $type * @return $this */ public function joinWhere($table, $first, $operator, $second, $type = 'inner') { return $this->join($table, $first, $operator, $second, $type, true); } /** * Add a subquery join clause to the query. * * @param \Closure|\Illuminate\Database\Query\Builder|string $query * @param string $as * @param \Closure|string $first * @param string|null $operator * @param string|null $second * @param string $type * @param bool $where * @return $this * * @throws \InvalidArgumentException */ public function joinSub($query, $as, $first, $operator = null, $second = null, $type = 'inner', $where = false) { [$query, $bindings] = $this->createSub($query); $expression = '('.$query.') as '.$this->grammar->wrapTable($as); $this->addBinding($bindings, 'join'); return $this->join(new Expression($expression), $first, $operator, $second, $type, $where); } /** * Add a left join to the query. * * @param string $table * @param \Closure|string $first * @param string|null $operator * @param string|null $second * @return $this */ public function leftJoin($table, $first, $operator = null, $second = null) { return $this->join($table, $first, $operator, $second, 'left'); } /** * Add a "join where" clause to the query. * * @param string $table * @param \Closure|string $first * @param string $operator * @param string $second * @return $this */ public function leftJoinWhere($table, $first, $operator, $second) { return $this->joinWhere($table, $first, $operator, $second, 'left'); } /** * Add a subquery left join to the query. * * @param \Closure|\Illuminate\Database\Query\Builder|string $query * @param string $as * @param \Closure|string $first * @param string|null $operator * @param string|null $second * @return $this */ public function leftJoinSub($query, $as, $first, $operator = null, $second = null) { return $this->joinSub($query, $as, $first, $operator, $second, 'left'); } /** * Add a right join to the query. * * @param string $table * @param \Closure|string $first * @param string|null $operator * @param string|null $second * @return $this */ public function rightJoin($table, $first, $operator = null, $second = null) { return $this->join($table, $first, $operator, $second, 'right'); } /** * Add a "right join where" clause to the query. * * @param string $table * @param \Closure|string $first * @param string $operator * @param string $second * @return $this */ public function rightJoinWhere($table, $first, $operator, $second) { return $this->joinWhere($table, $first, $operator, $second, 'right'); } /** * Add a subquery right join to the query. * * @param \Closure|\Illuminate\Database\Query\Builder|string $query * @param string $as * @param \Closure|string $first * @param string|null $operator * @param string|null $second * @return $this */ public function rightJoinSub($query, $as, $first, $operator = null, $second = null) { return $this->joinSub($query, $as, $first, $operator, $second, 'right'); } /** * Add a "cross join" clause to the query. * * @param string $table * @param \Closure|string|null $first * @param string|null $operator * @param string|null $second * @return $this */ public function crossJoin($table, $first = null, $operator = null, $second = null) { if ($first) { return $this->join($table, $first, $operator, $second, 'cross'); } $this->joins[] = $this->newJoinClause($this, 'cross', $table); return $this; } /** * Get a new join clause. * * @param \Illuminate\Database\Query\Builder $parentQuery * @param string $type * @param string $table * @return \Illuminate\Database\Query\JoinClause */ protected function newJoinClause(self $parentQuery, $type, $table) { return new JoinClause($parentQuery, $type, $table); } /** * Merge an array of where clauses and bindings. * * @param array $wheres * @param array $bindings * @return void */ public function mergeWheres($wheres, $bindings) { $this->wheres = array_merge($this->wheres, (array) $wheres); $this->bindings['where'] = array_values( array_merge($this->bindings['where'], (array) $bindings) ); } /** * Add a basic where clause to the query. * * @param \Closure|string|array $column * @param mixed $operator * @param mixed $value * @param string $boolean * @return $this */ public function where($column, $operator = null, $value = null, $boolean = 'and') { // If the column is an array, we will assume it is an array of key-value pairs // and can add them each as a where clause. We will maintain the boolean we // received when the method was called and pass it into the nested where. if (is_array($column)) { return $this->addArrayOfWheres($column, $boolean); } // Here we will make some assumptions about the operator. If only 2 values are // passed to the method, we will assume that the operator is an equals sign // and keep going. Otherwise, we'll require the operator to be passed in. [$value, $operator] = $this->prepareValueAndOperator( $value, $operator, func_num_args() === 2 ); // If the columns is actually a Closure instance, we will assume the developer // wants to begin a nested where statement which is wrapped in parenthesis. // We'll add that Closure to the query then return back out immediately. if ($column instanceof Closure && is_null($operator)) { return $this->whereNested($column, $boolean); } // If the column is a Closure instance and there is an operator value, we will // assume the developer wants to run a subquery and then compare the result // of that subquery with the given value that was provided to the method. if ($this->isQueryable($column) && ! is_null($operator)) { [$sub, $bindings] = $this->createSub($column); return $this->addBinding($bindings, 'where') ->where(new Expression('('.$sub.')'), $operator, $value, $boolean); } // If the given operator is not found in the list of valid operators we will // assume that the developer is just short-cutting the '=' operators and // we will set the operators to '=' and set the values appropriately. if ($this->invalidOperator($operator)) { [$value, $operator] = [$operator, '=']; } // If the value is a Closure, it means the developer is performing an entire // sub-select within the query and we will need to compile the sub-select // within the where clause to get the appropriate query record results. if ($value instanceof Closure) { return $this->whereSub($column, $operator, $value, $boolean); } // If the value is "null", we will just assume the developer wants to add a // where null clause to the query. So, we will allow a short-cut here to // that method for convenience so the developer doesn't have to check. if (is_null($value)) { return $this->whereNull($column, $boolean, $operator !== '='); } $type = 'Basic'; // If the column is making a JSON reference we'll check to see if the value // is a boolean. If it is, we'll add the raw boolean string as an actual // value to the query to ensure this is properly handled by the query. if (Str::contains($column, '->') && is_bool($value)) { $value = new Expression($value ? 'true' : 'false'); if (is_string($column)) { $type = 'JsonBoolean'; } } // Now that we are working with just a simple query we can put the elements // in our array and add the query binding to our array of bindings that // will be bound to each SQL statements when it is finally executed. $this->wheres[] = compact( 'type', 'column', 'operator', 'value', 'boolean' ); if (! $value instanceof Expression) { $this->addBinding($value, 'where'); } return $this; } /** * Add an array of where clauses to the query. * * @param array $column * @param string $boolean * @param string $method * @return $this */ protected function addArrayOfWheres($column, $boolean, $method = 'where') { return $this->whereNested(function ($query) use ($column, $method, $boolean) { foreach ($column as $key => $value) { if (is_numeric($key) && is_array($value)) { $query->{$method}(...array_values($value)); } else { $query->$method($key, '=', $value, $boolean); } } }, $boolean); } /** * Prepare the value and operator for a where clause. * * @param string $value * @param string $operator * @param bool $useDefault * @return array * * @throws \InvalidArgumentException */ public function prepareValueAndOperator($value, $operator, $useDefault = false) { if ($useDefault) { return [$operator, '=']; } elseif ($this->invalidOperatorAndValue($operator, $value)) { throw new InvalidArgumentException('Illegal operator and value combination.'); } return [$value, $operator]; } /** * Determine if the given operator and value combination is legal. * * Prevents using Null values with invalid operators. * * @param string $operator * @param mixed $value * @return bool */ protected function invalidOperatorAndValue($operator, $value) { return is_null($value) && in_array($operator, $this->operators) && ! in_array($operator, ['=', '<>', '!=']); } /** * Determine if the given operator is supported. * * @param string $operator * @return bool */ protected function invalidOperator($operator) { return ! in_array(strtolower($operator), $this->operators, true) && ! in_array(strtolower($operator), $this->grammar->getOperators(), true); } /** * Add an "or where" clause to the query. * * @param \Closure|string|array $column * @param mixed $operator * @param mixed $value * @return $this */ public function orWhere($column, $operator = null, $value = null) { [$value, $operator] = $this->prepareValueAndOperator( $value, $operator, func_num_args() === 2 ); return $this->where($column, $operator, $value, 'or'); } /** * Add a "where" clause comparing two columns to the query. * * @param string|array $first * @param string|null $operator * @param string|null $second * @param string|null $boolean * @return $this */ public function whereColumn($first, $operator = null, $second = null, $boolean = 'and') { // If the column is an array, we will assume it is an array of key-value pairs // and can add them each as a where clause. We will maintain the boolean we // received when the method was called and pass it into the nested where. if (is_array($first)) { return $this->addArrayOfWheres($first, $boolean, 'whereColumn'); } // If the given operator is not found in the list of valid operators we will // assume that the developer is just short-cutting the '=' operators and // we will set the operators to '=' and set the values appropriately. if ($this->invalidOperator($operator)) { [$second, $operator] = [$operator, '=']; } // Finally, we will add this where clause into this array of clauses that we // are building for the query. All of them will be compiled via a grammar // once the query is about to be executed and run against the database. $type = 'Column'; $this->wheres[] = compact( 'type', 'first', 'operator', 'second', 'boolean' ); return $this; } /** * Add an "or where" clause comparing two columns to the query. * * @param string|array $first * @param string|null $operator * @param string|null $second * @return $this */ public function orWhereColumn($first, $operator = null, $second = null) { return $this->whereColumn($first, $operator, $second, 'or'); } /** * Add a raw where clause to the query. * * @param string $sql * @param mixed $bindings * @param string $boolean * @return $this */ public function whereRaw($sql, $bindings = [], $boolean = 'and') { $this->wheres[] = ['type' => 'raw', 'sql' => $sql, 'boolean' => $boolean]; $this->addBinding((array) $bindings, 'where'); return $this; } /** * Add a raw or where clause to the query. * * @param string $sql * @param mixed $bindings * @return $this */ public function orWhereRaw($sql, $bindings = []) { return $this->whereRaw($sql, $bindings, 'or'); } /** * Add a "where in" clause to the query. * * @param string $column * @param mixed $values * @param string $boolean * @param bool $not * @return $this */ public function whereIn($column, $values, $boolean = 'and', $not = false) { $type = $not ? 'NotIn' : 'In'; // If the value is a query builder instance we will assume the developer wants to // look for any values that exists within this given query. So we will add the // query accordingly so that this query is properly executed when it is run. if ($this->isQueryable($values)) { [$query, $bindings] = $this->createSub($values); $values = [new Expression($query)]; $this->addBinding($bindings, 'where'); } // Next, if the value is Arrayable we need to cast it to its raw array form so we // have the underlying array value instead of an Arrayable object which is not // able to be added as a binding, etc. We will then add to the wheres array. if ($values instanceof Arrayable) { $values = $values->toArray(); } $this->wheres[] = compact('type', 'column', 'values', 'boolean'); // Finally we'll add a binding for each values unless that value is an expression // in which case we will just skip over it since it will be the query as a raw // string and not as a parameterized place-holder to be replaced by the PDO. $this->addBinding($this->cleanBindings($values), 'where'); return $this; } /** * Add an "or where in" clause to the query. * * @param string $column * @param mixed $values * @return $this */ public function orWhereIn($column, $values) { return $this->whereIn($column, $values, 'or'); } /** * Add a "where not in" clause to the query. * * @param string $column * @param mixed $values * @param string $boolean * @return $this */ public function whereNotIn($column, $values, $boolean = 'and') { return $this->whereIn($column, $values, $boolean, true); } /** * Add an "or where not in" clause to the query. * * @param string $column * @param mixed $values * @return $this */ public function orWhereNotIn($column, $values) { return $this->whereNotIn($column, $values, 'or'); } /** * Add a "where in raw" clause for integer values to the query. * * @param string $column * @param \Illuminate\Contracts\Support\Arrayable|array $values * @param string $boolean * @param bool $not * @return $this */ public function whereIntegerInRaw($column, $values, $boolean = 'and', $not = false) { $type = $not ? 'NotInRaw' : 'InRaw'; if ($values instanceof Arrayable) { $values = $values->toArray(); } foreach ($values as &$value) { $value = (int) $value; } $this->wheres[] = compact('type', 'column', 'values', 'boolean'); return $this; } /** * Add an "or where in raw" clause for integer values to the query. * * @param string $column * @param \Illuminate\Contracts\Support\Arrayable|array $values * @return $this */ public function orWhereIntegerInRaw($column, $values) { return $this->whereIntegerInRaw($column, $values, 'or'); } /** * Add a "where not in raw" clause for integer values to the query. * * @param string $column * @param \Illuminate\Contracts\Support\Arrayable|array $values * @param string $boolean * @return $this */ public function whereIntegerNotInRaw($column, $values, $boolean = 'and') { return $this->whereIntegerInRaw($column, $values, $boolean, true); } /** * Add an "or where not in raw" clause for integer values to the query. * * @param string $column * @param \Illuminate\Contracts\Support\Arrayable|array $values * @return $this */ public function orWhereIntegerNotInRaw($column, $values) { return $this->whereIntegerNotInRaw($column, $values, 'or'); } /** * Add a "where null" clause to the query. * * @param string|array $columns * @param string $boolean * @param bool $not * @return $this */ public function whereNull($columns, $boolean = 'and', $not = false) { $type = $not ? 'NotNull' : 'Null'; foreach (Arr::wrap($columns) as $column) { $this->wheres[] = compact('type', 'column', 'boolean'); } return $this; } /** * Add an "or where null" clause to the query. * * @param string $column * @return $this */ public function orWhereNull($column) { return $this->whereNull($column, 'or'); } /** * Add a "where not null" clause to the query. * * @param string|array $columns * @param string $boolean * @return $this */ public function whereNotNull($columns, $boolean = 'and') { return $this->whereNull($columns, $boolean, true); } /** * Add a where between statement to the query. * * @param string $column * @param array $values * @param string $boolean * @param bool $not * @return $this */ public function whereBetween($column, array $values, $boolean = 'and', $not = false) { $type = 'between'; $this->wheres[] = compact('type', 'column', 'values', 'boolean', 'not'); $this->addBinding($this->cleanBindings($values), 'where'); return $this; } /** * Add an or where between statement to the query. * * @param string $column * @param array $values * @return $this */ public function orWhereBetween($column, array $values) { return $this->whereBetween($column, $values, 'or'); } /** * Add a where not between statement to the query. * * @param string $column * @param array $values * @param string $boolean * @return $this */ public function whereNotBetween($column, array $values, $boolean = 'and') { return $this->whereBetween($column, $values, $boolean, true); } /** * Add an or where not between statement to the query. * * @param string $column * @param array $values * @return $this */ public function orWhereNotBetween($column, array $values) { return $this->whereNotBetween($column, $values, 'or'); } /** * Add an "or where not null" clause to the query. * * @param string $column * @return $this */ public function orWhereNotNull($column) { return $this->whereNotNull($column, 'or'); } /** * Add a "where date" statement to the query. * * @param string $column * @param string $operator * @param \DateTimeInterface|string|null $value * @param string $boolean * @return $this */ public function whereDate($column, $operator, $value = null, $boolean = 'and') { [$value, $operator] = $this->prepareValueAndOperator( $value, $operator, func_num_args() === 2 ); if ($value instanceof DateTimeInterface) { $value = $value->format('Y-m-d'); } return $this->addDateBasedWhere('Date', $column, $operator, $value, $boolean); } /** * Add an "or where date" statement to the query. * * @param string $column * @param string $operator * @param \DateTimeInterface|string|null $value * @return $this */ public function orWhereDate($column, $operator, $value = null) { [$value, $operator] = $this->prepareValueAndOperator( $value, $operator, func_num_args() === 2 ); return $this->whereDate($column, $operator, $value, 'or'); } /** * Add a "where time" statement to the query. * * @param string $column * @param string $operator * @param \DateTimeInterface|string|null $value * @param string $boolean * @return $this */ public function whereTime($column, $operator, $value = null, $boolean = 'and') { [$value, $operator] = $this->prepareValueAndOperator( $value, $operator, func_num_args() === 2 ); if ($value instanceof DateTimeInterface) { $value = $value->format('H:i:s'); } return $this->addDateBasedWhere('Time', $column, $operator, $value, $boolean); } /** * Add an "or where time" statement to the query. * * @param string $column * @param string $operator * @param \DateTimeInterface|string|null $value * @return $this */ public function orWhereTime($column, $operator, $value = null) { [$value, $operator] = $this->prepareValueAndOperator( $value, $operator, func_num_args() === 2 ); return $this->whereTime($column, $operator, $value, 'or'); } /** * Add a "where day" statement to the query. * * @param string $column * @param string $operator * @param \DateTimeInterface|string|null $value * @param string $boolean * @return $this */ public function whereDay($column, $operator, $value = null, $boolean = 'and') { [$value, $operator] = $this->prepareValueAndOperator( $value, $operator, func_num_args() === 2 ); if ($value instanceof DateTimeInterface) { $value = $value->format('d'); } if (! $value instanceof Expression) { $value = str_pad($value, 2, '0', STR_PAD_LEFT); } return $this->addDateBasedWhere('Day', $column, $operator, $value, $boolean); } /** * Add an "or where day" statement to the query. * * @param string $column * @param string $operator * @param \DateTimeInterface|string|null $value * @return $this */ public function orWhereDay($column, $operator, $value = null) { [$value, $operator] = $this->prepareValueAndOperator( $value, $operator, func_num_args() === 2 ); return $this->whereDay($column, $operator, $value, 'or'); } /** * Add a "where month" statement to the query. * * @param string $column * @param string $operator * @param \DateTimeInterface|string|null $value * @param string $boolean * @return $this */ public function whereMonth($column, $operator, $value = null, $boolean = 'and') { [$value, $operator] = $this->prepareValueAndOperator( $value, $operator, func_num_args() === 2 ); if ($value instanceof DateTimeInterface) { $value = $value->format('m'); } if (! $value instanceof Expression) { $value = str_pad($value, 2, '0', STR_PAD_LEFT); } return $this->addDateBasedWhere('Month', $column, $operator, $value, $boolean); } /** * Add an "or where month" statement to the query. * * @param string $column * @param string $operator * @param \DateTimeInterface|string|null $value * @return $this */ public function orWhereMonth($column, $operator, $value = null) { [$value, $operator] = $this->prepareValueAndOperator( $value, $operator, func_num_args() === 2 ); return $this->whereMonth($column, $operator, $value, 'or'); } /** * Add a "where year" statement to the query. * * @param string $column * @param string $operator * @param \DateTimeInterface|string|int|null $value * @param string $boolean * @return $this */ public function whereYear($column, $operator, $value = null, $boolean = 'and') { [$value, $operator] = $this->prepareValueAndOperator( $value, $operator, func_num_args() === 2 ); if ($value instanceof DateTimeInterface) { $value = $value->format('Y'); } return $this->addDateBasedWhere('Year', $column, $operator, $value, $boolean); } /** * Add an "or where year" statement to the query. * * @param string $column * @param string $operator * @param \DateTimeInterface|string|int|null $value * @return $this */ public function orWhereYear($column, $operator, $value = null) { [$value, $operator] = $this->prepareValueAndOperator( $value, $operator, func_num_args() === 2 ); return $this->whereYear($column, $operator, $value, 'or'); } /** * Add a date based (year, month, day, time) statement to the query. * * @param string $type * @param string $column * @param string $operator * @param mixed $value * @param string $boolean * @return $this */ protected function addDateBasedWhere($type, $column, $operator, $value, $boolean = 'and') { $this->wheres[] = compact('column', 'type', 'boolean', 'operator', 'value'); if (! $value instanceof Expression) { $this->addBinding($value, 'where'); } return $this; } /** * Add a nested where statement to the query. * * @param \Closure $callback * @param string $boolean * @return $this */ public function whereNested(Closure $callback, $boolean = 'and') { call_user_func($callback, $query = $this->forNestedWhere()); return $this->addNestedWhereQuery($query, $boolean); } /** * Create a new query instance for nested where condition. * * @return \Illuminate\Database\Query\Builder */ public function forNestedWhere() { return $this->newQuery()->from($this->from); } /** * Add another query builder as a nested where to the query builder. * * @param $this $query * @param string $boolean * @return $this */ public function addNestedWhereQuery($query, $boolean = 'and') { if (count($query->wheres)) { $type = 'Nested'; $this->wheres[] = compact('type', 'query', 'boolean'); $this->addBinding($query->getRawBindings()['where'], 'where'); } return $this; } /** * Add a full sub-select to the query. * * @param string $column * @param string $operator * @param \Closure $callback * @param string $boolean * @return $this */ protected function whereSub($column, $operator, Closure $callback, $boolean) { $type = 'Sub'; // Once we have the query instance we can simply execute it so it can add all // of the sub-select's conditions to itself, and then we can cache it off // in the array of where clauses for the "main" parent query instance. call_user_func($callback, $query = $this->forSubQuery()); $this->wheres[] = compact( 'type', 'column', 'operator', 'query', 'boolean' ); $this->addBinding($query->getBindings(), 'where'); return $this; } /** * Add an exists clause to the query. * * @param \Closure $callback * @param string $boolean * @param bool $not * @return $this */ public function whereExists(Closure $callback, $boolean = 'and', $not = false) { $query = $this->forSubQuery(); // Similar to the sub-select clause, we will create a new query instance so // the developer may cleanly specify the entire exists query and we will // compile the whole thing in the grammar and insert it into the SQL. call_user_func($callback, $query); return $this->addWhereExistsQuery($query, $boolean, $not); } /** * Add an or exists clause to the query. * * @param \Closure $callback * @param bool $not * @return $this */ public function orWhereExists(Closure $callback, $not = false) { return $this->whereExists($callback, 'or', $not); } /** * Add a where not exists clause to the query. * * @param \Closure $callback * @param string $boolean * @return $this */ public function whereNotExists(Closure $callback, $boolean = 'and') { return $this->whereExists($callback, $boolean, true); } /** * Add a where not exists clause to the query. * * @param \Closure $callback * @return $this */ public function orWhereNotExists(Closure $callback) { return $this->orWhereExists($callback, true); } /** * Add an exists clause to the query. * * @param \Illuminate\Database\Query\Builder $query * @param string $boolean * @param bool $not * @return $this */ public function addWhereExistsQuery(self $query, $boolean = 'and', $not = false) { $type = $not ? 'NotExists' : 'Exists'; $this->wheres[] = compact('type', 'query', 'boolean'); $this->addBinding($query->getBindings(), 'where'); return $this; } /** * Adds a where condition using row values. * * @param array $columns * @param string $operator * @param array $values * @param string $boolean * @return $this * * @throws \InvalidArgumentException */ public function whereRowValues($columns, $operator, $values, $boolean = 'and') { if (count($columns) !== count($values)) { throw new InvalidArgumentException('The number of columns must match the number of values'); } $type = 'RowValues'; $this->wheres[] = compact('type', 'columns', 'operator', 'values', 'boolean'); $this->addBinding($this->cleanBindings($values)); return $this; } /** * Adds a or where condition using row values. * * @param array $columns * @param string $operator * @param array $values * @return $this */ public function orWhereRowValues($columns, $operator, $values) { return $this->whereRowValues($columns, $operator, $values, 'or'); } /** * Add a "where JSON contains" clause to the query. * * @param string $column * @param mixed $value * @param string $boolean * @param bool $not * @return $this */ public function whereJsonContains($column, $value, $boolean = 'and', $not = false) { $type = 'JsonContains'; $this->wheres[] = compact('type', 'column', 'value', 'boolean', 'not'); if (! $value instanceof Expression) { $this->addBinding($this->grammar->prepareBindingForJsonContains($value)); } return $this; } /** * Add a "or where JSON contains" clause to the query. * * @param string $column * @param mixed $value * @return $this */ public function orWhereJsonContains($column, $value) { return $this->whereJsonContains($column, $value, 'or'); } /** * Add a "where JSON not contains" clause to the query. * * @param string $column * @param mixed $value * @param string $boolean * @return $this */ public function whereJsonDoesntContain($column, $value, $boolean = 'and') { return $this->whereJsonContains($column, $value, $boolean, true); } /** * Add a "or where JSON not contains" clause to the query. * * @param string $column * @param mixed $value * @return $this */ public function orWhereJsonDoesntContain($column, $value) { return $this->whereJsonDoesntContain($column, $value, 'or'); } /** * Add a "where JSON length" clause to the query. * * @param string $column * @param mixed $operator * @param mixed $value * @param string $boolean * @return $this */ public function whereJsonLength($column, $operator, $value = null, $boolean = 'and') { $type = 'JsonLength'; [$value, $operator] = $this->prepareValueAndOperator( $value, $operator, func_num_args() === 2 ); $this->wheres[] = compact('type', 'column', 'operator', 'value', 'boolean'); if (! $value instanceof Expression) { $this->addBinding($value); } return $this; } /** * Add a "or where JSON length" clause to the query. * * @param string $column * @param mixed $operator * @param mixed $value * @return $this */ public function orWhereJsonLength($column, $operator, $value = null) { [$value, $operator] = $this->prepareValueAndOperator( $value, $operator, func_num_args() === 2 ); return $this->whereJsonLength($column, $operator, $value, 'or'); } /** * Handles dynamic "where" clauses to the query. * * @param string $method * @param array $parameters * @return $this */ public function dynamicWhere($method, $parameters) { $finder = substr($method, 5); $segments = preg_split( '/(And|Or)(?=[A-Z])/', $finder, -1, PREG_SPLIT_DELIM_CAPTURE ); // The connector variable will determine which connector will be used for the // query condition. We will change it as we come across new boolean values // in the dynamic method strings, which could contain a number of these. $connector = 'and'; $index = 0; foreach ($segments as $segment) { // If the segment is not a boolean connector, we can assume it is a column's name // and we will add it to the query as a new constraint as a where clause, then // we can keep iterating through the dynamic method string's segments again. if ($segment !== 'And' && $segment !== 'Or') { $this->addDynamic($segment, $connector, $parameters, $index); $index++; } // Otherwise, we will store the connector so we know how the next where clause we // find in the query should be connected to the previous ones, meaning we will // have the proper boolean connector to connect the next where clause found. else { $connector = $segment; } } return $this; } /** * Add a single dynamic where clause statement to the query. * * @param string $segment * @param string $connector * @param array $parameters * @param int $index * @return void */ protected function addDynamic($segment, $connector, $parameters, $index) { // Once we have parsed out the columns and formatted the boolean operators we // are ready to add it to this query as a where clause just like any other // clause on the query. Then we'll increment the parameter index values. $bool = strtolower($connector); $this->where(Str::snake($segment), '=', $parameters[$index], $bool); } /** * Add a "group by" clause to the query. * * @param array|string ...$groups * @return $this */ public function groupBy(...$groups) { foreach ($groups as $group) { $this->groups = array_merge( (array) $this->groups, Arr::wrap($group) ); } return $this; } /** * Add a raw groupBy clause to the query. * * @param string $sql * @param array $bindings * @return $this */ public function groupByRaw($sql, array $bindings = []) { $this->groups[] = new Expression($sql); $this->addBinding($bindings, 'groupBy'); return $this; } /** * Add a "having" clause to the query. * * @param string $column * @param string|null $operator * @param string|null $value * @param string $boolean * @return $this */ public function having($column, $operator = null, $value = null, $boolean = 'and') { $type = 'Basic'; // Here we will make some assumptions about the operator. If only 2 values are // passed to the method, we will assume that the operator is an equals sign // and keep going. Otherwise, we'll require the operator to be passed in. [$value, $operator] = $this->prepareValueAndOperator( $value, $operator, func_num_args() === 2 ); // If the given operator is not found in the list of valid operators we will // assume that the developer is just short-cutting the '=' operators and // we will set the operators to '=' and set the values appropriately. if ($this->invalidOperator($operator)) { [$value, $operator] = [$operator, '=']; } $this->havings[] = compact('type', 'column', 'operator', 'value', 'boolean'); if (! $value instanceof Expression) { $this->addBinding($value, 'having'); } return $this; } /** * Add a "or having" clause to the query. * * @param string $column * @param string|null $operator * @param string|null $value * @return $this */ public function orHaving($column, $operator = null, $value = null) { [$value, $operator] = $this->prepareValueAndOperator( $value, $operator, func_num_args() === 2 ); return $this->having($column, $operator, $value, 'or'); } /** * Add a "having between " clause to the query. * * @param string $column * @param array $values * @param string $boolean * @param bool $not * @return $this */ public function havingBetween($column, array $values, $boolean = 'and', $not = false) { $type = 'between'; $this->havings[] = compact('type', 'column', 'values', 'boolean', 'not'); $this->addBinding($this->cleanBindings($values), 'having'); return $this; } /** * Add a raw having clause to the query. * * @param string $sql * @param array $bindings * @param string $boolean * @return $this */ public function havingRaw($sql, array $bindings = [], $boolean = 'and') { $type = 'Raw'; $this->havings[] = compact('type', 'sql', 'boolean'); $this->addBinding($bindings, 'having'); return $this; } /** * Add a raw or having clause to the query. * * @param string $sql * @param array $bindings * @return $this */ public function orHavingRaw($sql, array $bindings = []) { return $this->havingRaw($sql, $bindings, 'or'); } /** * Add an "order by" clause to the query. * * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Query\Expression|string $column * @param string $direction * @return $this * * @throws \InvalidArgumentException */ public function orderBy($column, $direction = 'asc') { if ($this->isQueryable($column)) { [$query, $bindings] = $this->createSub($column); $column = new Expression('('.$query.')'); $this->addBinding($bindings, $this->unions ? 'unionOrder' : 'order'); } $direction = strtolower($direction); if (! in_array($direction, ['asc', 'desc'], true)) { throw new InvalidArgumentException('Order direction must be "asc" or "desc".'); } $this->{$this->unions ? 'unionOrders' : 'orders'}[] = [ 'column' => $column, 'direction' => $direction, ]; return $this; } /** * Add a descending "order by" clause to the query. * * @param string $column * @return $this */ public function orderByDesc($column) { return $this->orderBy($column, 'desc'); } /** * Add an "order by" clause for a timestamp to the query. * * @param string $column * @return $this */ public function latest($column = 'created_at') { return $this->orderBy($column, 'desc'); } /** * Add an "order by" clause for a timestamp to the query. * * @param string $column * @return $this */ public function oldest($column = 'created_at') { return $this->orderBy($column, 'asc'); } /** * Put the query's results in random order. * * @param string $seed * @return $this */ public function inRandomOrder($seed = '') { return $this->orderByRaw($this->grammar->compileRandom($seed)); } /** * Add a raw "order by" clause to the query. * * @param string $sql * @param array $bindings * @return $this */ public function orderByRaw($sql, $bindings = []) { $type = 'Raw'; $this->{$this->unions ? 'unionOrders' : 'orders'}[] = compact('type', 'sql'); $this->addBinding($bindings, $this->unions ? 'unionOrder' : 'order'); return $this; } /** * Alias to set the "offset" value of the query. * * @param int $value * @return $this */ public function skip($value) { return $this->offset($value); } /** * Set the "offset" value of the query. * * @param int $value * @return $this */ public function offset($value) { $property = $this->unions ? 'unionOffset' : 'offset'; $this->$property = max(0, $value); return $this; } /** * Alias to set the "limit" value of the query. * * @param int $value * @return $this */ public function take($value) { return $this->limit($value); } /** * Set the "limit" value of the query. * * @param int $value * @return $this */ public function limit($value) { $property = $this->unions ? 'unionLimit' : 'limit'; if ($value >= 0) { $this->$property = $value; } return $this; } /** * Set the limit and offset for a given page. * * @param int $page * @param int $perPage * @return $this */ public function forPage($page, $perPage = 15) { return $this->offset(($page - 1) * $perPage)->limit($perPage); } /** * Constrain the query to the previous "page" of results before a given ID. * * @param int $perPage * @param int|null $lastId * @param string $column * @return $this */ public function forPageBeforeId($perPage = 15, $lastId = 0, $column = 'id') { $this->orders = $this->removeExistingOrdersFor($column); if (! is_null($lastId)) { $this->where($column, '<', $lastId); } return $this->orderBy($column, 'desc') ->limit($perPage); } /** * Constrain the query to the next "page" of results after a given ID. * * @param int $perPage * @param int|null $lastId * @param string $column * @return $this */ public function forPageAfterId($perPage = 15, $lastId = 0, $column = 'id') { $this->orders = $this->removeExistingOrdersFor($column); if (! is_null($lastId)) { $this->where($column, '>', $lastId); } return $this->orderBy($column, 'asc') ->limit($perPage); } /** * Remove all existing orders and optionally add a new order. * * @return $this */ public function reorder($column = null, $direction = 'asc') { $this->orders = null; $this->unionOrders = null; $this->bindings['order'] = []; $this->bindings['unionOrder'] = []; if ($column) { return $this->orderBy($column, $direction); } return $this; } /** * Get an array with all orders with a given column removed. * * @param string $column * @return array */ protected function removeExistingOrdersFor($column) { return Collection::make($this->orders) ->reject(function ($order) use ($column) { return isset($order['column']) ? $order['column'] === $column : false; })->values()->all(); } /** * Add a union statement to the query. * * @param \Illuminate\Database\Query\Builder|\Closure $query * @param bool $all * @return $this */ public function union($query, $all = false) { if ($query instanceof Closure) { call_user_func($query, $query = $this->newQuery()); } $this->unions[] = compact('query', 'all'); $this->addBinding($query->getBindings(), 'union'); return $this; } /** * Add a union all statement to the query. * * @param \Illuminate\Database\Query\Builder|\Closure $query * @return $this */ public function unionAll($query) { return $this->union($query, true); } /** * Lock the selected rows in the table. * * @param string|bool $value * @return $this */ public function lock($value = true) { $this->lock = $value; if (! is_null($this->lock)) { $this->useWritePdo(); } return $this; } /** * Lock the selected rows in the table for updating. * * @return \Illuminate\Database\Query\Builder */ public function lockForUpdate() { return $this->lock(true); } /** * Share lock the selected rows in the table. * * @return \Illuminate\Database\Query\Builder */ public function sharedLock() { return $this->lock(false); } /** * Get the SQL representation of the query. * * @return string */ public function toSql() { return $this->grammar->compileSelect($this); } /** * Execute a query for a single record by ID. * * @param int|string $id * @param array $columns * @return mixed|static */ public function find($id, $columns = ['*']) { return $this->where('id', '=', $id)->first($columns); } /** * Get a single column's value from the first result of a query. * * @param string $column * @return mixed */ public function value($column) { $result = (array) $this->first([$column]); return count($result) > 0 ? reset($result) : null; } /** * Execute the query as a "select" statement. * * @param array|string $columns * @return \Illuminate\Support\Collection */ public function get($columns = ['*']) { return collect($this->onceWithColumns(Arr::wrap($columns), function () { return $this->processor->processSelect($this, $this->runSelect()); })); } /** * Run the query as a "select" statement against the connection. * * @return array */ protected function runSelect() { return $this->connection->select( $this->toSql(), $this->getBindings(), ! $this->useWritePdo ); } /** * Paginate the given query into a simple paginator. * * @param int $perPage * @param array $columns * @param string $pageName * @param int|null $page * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator */ public function paginate($perPage = 15, $columns = ['*'], $pageName = 'page', $page = null) { $page = $page ?: Paginator::resolveCurrentPage($pageName); $total = $this->getCountForPagination(); $results = $total ? $this->forPage($page, $perPage)->get($columns) : collect(); return $this->paginator($results, $total, $perPage, $page, [ 'path' => Paginator::resolveCurrentPath(), 'pageName' => $pageName, ]); } /** * Get a paginator only supporting simple next and previous links. * * This is more efficient on larger data-sets, etc. * * @param int $perPage * @param array $columns * @param string $pageName * @param int|null $page * @return \Illuminate\Contracts\Pagination\Paginator */ public function simplePaginate($perPage = 15, $columns = ['*'], $pageName = 'page', $page = null) { $page = $page ?: Paginator::resolveCurrentPage($pageName); $this->offset(($page - 1) * $perPage)->limit($perPage + 1); return $this->simplePaginator($this->get($columns), $perPage, $page, [ 'path' => Paginator::resolveCurrentPath(), 'pageName' => $pageName, ]); } /** * Get the count of the total records for the paginator. * * @param array $columns * @return int */ public function getCountForPagination($columns = ['*']) { $results = $this->runPaginationCountQuery($columns); // Once we have run the pagination count query, we will get the resulting count and // take into account what type of query it was. When there is a group by we will // just return the count of the entire results set since that will be correct. if (! isset($results[0])) { return 0; } elseif (is_object($results[0])) { return (int) $results[0]->aggregate; } return (int) array_change_key_case((array) $results[0])['aggregate']; } /** * Run a pagination count query. * * @param array $columns * @return array */ protected function runPaginationCountQuery($columns = ['*']) { if ($this->groups || $this->havings) { $clone = $this->cloneForPaginationCount(); if (is_null($clone->columns) && ! empty($this->joins)) { $clone->select($this->from.'.*'); } return $this->newQuery() ->from(new Expression('('.$clone->toSql().') as '.$this->grammar->wrap('aggregate_table'))) ->mergeBindings($clone) ->setAggregate('count', $this->withoutSelectAliases($columns)) ->get()->all(); } $without = $this->unions ? ['orders', 'limit', 'offset'] : ['columns', 'orders', 'limit', 'offset']; return $this->cloneWithout($without) ->cloneWithoutBindings($this->unions ? ['order'] : ['select', 'order']) ->setAggregate('count', $this->withoutSelectAliases($columns)) ->get()->all(); } /** * Clone the existing query instance for usage in a pagination subquery. * * @return self */ protected function cloneForPaginationCount() { return $this->cloneWithout(['orders', 'limit', 'offset']) ->cloneWithoutBindings(['order']); } /** * Remove the column aliases since they will break count queries. * * @param array $columns * @return array */ protected function withoutSelectAliases(array $columns) { return array_map(function ($column) { return is_string($column) && ($aliasPosition = stripos($column, ' as ')) !== false ? substr($column, 0, $aliasPosition) : $column; }, $columns); } /** * Get a lazy collection for the given query. * * @return \Illuminate\Support\LazyCollection */ public function cursor() { if (is_null($this->columns)) { $this->columns = ['*']; } return new LazyCollection(function () { yield from $this->connection->cursor( $this->toSql(), $this->getBindings(), ! $this->useWritePdo ); }); } /** * Throw an exception if the query doesn't have an orderBy clause. * * @return void * * @throws \RuntimeException */ protected function enforceOrderBy() { if (empty($this->orders) && empty($this->unionOrders)) { throw new RuntimeException('You must specify an orderBy clause when using this function.'); } } /** * Get an array with the values of a given column. * * @param string $column * @param string|null $key * @return \Illuminate\Support\Collection */ public function pluck($column, $key = null) { // First, we will need to select the results of the query accounting for the // given columns / key. Once we have the results, we will be able to take // the results and get the exact data that was requested for the query. $queryResult = $this->onceWithColumns( is_null($key) ? [$column] : [$column, $key], function () { return $this->processor->processSelect( $this, $this->runSelect() ); } ); if (empty($queryResult)) { return collect(); } // If the columns are qualified with a table or have an alias, we cannot use // those directly in the "pluck" operations since the results from the DB // are only keyed by the column itself. We'll strip the table out here. $column = $this->stripTableForPluck($column); $key = $this->stripTableForPluck($key); return is_array($queryResult[0]) ? $this->pluckFromArrayColumn($queryResult, $column, $key) : $this->pluckFromObjectColumn($queryResult, $column, $key); } /** * Strip off the table name or alias from a column identifier. * * @param string $column * @return string|null */ protected function stripTableForPluck($column) { if (is_null($column)) { return $column; } $separator = strpos(strtolower($column), ' as ') !== false ? ' as ' : '\.'; return last(preg_split('~'.$separator.'~i', $column)); } /** * Retrieve column values from rows represented as objects. * * @param array $queryResult * @param string $column * @param string $key * @return \Illuminate\Support\Collection */ protected function pluckFromObjectColumn($queryResult, $column, $key) { $results = []; if (is_null($key)) { foreach ($queryResult as $row) { $results[] = $row->$column; } } else { foreach ($queryResult as $row) { $results[$row->$key] = $row->$column; } } return collect($results); } /** * Retrieve column values from rows represented as arrays. * * @param array $queryResult * @param string $column * @param string $key * @return \Illuminate\Support\Collection */ protected function pluckFromArrayColumn($queryResult, $column, $key) { $results = []; if (is_null($key)) { foreach ($queryResult as $row) { $results[] = $row[$column]; } } else { foreach ($queryResult as $row) { $results[$row[$key]] = $row[$column]; } } return collect($results); } /** * Concatenate values of a given column as a string. * * @param string $column * @param string $glue * @return string */ public function implode($column, $glue = '') { return $this->pluck($column)->implode($glue); } /** * Determine if any rows exist for the current query. * * @return bool */ public function exists() { $results = $this->connection->select( $this->grammar->compileExists($this), $this->getBindings(), ! $this->useWritePdo ); // If the results has rows, we will get the row and see if the exists column is a // boolean true. If there is no results for this query we will return false as // there are no rows for this query at all and we can return that info here. if (isset($results[0])) { $results = (array) $results[0]; return (bool) $results['exists']; } return false; } /** * Determine if no rows exist for the current query. * * @return bool */ public function doesntExist() { return ! $this->exists(); } /** * Execute the given callback if no rows exist for the current query. * * @param \Closure $callback * @return mixed */ public function existsOr(Closure $callback) { return $this->exists() ? true : $callback(); } /** * Execute the given callback if rows exist for the current query. * * @param \Closure $callback * @return mixed */ public function doesntExistOr(Closure $callback) { return $this->doesntExist() ? true : $callback(); } /** * Retrieve the "count" result of the query. * * @param string $columns * @return int */ public function count($columns = '*') { return (int) $this->aggregate(__FUNCTION__, Arr::wrap($columns)); } /** * Retrieve the minimum value of a given column. * * @param string $column * @return mixed */ public function min($column) { return $this->aggregate(__FUNCTION__, [$column]); } /** * Retrieve the maximum value of a given column. * * @param string $column * @return mixed */ public function max($column) { return $this->aggregate(__FUNCTION__, [$column]); } /** * Retrieve the sum of the values of a given column. * * @param string $column * @return mixed */ public function sum($column) { $result = $this->aggregate(__FUNCTION__, [$column]); return $result ?: 0; } /** * Retrieve the average of the values of a given column. * * @param string $column * @return mixed */ public function avg($column) { return $this->aggregate(__FUNCTION__, [$column]); } /** * Alias for the "avg" method. * * @param string $column * @return mixed */ public function average($column) { return $this->avg($column); } /** * Execute an aggregate function on the database. * * @param string $function * @param array $columns * @return mixed */ public function aggregate($function, $columns = ['*']) { $results = $this->cloneWithout($this->unions ? [] : ['columns']) ->cloneWithoutBindings($this->unions ? [] : ['select']) ->setAggregate($function, $columns) ->get($columns); if (! $results->isEmpty()) { return array_change_key_case((array) $results[0])['aggregate']; } } /** * Execute a numeric aggregate function on the database. * * @param string $function * @param array $columns * @return float|int */ public function numericAggregate($function, $columns = ['*']) { $result = $this->aggregate($function, $columns); // If there is no result, we can obviously just return 0 here. Next, we will check // if the result is an integer or float. If it is already one of these two data // types we can just return the result as-is, otherwise we will convert this. if (! $result) { return 0; } if (is_int($result) || is_float($result)) { return $result; } // If the result doesn't contain a decimal place, we will assume it is an int then // cast it to one. When it does we will cast it to a float since it needs to be // cast to the expected data type for the developers out of pure convenience. return strpos((string) $result, '.') === false ? (int) $result : (float) $result; } /** * Set the aggregate property without running the query. * * @param string $function * @param array $columns * @return $this */ protected function setAggregate($function, $columns) { $this->aggregate = compact('function', 'columns'); if (empty($this->groups)) { $this->orders = null; $this->bindings['order'] = []; } return $this; } /** * Execute the given callback while selecting the given columns. * * After running the callback, the columns are reset to the original value. * * @param array $columns * @param callable $callback * @return mixed */ protected function onceWithColumns($columns, $callback) { $original = $this->columns; if (is_null($original)) { $this->columns = $columns; } $result = $callback(); $this->columns = $original; return $result; } /** * Insert a new record into the database. * * @param array $values * @return bool */ public function insert(array $values) { // Since every insert gets treated like a batch insert, we will make sure the // bindings are structured in a way that is convenient when building these // inserts statements by verifying these elements are actually an array. if (empty($values)) { return true; } if (! is_array(reset($values))) { $values = [$values]; } // Here, we will sort the insert keys for every record so that each insert is // in the same order for the record. We need to make sure this is the case // so there are not any errors or problems when inserting these records. else { foreach ($values as $key => $value) { ksort($value); $values[$key] = $value; } } // Finally, we will run this query against the database connection and return // the results. We will need to also flatten these bindings before running // the query so they are all in one huge, flattened array for execution. return $this->connection->insert( $this->grammar->compileInsert($this, $values), $this->cleanBindings(Arr::flatten($values, 1)) ); } /** * Insert a new record into the database while ignoring errors. * * @param array $values * @return int */ public function insertOrIgnore(array $values) { if (empty($values)) { return 0; } if (! is_array(reset($values))) { $values = [$values]; } else { foreach ($values as $key => $value) { ksort($value); $values[$key] = $value; } } return $this->connection->affectingStatement( $this->grammar->compileInsertOrIgnore($this, $values), $this->cleanBindings(Arr::flatten($values, 1)) ); } /** * Insert a new record and get the value of the primary key. * * @param array $values * @param string|null $sequence * @return int */ public function insertGetId(array $values, $sequence = null) { $sql = $this->grammar->compileInsertGetId($this, $values, $sequence); $values = $this->cleanBindings($values); return $this->processor->processInsertGetId($this, $sql, $values, $sequence); } /** * Insert new records into the table using a subquery. * * @param array $columns * @param \Closure|\Illuminate\Database\Query\Builder|string $query * @return int */ public function insertUsing(array $columns, $query) { [$sql, $bindings] = $this->createSub($query); return $this->connection->affectingStatement( $this->grammar->compileInsertUsing($this, $columns, $sql), $this->cleanBindings($bindings) ); } /** * Update a record in the database. * * @param array $values * @return int */ public function update(array $values) { $sql = $this->grammar->compileUpdate($this, $values); return $this->connection->update($sql, $this->cleanBindings( $this->grammar->prepareBindingsForUpdate($this->bindings, $values) )); } /** * Insert or update a record matching the attributes, and fill it with values. * * @param array $attributes * @param array $values * @return bool */ public function updateOrInsert(array $attributes, array $values = []) { if (! $this->where($attributes)->exists()) { return $this->insert(array_merge($attributes, $values)); } if (empty($values)) { return true; } return (bool) $this->limit(1)->update($values); } /** * Increment a column's value by a given amount. * * @param string $column * @param float|int $amount * @param array $extra * @return int * * @throws \InvalidArgumentException */ public function increment($column, $amount = 1, array $extra = []) { if (! is_numeric($amount)) { throw new InvalidArgumentException('Non-numeric value passed to increment method.'); } $wrapped = $this->grammar->wrap($column); $columns = array_merge([$column => $this->raw("$wrapped + $amount")], $extra); return $this->update($columns); } /** * Decrement a column's value by a given amount. * * @param string $column * @param float|int $amount * @param array $extra * @return int * * @throws \InvalidArgumentException */ public function decrement($column, $amount = 1, array $extra = []) { if (! is_numeric($amount)) { throw new InvalidArgumentException('Non-numeric value passed to decrement method.'); } $wrapped = $this->grammar->wrap($column); $columns = array_merge([$column => $this->raw("$wrapped - $amount")], $extra); return $this->update($columns); } /** * Delete a record from the database. * * @param mixed $id * @return int */ public function delete($id = null) { // If an ID is passed to the method, we will set the where clause to check the // ID to let developers to simply and quickly remove a single row from this // database without manually specifying the "where" clauses on the query. if (! is_null($id)) { $this->where($this->from.'.id', '=', $id); } return $this->connection->delete( $this->grammar->compileDelete($this), $this->cleanBindings( $this->grammar->prepareBindingsForDelete($this->bindings) ) ); } /** * Run a truncate statement on the table. * * @return void */ public function truncate() { foreach ($this->grammar->compileTruncate($this) as $sql => $bindings) { $this->connection->statement($sql, $bindings); } } /** * Get a new instance of the query builder. * * @return \Illuminate\Database\Query\Builder */ public function newQuery() { return new static($this->connection, $this->grammar, $this->processor); } /** * Create a new query instance for a sub-query. * * @return \Illuminate\Database\Query\Builder */ protected function forSubQuery() { return $this->newQuery(); } /** * Create a raw database expression. * * @param mixed $value * @return \Illuminate\Database\Query\Expression */ public function raw($value) { return $this->connection->raw($value); } /** * Get the current query value bindings in a flattened array. * * @return array */ public function getBindings() { return Arr::flatten($this->bindings); } /** * Get the raw array of bindings. * * @return array */ public function getRawBindings() { return $this->bindings; } /** * Set the bindings on the query builder. * * @param array $bindings * @param string $type * @return $this * * @throws \InvalidArgumentException */ public function setBindings(array $bindings, $type = 'where') { if (! array_key_exists($type, $this->bindings)) { throw new InvalidArgumentException("Invalid binding type: {$type}."); } $this->bindings[$type] = $bindings; return $this; } /** * Add a binding to the query. * * @param mixed $value * @param string $type * @return $this * * @throws \InvalidArgumentException */ public function addBinding($value, $type = 'where') { if (! array_key_exists($type, $this->bindings)) { throw new InvalidArgumentException("Invalid binding type: {$type}."); } if (is_array($value)) { $this->bindings[$type] = array_values(array_merge($this->bindings[$type], $value)); } else { $this->bindings[$type][] = $value; } return $this; } /** * Merge an array of bindings into our bindings. * * @param \Illuminate\Database\Query\Builder $query * @return $this */ public function mergeBindings(self $query) { $this->bindings = array_merge_recursive($this->bindings, $query->bindings); return $this; } /** * Remove all of the expressions from a list of bindings. * * @param array $bindings * @return array */ protected function cleanBindings(array $bindings) { return array_values(array_filter($bindings, function ($binding) { return ! $binding instanceof Expression; })); } /** * Get the default key name of the table. * * @return string */ protected function defaultKeyName() { return 'id'; } /** * Get the database connection instance. * * @return \Illuminate\Database\ConnectionInterface */ public function getConnection() { return $this->connection; } /** * Get the database query processor instance. * * @return \Illuminate\Database\Query\Processors\Processor */ public function getProcessor() { return $this->processor; } /** * Get the query grammar instance. * * @return \Illuminate\Database\Query\Grammars\Grammar */ public function getGrammar() { return $this->grammar; } /** * Use the write pdo for query. * * @return $this */ public function useWritePdo() { $this->useWritePdo = true; return $this; } /** * Determine if the value is a query builder instance or a Closure. * * @param mixed $value * @return bool */ protected function isQueryable($value) { return $value instanceof self || $value instanceof EloquentBuilder || $value instanceof Closure; } /** * Clone the query without the given properties. * * @param array $properties * @return static */ public function cloneWithout(array $properties) { return tap(clone $this, function ($clone) use ($properties) { foreach ($properties as $property) { $clone->{$property} = null; } }); } /** * Clone the query without the given bindings. * * @param array $except * @return static */ public function cloneWithoutBindings(array $except) { return tap(clone $this, function ($clone) use ($except) { foreach ($except as $type) { $clone->bindings[$type] = []; } }); } /** * Dump the current SQL and bindings. * * @return $this */ public function dump() { dump($this->toSql(), $this->getBindings()); return $this; } /** * Die and dump the current SQL and bindings. * * @return void */ public function dd() { dd($this->toSql(), $this->getBindings()); } /** * Handle dynamic method calls into the method. * * @param string $method * @param array $parameters * @return mixed * * @throws \BadMethodCallException */ public function __call($method, $parameters) { if (static::hasMacro($method)) { return $this->macroCall($method, $parameters); } if (Str::startsWith($method, 'where')) { return $this->dynamicWhere($method, $parameters); } static::throwBadMethodCallException($method); } } database/ConnectionInterface.php 0000644 00000007256 14736103231 0012753 0 ustar 00 <?php namespace Illuminate\Database; use Closure; interface ConnectionInterface { /** * Begin a fluent query against a database table. * * @param \Closure|\Illuminate\Database\Query\Builder|string $table * @param string|null $as * @return \Illuminate\Database\Query\Builder */ public function table($table, $as = null); /** * Get a new raw query expression. * * @param mixed $value * @return \Illuminate\Database\Query\Expression */ public function raw($value); /** * Run a select statement and return a single result. * * @param string $query * @param array $bindings * @param bool $useReadPdo * @return mixed */ public function selectOne($query, $bindings = [], $useReadPdo = true); /** * Run a select statement against the database. * * @param string $query * @param array $bindings * @param bool $useReadPdo * @return array */ public function select($query, $bindings = [], $useReadPdo = true); /** * Run a select statement against the database and returns a generator. * * @param string $query * @param array $bindings * @param bool $useReadPdo * @return \Generator */ public function cursor($query, $bindings = [], $useReadPdo = true); /** * Run an insert statement against the database. * * @param string $query * @param array $bindings * @return bool */ public function insert($query, $bindings = []); /** * Run an update statement against the database. * * @param string $query * @param array $bindings * @return int */ public function update($query, $bindings = []); /** * Run a delete statement against the database. * * @param string $query * @param array $bindings * @return int */ public function delete($query, $bindings = []); /** * Execute an SQL statement and return the boolean result. * * @param string $query * @param array $bindings * @return bool */ public function statement($query, $bindings = []); /** * Run an SQL statement and get the number of rows affected. * * @param string $query * @param array $bindings * @return int */ public function affectingStatement($query, $bindings = []); /** * Run a raw, unprepared query against the PDO connection. * * @param string $query * @return bool */ public function unprepared($query); /** * Prepare the query bindings for execution. * * @param array $bindings * @return array */ public function prepareBindings(array $bindings); /** * Execute a Closure within a transaction. * * @param \Closure $callback * @param int $attempts * @return mixed * * @throws \Throwable */ public function transaction(Closure $callback, $attempts = 1); /** * Start a new database transaction. * * @return void */ public function beginTransaction(); /** * Commit the active database transaction. * * @return void */ public function commit(); /** * Rollback the active database transaction. * * @return void */ public function rollBack(); /** * Get the number of active transactions. * * @return int */ public function transactionLevel(); /** * Execute the given callback in "dry run" mode. * * @param \Closure $callback * @return array */ public function pretend(Closure $callback); } database/LICENSE.md 0000644 00000002063 14736103231 0007715 0 ustar 00 The MIT License (MIT) Copyright (c) Taylor Otwell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. database/Eloquent/ScopeInterface.php 0000644 00000000255 14736103231 0013511 0 ustar 00 <?php namespace Illuminate\Database\Eloquent; /** * @deprecated since version 5.2. Use Illuminate\Database\Eloquent\Scope. */ interface ScopeInterface extends Scope { } database/Eloquent/SoftDeletes.php 0000644 00000011245 14736103231 0013041 0 ustar 00 <?php namespace Illuminate\Database\Eloquent; /** * @method static static|\Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Query\Builder withTrashed() * @method static static|\Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Query\Builder onlyTrashed() * @method static static|\Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Query\Builder withoutTrashed() */ trait SoftDeletes { /** * Indicates if the model is currently force deleting. * * @var bool */ protected $forceDeleting = false; /** * Boot the soft deleting trait for a model. * * @return void */ public static function bootSoftDeletes() { static::addGlobalScope(new SoftDeletingScope); } /** * Initialize the soft deleting trait for an instance. * * @return void */ public function initializeSoftDeletes() { $this->dates[] = $this->getDeletedAtColumn(); } /** * Force a hard delete on a soft deleted model. * * @return bool|null */ public function forceDelete() { $this->forceDeleting = true; return tap($this->delete(), function ($deleted) { $this->forceDeleting = false; if ($deleted) { $this->fireModelEvent('forceDeleted', false); } }); } /** * Perform the actual delete query on this model instance. * * @return mixed */ protected function performDeleteOnModel() { if ($this->forceDeleting) { $this->exists = false; return $this->setKeysForSaveQuery($this->newModelQuery())->forceDelete(); } return $this->runSoftDelete(); } /** * Perform the actual delete query on this model instance. * * @return void */ protected function runSoftDelete() { $query = $this->setKeysForSaveQuery($this->newModelQuery()); $time = $this->freshTimestamp(); $columns = [$this->getDeletedAtColumn() => $this->fromDateTime($time)]; $this->{$this->getDeletedAtColumn()} = $time; if ($this->timestamps && ! is_null($this->getUpdatedAtColumn())) { $this->{$this->getUpdatedAtColumn()} = $time; $columns[$this->getUpdatedAtColumn()] = $this->fromDateTime($time); } $query->update($columns); $this->syncOriginalAttributes(array_keys($columns)); } /** * Restore a soft-deleted model instance. * * @return bool|null */ public function restore() { // If the restoring event does not return false, we will proceed with this // restore operation. Otherwise, we bail out so the developer will stop // the restore totally. We will clear the deleted timestamp and save. if ($this->fireModelEvent('restoring') === false) { return false; } $this->{$this->getDeletedAtColumn()} = null; // Once we have saved the model, we will fire the "restored" event so this // developer will do anything they need to after a restore operation is // totally finished. Then we will return the result of the save call. $this->exists = true; $result = $this->save(); $this->fireModelEvent('restored', false); return $result; } /** * Determine if the model instance has been soft-deleted. * * @return bool */ public function trashed() { return ! is_null($this->{$this->getDeletedAtColumn()}); } /** * Register a restoring model event with the dispatcher. * * @param \Closure|string $callback * @return void */ public static function restoring($callback) { static::registerModelEvent('restoring', $callback); } /** * Register a restored model event with the dispatcher. * * @param \Closure|string $callback * @return void */ public static function restored($callback) { static::registerModelEvent('restored', $callback); } /** * Determine if the model is currently force deleting. * * @return bool */ public function isForceDeleting() { return $this->forceDeleting; } /** * Get the name of the "deleted at" column. * * @return string */ public function getDeletedAtColumn() { return defined('static::DELETED_AT') ? static::DELETED_AT : 'deleted_at'; } /** * Get the fully qualified "deleted at" column. * * @return string */ public function getQualifiedDeletedAtColumn() { return $this->qualifyColumn($this->getDeletedAtColumn()); } } database/Eloquent/ModelNotFoundException.php 0000644 00000002310 14736103231 0015205 0 ustar 00 <?php namespace Illuminate\Database\Eloquent; use Illuminate\Support\Arr; use RuntimeException; class ModelNotFoundException extends RuntimeException { /** * Name of the affected Eloquent model. * * @var string */ protected $model; /** * The affected model IDs. * * @var int|array */ protected $ids; /** * Set the affected Eloquent model and instance ids. * * @param string $model * @param int|array $ids * @return $this */ public function setModel($model, $ids = []) { $this->model = $model; $this->ids = Arr::wrap($ids); $this->message = "No query results for model [{$model}]"; if (count($this->ids) > 0) { $this->message .= ' '.implode(', ', $this->ids); } else { $this->message .= '.'; } return $this; } /** * Get the affected Eloquent model. * * @return string */ public function getModel() { return $this->model; } /** * Get the affected Eloquent model IDs. * * @return int|array */ public function getIds() { return $this->ids; } } database/Eloquent/FactoryBuilder.php 0000644 00000025761 14736103231 0013546 0 ustar 00 <?php namespace Illuminate\Database\Eloquent; use Faker\Generator as Faker; use Illuminate\Support\Traits\Macroable; use InvalidArgumentException; class FactoryBuilder { use Macroable; /** * The model definitions in the container. * * @var array */ protected $definitions; /** * The model being built. * * @var string */ protected $class; /** * The database connection on which the model instance should be persisted. * * @var string */ protected $connection; /** * The model states. * * @var array */ protected $states; /** * The model after making callbacks. * * @var array */ protected $afterMaking = []; /** * The model after creating callbacks. * * @var array */ protected $afterCreating = []; /** * The states to apply. * * @var array */ protected $activeStates = []; /** * The Faker instance for the builder. * * @var \Faker\Generator */ protected $faker; /** * The number of models to build. * * @var int|null */ protected $amount = null; /** * Create an new builder instance. * * @param string $class * @param array $definitions * @param array $states * @param array $afterMaking * @param array $afterCreating * @param \Faker\Generator $faker * @return void */ public function __construct($class, array $definitions, array $states, array $afterMaking, array $afterCreating, Faker $faker) { $this->class = $class; $this->faker = $faker; $this->states = $states; $this->definitions = $definitions; $this->afterMaking = $afterMaking; $this->afterCreating = $afterCreating; } /** * Set the amount of models you wish to create / make. * * @param int $amount * @return $this */ public function times($amount) { $this->amount = $amount; return $this; } /** * Set the state to be applied to the model. * * @param string $state * @return $this */ public function state($state) { return $this->states([$state]); } /** * Set the states to be applied to the model. * * @param array|mixed $states * @return $this */ public function states($states) { $this->activeStates = is_array($states) ? $states : func_get_args(); return $this; } /** * Set the database connection on which the model instance should be persisted. * * @param string $name * @return $this */ public function connection($name) { $this->connection = $name; return $this; } /** * Create a model and persist it in the database if requested. * * @param array $attributes * @return \Closure */ public function lazy(array $attributes = []) { return function () use ($attributes) { return $this->create($attributes); }; } /** * Create a collection of models and persist them to the database. * * @param array $attributes * @return \Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Model|mixed */ public function create(array $attributes = []) { $results = $this->make($attributes); if ($results instanceof Model) { $this->store(collect([$results])); $this->callAfterCreating(collect([$results])); } else { $this->store($results); $this->callAfterCreating($results); } return $results; } /** * Create a collection of models and persist them to the database. * * @param iterable $records * @return \Illuminate\Database\Eloquent\Collection|mixed */ public function createMany(iterable $records) { return (new $this->class)->newCollection(array_map(function ($attribute) { return $this->create($attribute); }, $records)); } /** * Set the connection name on the results and store them. * * @param \Illuminate\Support\Collection $results * @return void */ protected function store($results) { $results->each(function ($model) { if (! isset($this->connection)) { $model->setConnection($model->newQueryWithoutScopes()->getConnection()->getName()); } $model->save(); }); } /** * Create a collection of models. * * @param array $attributes * @return \Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Model|mixed */ public function make(array $attributes = []) { if ($this->amount === null) { return tap($this->makeInstance($attributes), function ($instance) { $this->callAfterMaking(collect([$instance])); }); } if ($this->amount < 1) { return (new $this->class)->newCollection(); } $instances = (new $this->class)->newCollection(array_map(function () use ($attributes) { return $this->makeInstance($attributes); }, range(1, $this->amount))); $this->callAfterMaking($instances); return $instances; } /** * Create an array of raw attribute arrays. * * @param array $attributes * @return mixed */ public function raw(array $attributes = []) { if ($this->amount === null) { return $this->getRawAttributes($attributes); } if ($this->amount < 1) { return []; } return array_map(function () use ($attributes) { return $this->getRawAttributes($attributes); }, range(1, $this->amount)); } /** * Get a raw attributes array for the model. * * @param array $attributes * @return mixed * * @throws \InvalidArgumentException */ protected function getRawAttributes(array $attributes = []) { if (! isset($this->definitions[$this->class])) { throw new InvalidArgumentException("Unable to locate factory for [{$this->class}]."); } $definition = call_user_func( $this->definitions[$this->class], $this->faker, $attributes ); return $this->expandAttributes( array_merge($this->applyStates($definition, $attributes), $attributes) ); } /** * Make an instance of the model with the given attributes. * * @param array $attributes * @return \Illuminate\Database\Eloquent\Model */ protected function makeInstance(array $attributes = []) { return Model::unguarded(function () use ($attributes) { $instance = new $this->class( $this->getRawAttributes($attributes) ); if (isset($this->connection)) { $instance->setConnection($this->connection); } return $instance; }); } /** * Apply the active states to the model definition array. * * @param array $definition * @param array $attributes * @return array * * @throws \InvalidArgumentException */ protected function applyStates(array $definition, array $attributes = []) { foreach ($this->activeStates as $state) { if (! isset($this->states[$this->class][$state])) { if ($this->stateHasAfterCallback($state)) { continue; } throw new InvalidArgumentException("Unable to locate [{$state}] state for [{$this->class}]."); } $definition = array_merge( $definition, $this->stateAttributes($state, $attributes) ); } return $definition; } /** * Get the state attributes. * * @param string $state * @param array $attributes * @return array */ protected function stateAttributes($state, array $attributes) { $stateAttributes = $this->states[$this->class][$state]; if (! is_callable($stateAttributes)) { return $stateAttributes; } return $stateAttributes($this->faker, $attributes); } /** * Expand all attributes to their underlying values. * * @param array $attributes * @return array */ protected function expandAttributes(array $attributes) { foreach ($attributes as &$attribute) { if (is_callable($attribute) && ! is_string($attribute) && ! is_array($attribute)) { $attribute = $attribute($attributes); } if ($attribute instanceof static) { $attribute = $attribute->create()->getKey(); } if ($attribute instanceof Model) { $attribute = $attribute->getKey(); } } return $attributes; } /** * Run after making callbacks on a collection of models. * * @param \Illuminate\Support\Collection $models * @return void */ public function callAfterMaking($models) { $this->callAfter($this->afterMaking, $models); } /** * Run after creating callbacks on a collection of models. * * @param \Illuminate\Support\Collection $models * @return void */ public function callAfterCreating($models) { $this->callAfter($this->afterCreating, $models); } /** * Call after callbacks for each model and state. * * @param array $afterCallbacks * @param \Illuminate\Support\Collection $models * @return void */ protected function callAfter(array $afterCallbacks, $models) { $states = array_merge(['default'], $this->activeStates); $models->each(function ($model) use ($states, $afterCallbacks) { foreach ($states as $state) { $this->callAfterCallbacks($afterCallbacks, $model, $state); } }); } /** * Call after callbacks for each model and state. * * @param array $afterCallbacks * @param \Illuminate\Database\Eloquent\Model $model * @param string $state * @return void */ protected function callAfterCallbacks(array $afterCallbacks, $model, $state) { if (! isset($afterCallbacks[$this->class][$state])) { return; } foreach ($afterCallbacks[$this->class][$state] as $callback) { $callback($model, $this->faker); } } /** * Determine if the given state has an "after" callback. * * @param string $state * @return bool */ protected function stateHasAfterCallback($state) { return isset($this->afterMaking[$this->class][$state]) || isset($this->afterCreating[$this->class][$state]); } } database/Eloquent/QueueEntityResolver.php 0000644 00000001245 14736103231 0014622 0 ustar 00 <?php namespace Illuminate\Database\Eloquent; use Illuminate\Contracts\Queue\EntityNotFoundException; use Illuminate\Contracts\Queue\EntityResolver as EntityResolverContract; class QueueEntityResolver implements EntityResolverContract { /** * Resolve the entity for the given ID. * * @param string $type * @param mixed $id * @return mixed * * @throws \Illuminate\Contracts\Queue\EntityNotFoundException */ public function resolve($type, $id) { $instance = (new $type)->find($id); if ($instance) { return $instance; } throw new EntityNotFoundException($type, $id); } } database/Eloquent/Concerns/HidesAttributes.php 0000644 00000003743 14736103231 0015501 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Concerns; trait HidesAttributes { /** * The attributes that should be hidden for serialization. * * @var array */ protected $hidden = []; /** * The attributes that should be visible in serialization. * * @var array */ protected $visible = []; /** * Get the hidden attributes for the model. * * @return array */ public function getHidden() { return $this->hidden; } /** * Set the hidden attributes for the model. * * @param array $hidden * @return $this */ public function setHidden(array $hidden) { $this->hidden = $hidden; return $this; } /** * Get the visible attributes for the model. * * @return array */ public function getVisible() { return $this->visible; } /** * Set the visible attributes for the model. * * @param array $visible * @return $this */ public function setVisible(array $visible) { $this->visible = $visible; return $this; } /** * Make the given, typically hidden, attributes visible. * * @param array|string|null $attributes * @return $this */ public function makeVisible($attributes) { $attributes = is_array($attributes) ? $attributes : func_get_args(); $this->hidden = array_diff($this->hidden, $attributes); if (! empty($this->visible)) { $this->visible = array_merge($this->visible, $attributes); } return $this; } /** * Make the given, typically visible, attributes hidden. * * @param array|string|null $attributes * @return $this */ public function makeHidden($attributes) { $this->hidden = array_merge( $this->hidden, is_array($attributes) ? $attributes : func_get_args() ); return $this; } } database/Eloquent/Concerns/QueriesRelationships.php 0000644 00000042732 14736103231 0016561 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Concerns; use Closure; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Database\Query\Builder as QueryBuilder; use Illuminate\Database\Query\Expression; use Illuminate\Support\Str; use RuntimeException; trait QueriesRelationships { /** * Add a relationship count / exists condition to the query. * * @param \Illuminate\Database\Eloquent\Relations\Relation|string $relation * @param string $operator * @param int $count * @param string $boolean * @param \Closure|null $callback * @return \Illuminate\Database\Eloquent\Builder|static * * @throws \RuntimeException */ public function has($relation, $operator = '>=', $count = 1, $boolean = 'and', Closure $callback = null) { if (is_string($relation)) { if (strpos($relation, '.') !== false) { return $this->hasNested($relation, $operator, $count, $boolean, $callback); } $relation = $this->getRelationWithoutConstraints($relation); } if ($relation instanceof MorphTo) { throw new RuntimeException('Please use whereHasMorph() for MorphTo relationships.'); } // If we only need to check for the existence of the relation, then we can optimize // the subquery to only run a "where exists" clause instead of this full "count" // clause. This will make these queries run much faster compared with a count. $method = $this->canUseExistsForExistenceCheck($operator, $count) ? 'getRelationExistenceQuery' : 'getRelationExistenceCountQuery'; $hasQuery = $relation->{$method}( $relation->getRelated()->newQueryWithoutRelationships(), $this ); // Next we will call any given callback as an "anonymous" scope so they can get the // proper logical grouping of the where clauses if needed by this Eloquent query // builder. Then, we will be ready to finalize and return this query instance. if ($callback) { $hasQuery->callScope($callback); } return $this->addHasWhere( $hasQuery, $relation, $operator, $count, $boolean ); } /** * Add nested relationship count / exists conditions to the query. * * Sets up recursive call to whereHas until we finish the nested relation. * * @param string $relations * @param string $operator * @param int $count * @param string $boolean * @param \Closure|null $callback * @return \Illuminate\Database\Eloquent\Builder|static */ protected function hasNested($relations, $operator = '>=', $count = 1, $boolean = 'and', $callback = null) { $relations = explode('.', $relations); $doesntHave = $operator === '<' && $count === 1; if ($doesntHave) { $operator = '>='; $count = 1; } $closure = function ($q) use (&$closure, &$relations, $operator, $count, $callback) { // In order to nest "has", we need to add count relation constraints on the // callback Closure. We'll do this by simply passing the Closure its own // reference to itself so it calls itself recursively on each segment. count($relations) > 1 ? $q->whereHas(array_shift($relations), $closure) : $q->has(array_shift($relations), $operator, $count, 'and', $callback); }; return $this->has(array_shift($relations), $doesntHave ? '<' : '>=', 1, $boolean, $closure); } /** * Add a relationship count / exists condition to the query with an "or". * * @param string $relation * @param string $operator * @param int $count * @return \Illuminate\Database\Eloquent\Builder|static */ public function orHas($relation, $operator = '>=', $count = 1) { return $this->has($relation, $operator, $count, 'or'); } /** * Add a relationship count / exists condition to the query. * * @param string $relation * @param string $boolean * @param \Closure|null $callback * @return \Illuminate\Database\Eloquent\Builder|static */ public function doesntHave($relation, $boolean = 'and', Closure $callback = null) { return $this->has($relation, '<', 1, $boolean, $callback); } /** * Add a relationship count / exists condition to the query with an "or". * * @param string $relation * @return \Illuminate\Database\Eloquent\Builder|static */ public function orDoesntHave($relation) { return $this->doesntHave($relation, 'or'); } /** * Add a relationship count / exists condition to the query with where clauses. * * @param string $relation * @param \Closure|null $callback * @param string $operator * @param int $count * @return \Illuminate\Database\Eloquent\Builder|static */ public function whereHas($relation, Closure $callback = null, $operator = '>=', $count = 1) { return $this->has($relation, $operator, $count, 'and', $callback); } /** * Add a relationship count / exists condition to the query with where clauses and an "or". * * @param string $relation * @param \Closure|null $callback * @param string $operator * @param int $count * @return \Illuminate\Database\Eloquent\Builder|static */ public function orWhereHas($relation, Closure $callback = null, $operator = '>=', $count = 1) { return $this->has($relation, $operator, $count, 'or', $callback); } /** * Add a relationship count / exists condition to the query with where clauses. * * @param string $relation * @param \Closure|null $callback * @return \Illuminate\Database\Eloquent\Builder|static */ public function whereDoesntHave($relation, Closure $callback = null) { return $this->doesntHave($relation, 'and', $callback); } /** * Add a relationship count / exists condition to the query with where clauses and an "or". * * @param string $relation * @param \Closure|null $callback * @return \Illuminate\Database\Eloquent\Builder|static */ public function orWhereDoesntHave($relation, Closure $callback = null) { return $this->doesntHave($relation, 'or', $callback); } /** * Add a polymorphic relationship count / exists condition to the query. * * @param string $relation * @param string|array $types * @param string $operator * @param int $count * @param string $boolean * @param \Closure|null $callback * @return \Illuminate\Database\Eloquent\Builder|static */ public function hasMorph($relation, $types, $operator = '>=', $count = 1, $boolean = 'and', Closure $callback = null) { $relation = $this->getRelationWithoutConstraints($relation); $types = (array) $types; if ($types === ['*']) { $types = $this->model->newModelQuery()->distinct()->pluck($relation->getMorphType())->filter()->all(); foreach ($types as &$type) { $type = Relation::getMorphedModel($type) ?? $type; } } return $this->where(function ($query) use ($relation, $callback, $operator, $count, $types) { foreach ($types as $type) { $query->orWhere(function ($query) use ($relation, $callback, $operator, $count, $type) { $belongsTo = $this->getBelongsToRelation($relation, $type); if ($callback) { $callback = function ($query) use ($callback, $type) { return $callback($query, $type); }; } $query->where($this->query->from.'.'.$relation->getMorphType(), '=', (new $type)->getMorphClass()) ->whereHas($belongsTo, $callback, $operator, $count); }); } }, null, null, $boolean); } /** * Get the BelongsTo relationship for a single polymorphic type. * * @param \Illuminate\Database\Eloquent\Relations\MorphTo $relation * @param string $type * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ protected function getBelongsToRelation(MorphTo $relation, $type) { $belongsTo = Relation::noConstraints(function () use ($relation, $type) { return $this->model->belongsTo( $type, $relation->getForeignKeyName(), $relation->getOwnerKeyName() ); }); $belongsTo->getQuery()->mergeConstraintsFrom($relation->getQuery()); return $belongsTo; } /** * Add a polymorphic relationship count / exists condition to the query with an "or". * * @param string $relation * @param string|array $types * @param string $operator * @param int $count * @return \Illuminate\Database\Eloquent\Builder|static */ public function orHasMorph($relation, $types, $operator = '>=', $count = 1) { return $this->hasMorph($relation, $types, $operator, $count, 'or'); } /** * Add a polymorphic relationship count / exists condition to the query. * * @param string $relation * @param string|array $types * @param string $boolean * @param \Closure|null $callback * @return \Illuminate\Database\Eloquent\Builder|static */ public function doesntHaveMorph($relation, $types, $boolean = 'and', Closure $callback = null) { return $this->hasMorph($relation, $types, '<', 1, $boolean, $callback); } /** * Add a polymorphic relationship count / exists condition to the query with an "or". * * @param string $relation * @param string|array $types * @return \Illuminate\Database\Eloquent\Builder|static */ public function orDoesntHaveMorph($relation, $types) { return $this->doesntHaveMorph($relation, $types, 'or'); } /** * Add a polymorphic relationship count / exists condition to the query with where clauses. * * @param string $relation * @param string|array $types * @param \Closure|null $callback * @param string $operator * @param int $count * @return \Illuminate\Database\Eloquent\Builder|static */ public function whereHasMorph($relation, $types, Closure $callback = null, $operator = '>=', $count = 1) { return $this->hasMorph($relation, $types, $operator, $count, 'and', $callback); } /** * Add a polymorphic relationship count / exists condition to the query with where clauses and an "or". * * @param string $relation * @param string|array $types * @param \Closure|null $callback * @param string $operator * @param int $count * @return \Illuminate\Database\Eloquent\Builder|static */ public function orWhereHasMorph($relation, $types, Closure $callback = null, $operator = '>=', $count = 1) { return $this->hasMorph($relation, $types, $operator, $count, 'or', $callback); } /** * Add a polymorphic relationship count / exists condition to the query with where clauses. * * @param string $relation * @param string|array $types * @param \Closure|null $callback * @return \Illuminate\Database\Eloquent\Builder|static */ public function whereDoesntHaveMorph($relation, $types, Closure $callback = null) { return $this->doesntHaveMorph($relation, $types, 'and', $callback); } /** * Add a polymorphic relationship count / exists condition to the query with where clauses and an "or". * * @param string $relation * @param string|array $types * @param \Closure|null $callback * @return \Illuminate\Database\Eloquent\Builder|static */ public function orWhereDoesntHaveMorph($relation, $types, Closure $callback = null) { return $this->doesntHaveMorph($relation, $types, 'or', $callback); } /** * Add subselect queries to count the relations. * * @param mixed $relations * @return $this */ public function withCount($relations) { if (empty($relations)) { return $this; } if (is_null($this->query->columns)) { $this->query->select([$this->query->from.'.*']); } $relations = is_array($relations) ? $relations : func_get_args(); foreach ($this->parseWithRelations($relations) as $name => $constraints) { // First we will determine if the name has been aliased using an "as" clause on the name // and if it has we will extract the actual relationship name and the desired name of // the resulting column. This allows multiple counts on the same relationship name. $segments = explode(' ', $name); unset($alias); if (count($segments) === 3 && Str::lower($segments[1]) === 'as') { [$name, $alias] = [$segments[0], $segments[2]]; } $relation = $this->getRelationWithoutConstraints($name); // Here we will get the relationship count query and prepare to add it to the main query // as a sub-select. First, we'll get the "has" query and use that to get the relation // count query. We will normalize the relation name then append _count as the name. $query = $relation->getRelationExistenceCountQuery( $relation->getRelated()->newQuery(), $this ); $query->callScope($constraints); $query = $query->mergeConstraintsFrom($relation->getQuery())->toBase(); $query->orders = null; $query->setBindings([], 'order'); if (count($query->columns) > 1) { $query->columns = [$query->columns[0]]; $query->bindings['select'] = []; } // Finally we will add the proper result column alias to the query and run the subselect // statement against the query builder. Then we will return the builder instance back // to the developer for further constraint chaining that needs to take place on it. $column = $alias ?? Str::snake($name.'_count'); $this->selectSub($query, $column); } return $this; } /** * Add the "has" condition where clause to the query. * * @param \Illuminate\Database\Eloquent\Builder $hasQuery * @param \Illuminate\Database\Eloquent\Relations\Relation $relation * @param string $operator * @param int $count * @param string $boolean * @return \Illuminate\Database\Eloquent\Builder|static */ protected function addHasWhere(Builder $hasQuery, Relation $relation, $operator, $count, $boolean) { $hasQuery->mergeConstraintsFrom($relation->getQuery()); return $this->canUseExistsForExistenceCheck($operator, $count) ? $this->addWhereExistsQuery($hasQuery->toBase(), $boolean, $operator === '<' && $count === 1) : $this->addWhereCountQuery($hasQuery->toBase(), $operator, $count, $boolean); } /** * Merge the where constraints from another query to the current query. * * @param \Illuminate\Database\Eloquent\Builder $from * @return \Illuminate\Database\Eloquent\Builder|static */ public function mergeConstraintsFrom(Builder $from) { $whereBindings = $from->getQuery()->getRawBindings()['where'] ?? []; // Here we have some other query that we want to merge the where constraints from. We will // copy over any where constraints on the query as well as remove any global scopes the // query might have removed. Then we will return ourselves with the finished merging. return $this->withoutGlobalScopes( $from->removedScopes() )->mergeWheres( $from->getQuery()->wheres, $whereBindings ); } /** * Add a sub-query count clause to this query. * * @param \Illuminate\Database\Query\Builder $query * @param string $operator * @param int $count * @param string $boolean * @return $this */ protected function addWhereCountQuery(QueryBuilder $query, $operator = '>=', $count = 1, $boolean = 'and') { $this->query->addBinding($query->getBindings(), 'where'); return $this->where( new Expression('('.$query->toSql().')'), $operator, is_numeric($count) ? new Expression($count) : $count, $boolean ); } /** * Get the "has relation" base query instance. * * @param string $relation * @return \Illuminate\Database\Eloquent\Relations\Relation */ protected function getRelationWithoutConstraints($relation) { return Relation::noConstraints(function () use ($relation) { return $this->getModel()->{$relation}(); }); } /** * Check if we can run an "exists" query to optimize performance. * * @param string $operator * @param int $count * @return bool */ protected function canUseExistsForExistenceCheck($operator, $count) { return ($operator === '>=' || $operator === '<') && $count === 1; } } database/Eloquent/Concerns/HasTimestamps.php 0000644 00000005666 14736103231 0015166 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Concerns; use Illuminate\Support\Facades\Date; trait HasTimestamps { /** * Indicates if the model should be timestamped. * * @var bool */ public $timestamps = true; /** * Update the model's update timestamp. * * @return bool */ public function touch() { if (! $this->usesTimestamps()) { return false; } $this->updateTimestamps(); return $this->save(); } /** * Update the creation and update timestamps. * * @return void */ protected function updateTimestamps() { $time = $this->freshTimestamp(); $updatedAtColumn = $this->getUpdatedAtColumn(); if (! is_null($updatedAtColumn) && ! $this->isDirty($updatedAtColumn)) { $this->setUpdatedAt($time); } $createdAtColumn = $this->getCreatedAtColumn(); if (! $this->exists && ! is_null($createdAtColumn) && ! $this->isDirty($createdAtColumn)) { $this->setCreatedAt($time); } } /** * Set the value of the "created at" attribute. * * @param mixed $value * @return $this */ public function setCreatedAt($value) { $this->{$this->getCreatedAtColumn()} = $value; return $this; } /** * Set the value of the "updated at" attribute. * * @param mixed $value * @return $this */ public function setUpdatedAt($value) { $this->{$this->getUpdatedAtColumn()} = $value; return $this; } /** * Get a fresh timestamp for the model. * * @return \Illuminate\Support\Carbon */ public function freshTimestamp() { return Date::now(); } /** * Get a fresh timestamp for the model. * * @return string */ public function freshTimestampString() { return $this->fromDateTime($this->freshTimestamp()); } /** * Determine if the model uses timestamps. * * @return bool */ public function usesTimestamps() { return $this->timestamps; } /** * Get the name of the "created at" column. * * @return string */ public function getCreatedAtColumn() { return static::CREATED_AT; } /** * Get the name of the "updated at" column. * * @return string */ public function getUpdatedAtColumn() { return static::UPDATED_AT; } /** * Get the fully qualified "created at" column. * * @return string */ public function getQualifiedCreatedAtColumn() { return $this->qualifyColumn($this->getCreatedAtColumn()); } /** * Get the fully qualified "updated at" column. * * @return string */ public function getQualifiedUpdatedAtColumn() { return $this->qualifyColumn($this->getUpdatedAtColumn()); } } database/Eloquent/Concerns/HasRelationships.php 0000644 00000067046 14736103231 0015664 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Concerns; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasManyThrough; use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\Relations\HasOneThrough; use Illuminate\Database\Eloquent\Relations\MorphMany; use Illuminate\Database\Eloquent\Relations\MorphOne; use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Database\Eloquent\Relations\MorphToMany; use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Support\Arr; use Illuminate\Support\Str; trait HasRelationships { /** * The loaded relationships for the model. * * @var array */ protected $relations = []; /** * The relationships that should be touched on save. * * @var array */ protected $touches = []; /** * The many to many relationship methods. * * @var array */ public static $manyMethods = [ 'belongsToMany', 'morphToMany', 'morphedByMany', ]; /** * Define a one-to-one relationship. * * @param string $related * @param string|null $foreignKey * @param string|null $localKey * @return \Illuminate\Database\Eloquent\Relations\HasOne */ public function hasOne($related, $foreignKey = null, $localKey = null) { $instance = $this->newRelatedInstance($related); $foreignKey = $foreignKey ?: $this->getForeignKey(); $localKey = $localKey ?: $this->getKeyName(); return $this->newHasOne($instance->newQuery(), $this, $instance->getTable().'.'.$foreignKey, $localKey); } /** * Instantiate a new HasOne relationship. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Model $parent * @param string $foreignKey * @param string $localKey * @return \Illuminate\Database\Eloquent\Relations\HasOne */ protected function newHasOne(Builder $query, Model $parent, $foreignKey, $localKey) { return new HasOne($query, $parent, $foreignKey, $localKey); } /** * Define a has-one-through relationship. * * @param string $related * @param string $through * @param string|null $firstKey * @param string|null $secondKey * @param string|null $localKey * @param string|null $secondLocalKey * @return \Illuminate\Database\Eloquent\Relations\HasOneThrough */ public function hasOneThrough($related, $through, $firstKey = null, $secondKey = null, $localKey = null, $secondLocalKey = null) { $through = new $through; $firstKey = $firstKey ?: $this->getForeignKey(); $secondKey = $secondKey ?: $through->getForeignKey(); return $this->newHasOneThrough( $this->newRelatedInstance($related)->newQuery(), $this, $through, $firstKey, $secondKey, $localKey ?: $this->getKeyName(), $secondLocalKey ?: $through->getKeyName() ); } /** * Instantiate a new HasOneThrough relationship. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Model $farParent * @param \Illuminate\Database\Eloquent\Model $throughParent * @param string $firstKey * @param string $secondKey * @param string $localKey * @param string $secondLocalKey * @return \Illuminate\Database\Eloquent\Relations\HasOneThrough */ protected function newHasOneThrough(Builder $query, Model $farParent, Model $throughParent, $firstKey, $secondKey, $localKey, $secondLocalKey) { return new HasOneThrough($query, $farParent, $throughParent, $firstKey, $secondKey, $localKey, $secondLocalKey); } /** * Define a polymorphic one-to-one relationship. * * @param string $related * @param string $name * @param string|null $type * @param string|null $id * @param string|null $localKey * @return \Illuminate\Database\Eloquent\Relations\MorphOne */ public function morphOne($related, $name, $type = null, $id = null, $localKey = null) { $instance = $this->newRelatedInstance($related); [$type, $id] = $this->getMorphs($name, $type, $id); $table = $instance->getTable(); $localKey = $localKey ?: $this->getKeyName(); return $this->newMorphOne($instance->newQuery(), $this, $table.'.'.$type, $table.'.'.$id, $localKey); } /** * Instantiate a new MorphOne relationship. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Model $parent * @param string $type * @param string $id * @param string $localKey * @return \Illuminate\Database\Eloquent\Relations\MorphOne */ protected function newMorphOne(Builder $query, Model $parent, $type, $id, $localKey) { return new MorphOne($query, $parent, $type, $id, $localKey); } /** * Define an inverse one-to-one or many relationship. * * @param string $related * @param string|null $foreignKey * @param string|null $ownerKey * @param string|null $relation * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function belongsTo($related, $foreignKey = null, $ownerKey = null, $relation = null) { // If no relation name was given, we will use this debug backtrace to extract // the calling method's name and use that as the relationship name as most // of the time this will be what we desire to use for the relationships. if (is_null($relation)) { $relation = $this->guessBelongsToRelation(); } $instance = $this->newRelatedInstance($related); // If no foreign key was supplied, we can use a backtrace to guess the proper // foreign key name by using the name of the relationship function, which // when combined with an "_id" should conventionally match the columns. if (is_null($foreignKey)) { $foreignKey = Str::snake($relation).'_'.$instance->getKeyName(); } // Once we have the foreign key names, we'll just create a new Eloquent query // for the related models and returns the relationship instance which will // actually be responsible for retrieving and hydrating every relations. $ownerKey = $ownerKey ?: $instance->getKeyName(); return $this->newBelongsTo( $instance->newQuery(), $this, $foreignKey, $ownerKey, $relation ); } /** * Instantiate a new BelongsTo relationship. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Model $child * @param string $foreignKey * @param string $ownerKey * @param string $relation * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ protected function newBelongsTo(Builder $query, Model $child, $foreignKey, $ownerKey, $relation) { return new BelongsTo($query, $child, $foreignKey, $ownerKey, $relation); } /** * Define a polymorphic, inverse one-to-one or many relationship. * * @param string|null $name * @param string|null $type * @param string|null $id * @param string|null $ownerKey * @return \Illuminate\Database\Eloquent\Relations\MorphTo */ public function morphTo($name = null, $type = null, $id = null, $ownerKey = null) { // If no name is provided, we will use the backtrace to get the function name // since that is most likely the name of the polymorphic interface. We can // use that to get both the class and foreign key that will be utilized. $name = $name ?: $this->guessBelongsToRelation(); [$type, $id] = $this->getMorphs( Str::snake($name), $type, $id ); // If the type value is null it is probably safe to assume we're eager loading // the relationship. In this case we'll just pass in a dummy query where we // need to remove any eager loads that may already be defined on a model. return empty($class = $this->{$type}) ? $this->morphEagerTo($name, $type, $id, $ownerKey) : $this->morphInstanceTo($class, $name, $type, $id, $ownerKey); } /** * Define a polymorphic, inverse one-to-one or many relationship. * * @param string $name * @param string $type * @param string $id * @param string $ownerKey * @return \Illuminate\Database\Eloquent\Relations\MorphTo */ protected function morphEagerTo($name, $type, $id, $ownerKey) { return $this->newMorphTo( $this->newQuery()->setEagerLoads([]), $this, $id, $ownerKey, $type, $name ); } /** * Define a polymorphic, inverse one-to-one or many relationship. * * @param string $target * @param string $name * @param string $type * @param string $id * @param string $ownerKey * @return \Illuminate\Database\Eloquent\Relations\MorphTo */ protected function morphInstanceTo($target, $name, $type, $id, $ownerKey) { $instance = $this->newRelatedInstance( static::getActualClassNameForMorph($target) ); return $this->newMorphTo( $instance->newQuery(), $this, $id, $ownerKey ?? $instance->getKeyName(), $type, $name ); } /** * Instantiate a new MorphTo relationship. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Model $parent * @param string $foreignKey * @param string $ownerKey * @param string $type * @param string $relation * @return \Illuminate\Database\Eloquent\Relations\MorphTo */ protected function newMorphTo(Builder $query, Model $parent, $foreignKey, $ownerKey, $type, $relation) { return new MorphTo($query, $parent, $foreignKey, $ownerKey, $type, $relation); } /** * Retrieve the actual class name for a given morph class. * * @param string $class * @return string */ public static function getActualClassNameForMorph($class) { return Arr::get(Relation::morphMap() ?: [], $class, $class); } /** * Guess the "belongs to" relationship name. * * @return string */ protected function guessBelongsToRelation() { [$one, $two, $caller] = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3); return $caller['function']; } /** * Define a one-to-many relationship. * * @param string $related * @param string|null $foreignKey * @param string|null $localKey * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function hasMany($related, $foreignKey = null, $localKey = null) { $instance = $this->newRelatedInstance($related); $foreignKey = $foreignKey ?: $this->getForeignKey(); $localKey = $localKey ?: $this->getKeyName(); return $this->newHasMany( $instance->newQuery(), $this, $instance->getTable().'.'.$foreignKey, $localKey ); } /** * Instantiate a new HasMany relationship. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Model $parent * @param string $foreignKey * @param string $localKey * @return \Illuminate\Database\Eloquent\Relations\HasMany */ protected function newHasMany(Builder $query, Model $parent, $foreignKey, $localKey) { return new HasMany($query, $parent, $foreignKey, $localKey); } /** * Define a has-many-through relationship. * * @param string $related * @param string $through * @param string|null $firstKey * @param string|null $secondKey * @param string|null $localKey * @param string|null $secondLocalKey * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough */ public function hasManyThrough($related, $through, $firstKey = null, $secondKey = null, $localKey = null, $secondLocalKey = null) { $through = new $through; $firstKey = $firstKey ?: $this->getForeignKey(); $secondKey = $secondKey ?: $through->getForeignKey(); return $this->newHasManyThrough( $this->newRelatedInstance($related)->newQuery(), $this, $through, $firstKey, $secondKey, $localKey ?: $this->getKeyName(), $secondLocalKey ?: $through->getKeyName() ); } /** * Instantiate a new HasManyThrough relationship. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Model $farParent * @param \Illuminate\Database\Eloquent\Model $throughParent * @param string $firstKey * @param string $secondKey * @param string $localKey * @param string $secondLocalKey * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough */ protected function newHasManyThrough(Builder $query, Model $farParent, Model $throughParent, $firstKey, $secondKey, $localKey, $secondLocalKey) { return new HasManyThrough($query, $farParent, $throughParent, $firstKey, $secondKey, $localKey, $secondLocalKey); } /** * Define a polymorphic one-to-many relationship. * * @param string $related * @param string $name * @param string|null $type * @param string|null $id * @param string|null $localKey * @return \Illuminate\Database\Eloquent\Relations\MorphMany */ public function morphMany($related, $name, $type = null, $id = null, $localKey = null) { $instance = $this->newRelatedInstance($related); // Here we will gather up the morph type and ID for the relationship so that we // can properly query the intermediate table of a relation. Finally, we will // get the table and create the relationship instances for the developers. [$type, $id] = $this->getMorphs($name, $type, $id); $table = $instance->getTable(); $localKey = $localKey ?: $this->getKeyName(); return $this->newMorphMany($instance->newQuery(), $this, $table.'.'.$type, $table.'.'.$id, $localKey); } /** * Instantiate a new MorphMany relationship. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Model $parent * @param string $type * @param string $id * @param string $localKey * @return \Illuminate\Database\Eloquent\Relations\MorphMany */ protected function newMorphMany(Builder $query, Model $parent, $type, $id, $localKey) { return new MorphMany($query, $parent, $type, $id, $localKey); } /** * Define a many-to-many relationship. * * @param string $related * @param string|null $table * @param string|null $foreignPivotKey * @param string|null $relatedPivotKey * @param string|null $parentKey * @param string|null $relatedKey * @param string|null $relation * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ public function belongsToMany($related, $table = null, $foreignPivotKey = null, $relatedPivotKey = null, $parentKey = null, $relatedKey = null, $relation = null) { // If no relationship name was passed, we will pull backtraces to get the // name of the calling function. We will use that function name as the // title of this relation since that is a great convention to apply. if (is_null($relation)) { $relation = $this->guessBelongsToManyRelation(); } // First, we'll need to determine the foreign key and "other key" for the // relationship. Once we have determined the keys we'll make the query // instances as well as the relationship instances we need for this. $instance = $this->newRelatedInstance($related); $foreignPivotKey = $foreignPivotKey ?: $this->getForeignKey(); $relatedPivotKey = $relatedPivotKey ?: $instance->getForeignKey(); // If no table name was provided, we can guess it by concatenating the two // models using underscores in alphabetical order. The two model names // are transformed to snake case from their default CamelCase also. if (is_null($table)) { $table = $this->joiningTable($related, $instance); } return $this->newBelongsToMany( $instance->newQuery(), $this, $table, $foreignPivotKey, $relatedPivotKey, $parentKey ?: $this->getKeyName(), $relatedKey ?: $instance->getKeyName(), $relation ); } /** * Instantiate a new BelongsToMany relationship. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Model $parent * @param string $table * @param string $foreignPivotKey * @param string $relatedPivotKey * @param string $parentKey * @param string $relatedKey * @param string|null $relationName * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ protected function newBelongsToMany(Builder $query, Model $parent, $table, $foreignPivotKey, $relatedPivotKey, $parentKey, $relatedKey, $relationName = null) { return new BelongsToMany($query, $parent, $table, $foreignPivotKey, $relatedPivotKey, $parentKey, $relatedKey, $relationName); } /** * Define a polymorphic many-to-many relationship. * * @param string $related * @param string $name * @param string|null $table * @param string|null $foreignPivotKey * @param string|null $relatedPivotKey * @param string|null $parentKey * @param string|null $relatedKey * @param bool $inverse * @return \Illuminate\Database\Eloquent\Relations\MorphToMany */ public function morphToMany($related, $name, $table = null, $foreignPivotKey = null, $relatedPivotKey = null, $parentKey = null, $relatedKey = null, $inverse = false) { $caller = $this->guessBelongsToManyRelation(); // First, we will need to determine the foreign key and "other key" for the // relationship. Once we have determined the keys we will make the query // instances, as well as the relationship instances we need for these. $instance = $this->newRelatedInstance($related); $foreignPivotKey = $foreignPivotKey ?: $name.'_id'; $relatedPivotKey = $relatedPivotKey ?: $instance->getForeignKey(); // Now we're ready to create a new query builder for this related model and // the relationship instances for this relation. This relations will set // appropriate query constraints then entirely manages the hydrations. if (! $table) { $words = preg_split('/(_)/u', $name, -1, PREG_SPLIT_DELIM_CAPTURE); $lastWord = array_pop($words); $table = implode('', $words).Str::plural($lastWord); } return $this->newMorphToMany( $instance->newQuery(), $this, $name, $table, $foreignPivotKey, $relatedPivotKey, $parentKey ?: $this->getKeyName(), $relatedKey ?: $instance->getKeyName(), $caller, $inverse ); } /** * Instantiate a new MorphToMany relationship. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Model $parent * @param string $name * @param string $table * @param string $foreignPivotKey * @param string $relatedPivotKey * @param string $parentKey * @param string $relatedKey * @param string|null $relationName * @param bool $inverse * @return \Illuminate\Database\Eloquent\Relations\MorphToMany */ protected function newMorphToMany(Builder $query, Model $parent, $name, $table, $foreignPivotKey, $relatedPivotKey, $parentKey, $relatedKey, $relationName = null, $inverse = false) { return new MorphToMany($query, $parent, $name, $table, $foreignPivotKey, $relatedPivotKey, $parentKey, $relatedKey, $relationName, $inverse); } /** * Define a polymorphic, inverse many-to-many relationship. * * @param string $related * @param string $name * @param string|null $table * @param string|null $foreignPivotKey * @param string|null $relatedPivotKey * @param string|null $parentKey * @param string|null $relatedKey * @return \Illuminate\Database\Eloquent\Relations\MorphToMany */ public function morphedByMany($related, $name, $table = null, $foreignPivotKey = null, $relatedPivotKey = null, $parentKey = null, $relatedKey = null) { $foreignPivotKey = $foreignPivotKey ?: $this->getForeignKey(); // For the inverse of the polymorphic many-to-many relations, we will change // the way we determine the foreign and other keys, as it is the opposite // of the morph-to-many method since we're figuring out these inverses. $relatedPivotKey = $relatedPivotKey ?: $name.'_id'; return $this->morphToMany( $related, $name, $table, $foreignPivotKey, $relatedPivotKey, $parentKey, $relatedKey, true ); } /** * Get the relationship name of the belongsToMany relationship. * * @return string|null */ protected function guessBelongsToManyRelation() { $caller = Arr::first(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), function ($trace) { return ! in_array( $trace['function'], array_merge(static::$manyMethods, ['guessBelongsToManyRelation']) ); }); return ! is_null($caller) ? $caller['function'] : null; } /** * Get the joining table name for a many-to-many relation. * * @param string $related * @param \Illuminate\Database\Eloquent\Model|null $instance * @return string */ public function joiningTable($related, $instance = null) { // The joining table name, by convention, is simply the snake cased models // sorted alphabetically and concatenated with an underscore, so we can // just sort the models and join them together to get the table name. $segments = [ $instance ? $instance->joiningTableSegment() : Str::snake(class_basename($related)), $this->joiningTableSegment(), ]; // Now that we have the model names in an array we can just sort them and // use the implode function to join them together with an underscores, // which is typically used by convention within the database system. sort($segments); return strtolower(implode('_', $segments)); } /** * Get this model's half of the intermediate table name for belongsToMany relationships. * * @return string */ public function joiningTableSegment() { return Str::snake(class_basename($this)); } /** * Determine if the model touches a given relation. * * @param string $relation * @return bool */ public function touches($relation) { return in_array($relation, $this->touches); } /** * Touch the owning relations of the model. * * @return void */ public function touchOwners() { foreach ($this->touches as $relation) { $this->$relation()->touch(); if ($this->$relation instanceof self) { $this->$relation->fireModelEvent('saved', false); $this->$relation->touchOwners(); } elseif ($this->$relation instanceof Collection) { $this->$relation->each->touchOwners(); } } } /** * Get the polymorphic relationship columns. * * @param string $name * @param string $type * @param string $id * @return array */ protected function getMorphs($name, $type, $id) { return [$type ?: $name.'_type', $id ?: $name.'_id']; } /** * Get the class name for polymorphic relations. * * @return string */ public function getMorphClass() { $morphMap = Relation::morphMap(); if (! empty($morphMap) && in_array(static::class, $morphMap)) { return array_search(static::class, $morphMap, true); } return static::class; } /** * Create a new model instance for a related model. * * @param string $class * @return mixed */ protected function newRelatedInstance($class) { return tap(new $class, function ($instance) { if (! $instance->getConnectionName()) { $instance->setConnection($this->connection); } }); } /** * Get all the loaded relations for the instance. * * @return array */ public function getRelations() { return $this->relations; } /** * Get a specified relationship. * * @param string $relation * @return mixed */ public function getRelation($relation) { return $this->relations[$relation]; } /** * Determine if the given relation is loaded. * * @param string $key * @return bool */ public function relationLoaded($key) { return array_key_exists($key, $this->relations); } /** * Set the given relationship on the model. * * @param string $relation * @param mixed $value * @return $this */ public function setRelation($relation, $value) { $this->relations[$relation] = $value; return $this; } /** * Unset a loaded relationship. * * @param string $relation * @return $this */ public function unsetRelation($relation) { unset($this->relations[$relation]); return $this; } /** * Set the entire relations array on the model. * * @param array $relations * @return $this */ public function setRelations(array $relations) { $this->relations = $relations; return $this; } /** * Duplicate the instance and unset all the loaded relations. * * @return $this */ public function withoutRelations() { $model = clone $this; return $model->unsetRelations(); } /** * Unset all the loaded relations for the instance. * * @return $this */ public function unsetRelations() { $this->relations = []; return $this; } /** * Get the relationships that are touched on save. * * @return array */ public function getTouchedRelations() { return $this->touches; } /** * Set the relationships that are touched on save. * * @param array $touches * @return $this */ public function setTouchedRelations(array $touches) { $this->touches = $touches; return $this; } } database/Eloquent/Concerns/GuardsAttributes.php 0000644 00000011277 14736103231 0015673 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Concerns; use Illuminate\Support\Str; trait GuardsAttributes { /** * The attributes that are mass assignable. * * @var array */ protected $fillable = []; /** * The attributes that aren't mass assignable. * * @var array */ protected $guarded = ['*']; /** * Indicates if all mass assignment is enabled. * * @var bool */ protected static $unguarded = false; /** * Get the fillable attributes for the model. * * @return array */ public function getFillable() { return $this->fillable; } /** * Set the fillable attributes for the model. * * @param array $fillable * @return $this */ public function fillable(array $fillable) { $this->fillable = $fillable; return $this; } /** * Merge new fillable attributes with existing fillable attributes on the model. * * @param array $fillable * @return $this */ public function mergeFillable(array $fillable) { $this->fillable = array_merge($this->fillable, $fillable); return $this; } /** * Get the guarded attributes for the model. * * @return array */ public function getGuarded() { return $this->guarded; } /** * Set the guarded attributes for the model. * * @param array $guarded * @return $this */ public function guard(array $guarded) { $this->guarded = $guarded; return $this; } /** * Merge new guarded attributes with existing guarded attributes on the model. * * @param array $guarded * @return $this */ public function mergeGuarded(array $guarded) { $this->guarded = array_merge($this->guarded, $guarded); return $this; } /** * Disable all mass assignable restrictions. * * @param bool $state * @return void */ public static function unguard($state = true) { static::$unguarded = $state; } /** * Enable the mass assignment restrictions. * * @return void */ public static function reguard() { static::$unguarded = false; } /** * Determine if current state is "unguarded". * * @return bool */ public static function isUnguarded() { return static::$unguarded; } /** * Run the given callable while being unguarded. * * @param callable $callback * @return mixed */ public static function unguarded(callable $callback) { if (static::$unguarded) { return $callback(); } static::unguard(); try { return $callback(); } finally { static::reguard(); } } /** * Determine if the given attribute may be mass assigned. * * @param string $key * @return bool */ public function isFillable($key) { if (static::$unguarded) { return true; } // If the key is in the "fillable" array, we can of course assume that it's // a fillable attribute. Otherwise, we will check the guarded array when // we need to determine if the attribute is black-listed on the model. if (in_array($key, $this->getFillable())) { return true; } // If the attribute is explicitly listed in the "guarded" array then we can // return false immediately. This means this attribute is definitely not // fillable and there is no point in going any further in this method. if ($this->isGuarded($key)) { return false; } return empty($this->getFillable()) && ! Str::startsWith($key, '_'); } /** * Determine if the given key is guarded. * * @param string $key * @return bool */ public function isGuarded($key) { return in_array($key, $this->getGuarded()) || $this->getGuarded() == ['*']; } /** * Determine if the model is totally guarded. * * @return bool */ public function totallyGuarded() { return count($this->getFillable()) === 0 && $this->getGuarded() == ['*']; } /** * Get the fillable attributes of a given array. * * @param array $attributes * @return array */ protected function fillableFromArray(array $attributes) { if (count($this->getFillable()) > 0 && ! static::$unguarded) { return array_intersect_key($attributes, array_flip($this->getFillable())); } return $attributes; } } database/Eloquent/Concerns/HasGlobalScopes.php 0000644 00000004026 14736103231 0015402 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Concerns; use Closure; use Illuminate\Database\Eloquent\Scope; use Illuminate\Support\Arr; use InvalidArgumentException; trait HasGlobalScopes { /** * Register a new global scope on the model. * * @param \Illuminate\Database\Eloquent\Scope|\Closure|string $scope * @param \Closure|null $implementation * @return mixed * * @throws \InvalidArgumentException */ public static function addGlobalScope($scope, Closure $implementation = null) { if (is_string($scope) && ! is_null($implementation)) { return static::$globalScopes[static::class][$scope] = $implementation; } elseif ($scope instanceof Closure) { return static::$globalScopes[static::class][spl_object_hash($scope)] = $scope; } elseif ($scope instanceof Scope) { return static::$globalScopes[static::class][get_class($scope)] = $scope; } throw new InvalidArgumentException('Global scope must be an instance of Closure or Scope.'); } /** * Determine if a model has a global scope. * * @param \Illuminate\Database\Eloquent\Scope|string $scope * @return bool */ public static function hasGlobalScope($scope) { return ! is_null(static::getGlobalScope($scope)); } /** * Get a global scope registered with the model. * * @param \Illuminate\Database\Eloquent\Scope|string $scope * @return \Illuminate\Database\Eloquent\Scope|\Closure|null */ public static function getGlobalScope($scope) { if (is_string($scope)) { return Arr::get(static::$globalScopes, static::class.'.'.$scope); } return Arr::get( static::$globalScopes, static::class.'.'.get_class($scope) ); } /** * Get the global scopes for this class instance. * * @return array */ public function getGlobalScopes() { return Arr::get(static::$globalScopes, static::class, []); } } database/Eloquent/Concerns/HasAttributes.php 0000644 00000123177 14736103231 0015164 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Concerns; use Carbon\CarbonInterface; use DateTimeInterface; use Illuminate\Contracts\Database\Eloquent\Castable; use Illuminate\Contracts\Database\Eloquent\CastsInboundAttributes; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Database\Eloquent\JsonEncodingException; use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Collection as BaseCollection; use Illuminate\Support\Facades\Date; use Illuminate\Support\Str; use LogicException; trait HasAttributes { /** * The model's attributes. * * @var array */ protected $attributes = []; /** * The model attribute's original state. * * @var array */ protected $original = []; /** * The changed model attributes. * * @var array */ protected $changes = []; /** * The attributes that should be cast. * * @var array */ protected $casts = []; /** * The attributes that have been cast using custom classes. * * @var array */ protected $classCastCache = []; /** * The built-in, primitive cast types supported by Eloquent. * * @var array */ protected static $primitiveCastTypes = [ 'array', 'bool', 'boolean', 'collection', 'custom_datetime', 'date', 'datetime', 'decimal', 'double', 'float', 'int', 'integer', 'json', 'object', 'real', 'string', 'timestamp', ]; /** * The attributes that should be mutated to dates. * * @var array */ protected $dates = []; /** * The storage format of the model's date columns. * * @var string */ protected $dateFormat; /** * The accessors to append to the model's array form. * * @var array */ protected $appends = []; /** * Indicates whether attributes are snake cased on arrays. * * @var bool */ public static $snakeAttributes = true; /** * The cache of the mutated attributes for each class. * * @var array */ protected static $mutatorCache = []; /** * Convert the model's attributes to an array. * * @return array */ public function attributesToArray() { // If an attribute is a date, we will cast it to a string after converting it // to a DateTime / Carbon instance. This is so we will get some consistent // formatting while accessing attributes vs. arraying / JSONing a model. $attributes = $this->addDateAttributesToArray( $attributes = $this->getArrayableAttributes() ); $attributes = $this->addMutatedAttributesToArray( $attributes, $mutatedAttributes = $this->getMutatedAttributes() ); // Next we will handle any casts that have been setup for this model and cast // the values to their appropriate type. If the attribute has a mutator we // will not perform the cast on those attributes to avoid any confusion. $attributes = $this->addCastAttributesToArray( $attributes, $mutatedAttributes ); // Here we will grab all of the appended, calculated attributes to this model // as these attributes are not really in the attributes array, but are run // when we need to array or JSON the model for convenience to the coder. foreach ($this->getArrayableAppends() as $key) { $attributes[$key] = $this->mutateAttributeForArray($key, null); } return $attributes; } /** * Add the date attributes to the attributes array. * * @param array $attributes * @return array */ protected function addDateAttributesToArray(array $attributes) { foreach ($this->getDates() as $key) { if (! isset($attributes[$key])) { continue; } $attributes[$key] = $this->serializeDate( $this->asDateTime($attributes[$key]) ); } return $attributes; } /** * Add the mutated attributes to the attributes array. * * @param array $attributes * @param array $mutatedAttributes * @return array */ protected function addMutatedAttributesToArray(array $attributes, array $mutatedAttributes) { foreach ($mutatedAttributes as $key) { // We want to spin through all the mutated attributes for this model and call // the mutator for the attribute. We cache off every mutated attributes so // we don't have to constantly check on attributes that actually change. if (! array_key_exists($key, $attributes)) { continue; } // Next, we will call the mutator for this attribute so that we can get these // mutated attribute's actual values. After we finish mutating each of the // attributes we will return this final array of the mutated attributes. $attributes[$key] = $this->mutateAttributeForArray( $key, $attributes[$key] ); } return $attributes; } /** * Add the casted attributes to the attributes array. * * @param array $attributes * @param array $mutatedAttributes * @return array */ protected function addCastAttributesToArray(array $attributes, array $mutatedAttributes) { foreach ($this->getCasts() as $key => $value) { if (! array_key_exists($key, $attributes) || in_array($key, $mutatedAttributes)) { continue; } // Here we will cast the attribute. Then, if the cast is a date or datetime cast // then we will serialize the date for the array. This will convert the dates // to strings based on the date format specified for these Eloquent models. $attributes[$key] = $this->castAttribute( $key, $attributes[$key] ); // If the attribute cast was a date or a datetime, we will serialize the date as // a string. This allows the developers to customize how dates are serialized // into an array without affecting how they are persisted into the storage. if ($attributes[$key] && ($value === 'date' || $value === 'datetime')) { $attributes[$key] = $this->serializeDate($attributes[$key]); } if ($attributes[$key] && $this->isCustomDateTimeCast($value)) { $attributes[$key] = $attributes[$key]->format(explode(':', $value, 2)[1]); } if ($attributes[$key] instanceof Arrayable) { $attributes[$key] = $attributes[$key]->toArray(); } } return $attributes; } /** * Get an attribute array of all arrayable attributes. * * @return array */ protected function getArrayableAttributes() { return $this->getArrayableItems($this->getAttributes()); } /** * Get all of the appendable values that are arrayable. * * @return array */ protected function getArrayableAppends() { if (! count($this->appends)) { return []; } return $this->getArrayableItems( array_combine($this->appends, $this->appends) ); } /** * Get the model's relationships in array form. * * @return array */ public function relationsToArray() { $attributes = []; foreach ($this->getArrayableRelations() as $key => $value) { // If the values implements the Arrayable interface we can just call this // toArray method on the instances which will convert both models and // collections to their proper array form and we'll set the values. if ($value instanceof Arrayable) { $relation = $value->toArray(); } // If the value is null, we'll still go ahead and set it in this list of // attributes since null is used to represent empty relationships if // if it a has one or belongs to type relationships on the models. elseif (is_null($value)) { $relation = $value; } // If the relationships snake-casing is enabled, we will snake case this // key so that the relation attribute is snake cased in this returned // array to the developers, making this consistent with attributes. if (static::$snakeAttributes) { $key = Str::snake($key); } // If the relation value has been set, we will set it on this attributes // list for returning. If it was not arrayable or null, we'll not set // the value on the array because it is some type of invalid value. if (isset($relation) || is_null($value)) { $attributes[$key] = $relation; } unset($relation); } return $attributes; } /** * Get an attribute array of all arrayable relations. * * @return array */ protected function getArrayableRelations() { return $this->getArrayableItems($this->relations); } /** * Get an attribute array of all arrayable values. * * @param array $values * @return array */ protected function getArrayableItems(array $values) { if (count($this->getVisible()) > 0) { $values = array_intersect_key($values, array_flip($this->getVisible())); } if (count($this->getHidden()) > 0) { $values = array_diff_key($values, array_flip($this->getHidden())); } return $values; } /** * Get an attribute from the model. * * @param string $key * @return mixed */ public function getAttribute($key) { if (! $key) { return; } // If the attribute exists in the attribute array or has a "get" mutator we will // get the attribute's value. Otherwise, we will proceed as if the developers // are asking for a relationship's value. This covers both types of values. if (array_key_exists($key, $this->attributes) || array_key_exists($key, $this->casts) || $this->hasGetMutator($key) || $this->isClassCastable($key)) { return $this->getAttributeValue($key); } // Here we will determine if the model base class itself contains this given key // since we don't want to treat any of those methods as relationships because // they are all intended as helper methods and none of these are relations. if (method_exists(self::class, $key)) { return; } return $this->getRelationValue($key); } /** * Get a plain attribute (not a relationship). * * @param string $key * @return mixed */ public function getAttributeValue($key) { return $this->transformModelValue($key, $this->getAttributeFromArray($key)); } /** * Get an attribute from the $attributes array. * * @param string $key * @return mixed */ protected function getAttributeFromArray($key) { return $this->getAttributes()[$key] ?? null; } /** * Get a relationship. * * @param string $key * @return mixed */ public function getRelationValue($key) { // If the key already exists in the relationships array, it just means the // relationship has already been loaded, so we'll just return it out of // here because there is no need to query within the relations twice. if ($this->relationLoaded($key)) { return $this->relations[$key]; } // If the "attribute" exists as a method on the model, we will just assume // it is a relationship and will load and return results from the query // and hydrate the relationship's value on the "relationships" array. if (method_exists($this, $key)) { return $this->getRelationshipFromMethod($key); } } /** * Get a relationship value from a method. * * @param string $method * @return mixed * * @throws \LogicException */ protected function getRelationshipFromMethod($method) { $relation = $this->$method(); if (! $relation instanceof Relation) { if (is_null($relation)) { throw new LogicException(sprintf( '%s::%s must return a relationship instance, but "null" was returned. Was the "return" keyword used?', static::class, $method )); } throw new LogicException(sprintf( '%s::%s must return a relationship instance.', static::class, $method )); } return tap($relation->getResults(), function ($results) use ($method) { $this->setRelation($method, $results); }); } /** * Determine if a get mutator exists for an attribute. * * @param string $key * @return bool */ public function hasGetMutator($key) { return method_exists($this, 'get'.Str::studly($key).'Attribute'); } /** * Get the value of an attribute using its mutator. * * @param string $key * @param mixed $value * @return mixed */ protected function mutateAttribute($key, $value) { return $this->{'get'.Str::studly($key).'Attribute'}($value); } /** * Get the value of an attribute using its mutator for array conversion. * * @param string $key * @param mixed $value * @return mixed */ protected function mutateAttributeForArray($key, $value) { $value = $this->isClassCastable($key) ? $this->getClassCastableAttributeValue($key, $value) : $this->mutateAttribute($key, $value); return $value instanceof Arrayable ? $value->toArray() : $value; } /** * Merge new casts with existing casts on the model. * * @param array $casts * @return void */ public function mergeCasts($casts) { $this->casts = array_merge($this->casts, $casts); } /** * Cast an attribute to a native PHP type. * * @param string $key * @param mixed $value * @return mixed */ protected function castAttribute($key, $value) { $castType = $this->getCastType($key); if (is_null($value) && in_array($castType, static::$primitiveCastTypes)) { return $value; } switch ($castType) { case 'int': case 'integer': return (int) $value; case 'real': case 'float': case 'double': return $this->fromFloat($value); case 'decimal': return $this->asDecimal($value, explode(':', $this->getCasts()[$key], 2)[1]); case 'string': return (string) $value; case 'bool': case 'boolean': return (bool) $value; case 'object': return $this->fromJson($value, true); case 'array': case 'json': return $this->fromJson($value); case 'collection': return new BaseCollection($this->fromJson($value)); case 'date': return $this->asDate($value); case 'datetime': case 'custom_datetime': return $this->asDateTime($value); case 'timestamp': return $this->asTimestamp($value); } if ($this->isClassCastable($key)) { return $this->getClassCastableAttributeValue($key, $value); } return $value; } /** * Cast the given attribute using a custom cast class. * * @param string $key * @param mixed $value * @return mixed */ protected function getClassCastableAttributeValue($key, $value) { if (isset($this->classCastCache[$key])) { return $this->classCastCache[$key]; } else { $caster = $this->resolveCasterClass($key); $value = $caster instanceof CastsInboundAttributes ? $value : $caster->get($this, $key, $value, $this->attributes); if ($caster instanceof CastsInboundAttributes || ! is_object($value)) { unset($this->classCastCache[$key]); } else { $this->classCastCache[$key] = $value; } return $value; } } /** * Get the type of cast for a model attribute. * * @param string $key * @return string */ protected function getCastType($key) { if ($this->isCustomDateTimeCast($this->getCasts()[$key])) { return 'custom_datetime'; } if ($this->isDecimalCast($this->getCasts()[$key])) { return 'decimal'; } return trim(strtolower($this->getCasts()[$key])); } /** * Determine if the cast type is a custom date time cast. * * @param string $cast * @return bool */ protected function isCustomDateTimeCast($cast) { return strncmp($cast, 'date:', 5) === 0 || strncmp($cast, 'datetime:', 9) === 0; } /** * Determine if the cast type is a decimal cast. * * @param string $cast * @return bool */ protected function isDecimalCast($cast) { return strncmp($cast, 'decimal:', 8) === 0; } /** * Set a given attribute on the model. * * @param string $key * @param mixed $value * @return mixed */ public function setAttribute($key, $value) { // First we will check for the presence of a mutator for the set operation // which simply lets the developers tweak the attribute as it is set on // the model, such as "json_encoding" an listing of data for storage. if ($this->hasSetMutator($key)) { return $this->setMutatedAttributeValue($key, $value); } // If an attribute is listed as a "date", we'll convert it from a DateTime // instance into a form proper for storage on the database tables using // the connection grammar's date format. We will auto set the values. elseif ($value && $this->isDateAttribute($key)) { $value = $this->fromDateTime($value); } if ($this->isClassCastable($key)) { $this->setClassCastableAttribute($key, $value); return $this; } if ($this->isJsonCastable($key) && ! is_null($value)) { $value = $this->castAttributeAsJson($key, $value); } // If this attribute contains a JSON ->, we'll set the proper value in the // attribute's underlying array. This takes care of properly nesting an // attribute in the array's value in the case of deeply nested items. if (Str::contains($key, '->')) { return $this->fillJsonAttribute($key, $value); } $this->attributes[$key] = $value; return $this; } /** * Determine if a set mutator exists for an attribute. * * @param string $key * @return bool */ public function hasSetMutator($key) { return method_exists($this, 'set'.Str::studly($key).'Attribute'); } /** * Set the value of an attribute using its mutator. * * @param string $key * @param mixed $value * @return mixed */ protected function setMutatedAttributeValue($key, $value) { return $this->{'set'.Str::studly($key).'Attribute'}($value); } /** * Determine if the given attribute is a date or date castable. * * @param string $key * @return bool */ protected function isDateAttribute($key) { return in_array($key, $this->getDates(), true) || $this->isDateCastable($key); } /** * Set a given JSON attribute on the model. * * @param string $key * @param mixed $value * @return $this */ public function fillJsonAttribute($key, $value) { [$key, $path] = explode('->', $key, 2); $this->attributes[$key] = $this->asJson($this->getArrayAttributeWithValue( $path, $key, $value )); return $this; } /** * Set the value of a class castable attribute. * * @param string $key * @param mixed $value * @return void */ protected function setClassCastableAttribute($key, $value) { $caster = $this->resolveCasterClass($key); if (is_null($value)) { $this->attributes = array_merge($this->attributes, array_map( function () { }, $this->normalizeCastClassResponse($key, $caster->set( $this, $key, $this->{$key}, $this->attributes )) )); } else { $this->attributes = array_merge( $this->attributes, $this->normalizeCastClassResponse($key, $caster->set( $this, $key, $value, $this->attributes )) ); } if ($caster instanceof CastsInboundAttributes || ! is_object($value)) { unset($this->classCastCache[$key]); } else { $this->classCastCache[$key] = $value; } } /** * Get an array attribute with the given key and value set. * * @param string $path * @param string $key * @param mixed $value * @return $this */ protected function getArrayAttributeWithValue($path, $key, $value) { return tap($this->getArrayAttributeByKey($key), function (&$array) use ($path, $value) { Arr::set($array, str_replace('->', '.', $path), $value); }); } /** * Get an array attribute or return an empty array if it is not set. * * @param string $key * @return array */ protected function getArrayAttributeByKey($key) { return isset($this->attributes[$key]) ? $this->fromJson($this->attributes[$key]) : []; } /** * Cast the given attribute to JSON. * * @param string $key * @param mixed $value * @return string */ protected function castAttributeAsJson($key, $value) { $value = $this->asJson($value); if ($value === false) { throw JsonEncodingException::forAttribute( $this, $key, json_last_error_msg() ); } return $value; } /** * Encode the given value as JSON. * * @param mixed $value * @return string */ protected function asJson($value) { return json_encode($value); } /** * Decode the given JSON back into an array or object. * * @param string $value * @param bool $asObject * @return mixed */ public function fromJson($value, $asObject = false) { return json_decode($value, ! $asObject); } /** * Decode the given float. * * @param mixed $value * @return mixed */ public function fromFloat($value) { switch ((string) $value) { case 'Infinity': return INF; case '-Infinity': return -INF; case 'NaN': return NAN; default: return (float) $value; } } /** * Return a decimal as string. * * @param float $value * @param int $decimals * @return string */ protected function asDecimal($value, $decimals) { return number_format($value, $decimals, '.', ''); } /** * Return a timestamp as DateTime object with time set to 00:00:00. * * @param mixed $value * @return \Illuminate\Support\Carbon */ protected function asDate($value) { return $this->asDateTime($value)->startOfDay(); } /** * Return a timestamp as DateTime object. * * @param mixed $value * @return \Illuminate\Support\Carbon */ protected function asDateTime($value) { // If this value is already a Carbon instance, we shall just return it as is. // This prevents us having to re-instantiate a Carbon instance when we know // it already is one, which wouldn't be fulfilled by the DateTime check. if ($value instanceof CarbonInterface) { return Date::instance($value); } // If the value is already a DateTime instance, we will just skip the rest of // these checks since they will be a waste of time, and hinder performance // when checking the field. We will just return the DateTime right away. if ($value instanceof DateTimeInterface) { return Date::parse( $value->format('Y-m-d H:i:s.u'), $value->getTimezone() ); } // If this value is an integer, we will assume it is a UNIX timestamp's value // and format a Carbon object from this timestamp. This allows flexibility // when defining your date fields as they might be UNIX timestamps here. if (is_numeric($value)) { return Date::createFromTimestamp($value); } // If the value is in simply year, month, day format, we will instantiate the // Carbon instances from that format. Again, this provides for simple date // fields on the database, while still supporting Carbonized conversion. if ($this->isStandardDateFormat($value)) { return Date::instance(Carbon::createFromFormat('Y-m-d', $value)->startOfDay()); } $format = $this->getDateFormat(); // Finally, we will just assume this date is in the format used by default on // the database connection and use that format to create the Carbon object // that is returned back out to the developers after we convert it here. if (Date::hasFormat($value, $format)) { return Date::createFromFormat($format, $value); } return Date::parse($value); } /** * Determine if the given value is a standard date format. * * @param string $value * @return bool */ protected function isStandardDateFormat($value) { return preg_match('/^(\d{4})-(\d{1,2})-(\d{1,2})$/', $value); } /** * Convert a DateTime to a storable string. * * @param mixed $value * @return string|null */ public function fromDateTime($value) { return empty($value) ? $value : $this->asDateTime($value)->format( $this->getDateFormat() ); } /** * Return a timestamp as unix timestamp. * * @param mixed $value * @return int */ protected function asTimestamp($value) { return $this->asDateTime($value)->getTimestamp(); } /** * Prepare a date for array / JSON serialization. * * @param \DateTimeInterface $date * @return string */ protected function serializeDate(DateTimeInterface $date) { return Carbon::instance($date)->toJSON(); } /** * Get the attributes that should be converted to dates. * * @return array */ public function getDates() { $defaults = [ $this->getCreatedAtColumn(), $this->getUpdatedAtColumn(), ]; return $this->usesTimestamps() ? array_unique(array_merge($this->dates, $defaults)) : $this->dates; } /** * Get the format for database stored dates. * * @return string */ public function getDateFormat() { return $this->dateFormat ?: $this->getConnection()->getQueryGrammar()->getDateFormat(); } /** * Set the date format used by the model. * * @param string $format * @return $this */ public function setDateFormat($format) { $this->dateFormat = $format; return $this; } /** * Determine whether an attribute should be cast to a native type. * * @param string $key * @param array|string|null $types * @return bool */ public function hasCast($key, $types = null) { if (array_key_exists($key, $this->getCasts())) { return $types ? in_array($this->getCastType($key), (array) $types, true) : true; } return false; } /** * Get the casts array. * * @return array */ public function getCasts() { if ($this->getIncrementing()) { return array_merge([$this->getKeyName() => $this->getKeyType()], $this->casts); } return $this->casts; } /** * Determine whether a value is Date / DateTime castable for inbound manipulation. * * @param string $key * @return bool */ protected function isDateCastable($key) { return $this->hasCast($key, ['date', 'datetime']); } /** * Determine whether a value is JSON castable for inbound manipulation. * * @param string $key * @return bool */ protected function isJsonCastable($key) { return $this->hasCast($key, ['array', 'json', 'object', 'collection']); } /** * Determine if the given key is cast using a custom class. * * @param string $key * @return bool */ protected function isClassCastable($key) { return array_key_exists($key, $this->getCasts()) && class_exists($class = $this->parseCasterClass($this->getCasts()[$key])) && ! in_array($class, static::$primitiveCastTypes); } /** * Resolve the custom caster class for a given key. * * @param string $key * @return mixed */ protected function resolveCasterClass($key) { $castType = $this->getCasts()[$key]; $arguments = []; if (is_string($castType) && strpos($castType, ':') !== false) { $segments = explode(':', $castType, 2); $castType = $segments[0]; $arguments = explode(',', $segments[1]); } if (is_subclass_of($castType, Castable::class)) { $castType = $castType::castUsing(); } if (is_object($castType)) { return $castType; } return new $castType(...$arguments); } /** * Parse the given caster class, removing any arguments. * * @param string $class * @return string */ protected function parseCasterClass($class) { return strpos($class, ':') === false ? $class : explode(':', $class, 2)[0]; } /** * Merge the cast class attributes back into the model. * * @return void */ protected function mergeAttributesFromClassCasts() { foreach ($this->classCastCache as $key => $value) { $caster = $this->resolveCasterClass($key); $this->attributes = array_merge( $this->attributes, $caster instanceof CastsInboundAttributes ? [$key => $value] : $this->normalizeCastClassResponse($key, $caster->set($this, $key, $value, $this->attributes)) ); } } /** * Normalize the response from a custom class caster. * * @param string $key * @param mixed $value * @return array */ protected function normalizeCastClassResponse($key, $value) { return is_array($value) ? $value : [$key => $value]; } /** * Get all of the current attributes on the model. * * @return array */ public function getAttributes() { $this->mergeAttributesFromClassCasts(); return $this->attributes; } /** * Set the array of model attributes. No checking is done. * * @param array $attributes * @param bool $sync * @return $this */ public function setRawAttributes(array $attributes, $sync = false) { $this->attributes = $attributes; if ($sync) { $this->syncOriginal(); } $this->classCastCache = []; return $this; } /** * Get the model's original attribute values. * * @param string|null $key * @param mixed $default * @return mixed|array */ public function getOriginal($key = null, $default = null) { if ($key) { return $this->transformModelValue( $key, Arr::get($this->original, $key, $default) ); } return collect($this->original)->mapWithKeys(function ($value, $key) { return [$key => $this->transformModelValue($key, $value)]; })->all(); } /** * Get the model's raw original attribute values. * * @param string|null $key * @param mixed $default * @return mixed|array */ public function getRawOriginal($key = null, $default = null) { return Arr::get($this->original, $key, $default); } /** * Get a subset of the model's attributes. * * @param array|mixed $attributes * @return array */ public function only($attributes) { $results = []; foreach (is_array($attributes) ? $attributes : func_get_args() as $attribute) { $results[$attribute] = $this->getAttribute($attribute); } return $results; } /** * Sync the original attributes with the current. * * @return $this */ public function syncOriginal() { $this->original = $this->getAttributes(); return $this; } /** * Sync a single original attribute with its current value. * * @param string $attribute * @return $this */ public function syncOriginalAttribute($attribute) { return $this->syncOriginalAttributes($attribute); } /** * Sync multiple original attribute with their current values. * * @param array|string $attributes * @return $this */ public function syncOriginalAttributes($attributes) { $attributes = is_array($attributes) ? $attributes : func_get_args(); $modelAttributes = $this->getAttributes(); foreach ($attributes as $attribute) { $this->original[$attribute] = $modelAttributes[$attribute]; } return $this; } /** * Sync the changed attributes. * * @return $this */ public function syncChanges() { $this->changes = $this->getDirty(); return $this; } /** * Determine if the model or any of the given attribute(s) have been modified. * * @param array|string|null $attributes * @return bool */ public function isDirty($attributes = null) { return $this->hasChanges( $this->getDirty(), is_array($attributes) ? $attributes : func_get_args() ); } /** * Determine if the model and all the given attribute(s) have remained the same. * * @param array|string|null $attributes * @return bool */ public function isClean($attributes = null) { return ! $this->isDirty(...func_get_args()); } /** * Determine if the model or any of the given attribute(s) have been modified. * * @param array|string|null $attributes * @return bool */ public function wasChanged($attributes = null) { return $this->hasChanges( $this->getChanges(), is_array($attributes) ? $attributes : func_get_args() ); } /** * Determine if any of the given attributes were changed. * * @param array $changes * @param array|string|null $attributes * @return bool */ protected function hasChanges($changes, $attributes = null) { // If no specific attributes were provided, we will just see if the dirty array // already contains any attributes. If it does we will just return that this // count is greater than zero. Else, we need to check specific attributes. if (empty($attributes)) { return count($changes) > 0; } // Here we will spin through every attribute and see if this is in the array of // dirty attributes. If it is, we will return true and if we make it through // all of the attributes for the entire array we will return false at end. foreach (Arr::wrap($attributes) as $attribute) { if (array_key_exists($attribute, $changes)) { return true; } } return false; } /** * Get the attributes that have been changed since last sync. * * @return array */ public function getDirty() { $dirty = []; foreach ($this->getAttributes() as $key => $value) { if (! $this->originalIsEquivalent($key)) { $dirty[$key] = $value; } } return $dirty; } /** * Get the attributes that were changed. * * @return array */ public function getChanges() { return $this->changes; } /** * Determine if the new and old values for a given key are equivalent. * * @param string $key * @return bool */ public function originalIsEquivalent($key) { if (! array_key_exists($key, $this->original)) { return false; } $attribute = Arr::get($this->attributes, $key); $original = Arr::get($this->original, $key); if ($attribute === $original) { return true; } elseif (is_null($attribute)) { return false; } elseif ($this->isDateAttribute($key)) { return $this->fromDateTime($attribute) === $this->fromDateTime($original); } elseif ($this->hasCast($key, ['object', 'collection'])) { return $this->castAttribute($key, $attribute) == $this->castAttribute($key, $original); } elseif ($this->hasCast($key, static::$primitiveCastTypes)) { return $this->castAttribute($key, $attribute) === $this->castAttribute($key, $original); } return is_numeric($attribute) && is_numeric($original) && strcmp((string) $attribute, (string) $original) === 0; } /** * Transform a raw model value using mutators, casts, etc. * * @param string $key * @param mixed $value * @return mixed */ protected function transformModelValue($key, $value) { // If the attribute has a get mutator, we will call that then return what // it returns as the value, which is useful for transforming values on // retrieval from the model to a form that is more useful for usage. if ($this->hasGetMutator($key)) { return $this->mutateAttribute($key, $value); } // If the attribute exists within the cast array, we will convert it to // an appropriate native PHP type dependent upon the associated value // given with the key in the pair. Dayle made this comment line up. if ($this->hasCast($key)) { return $this->castAttribute($key, $value); } // If the attribute is listed as a date, we will convert it to a DateTime // instance on retrieval, which makes it quite convenient to work with // date fields without having to create a mutator for each property. if ($value !== null && \in_array($key, $this->getDates(), false)) { return $this->asDateTime($value); } return $value; } /** * Append attributes to query when building a query. * * @param array|string $attributes * @return $this */ public function append($attributes) { $this->appends = array_unique( array_merge($this->appends, is_string($attributes) ? func_get_args() : $attributes) ); return $this; } /** * Set the accessors to append to model arrays. * * @param array $appends * @return $this */ public function setAppends(array $appends) { $this->appends = $appends; return $this; } /** * Get the mutated attributes for a given instance. * * @return array */ public function getMutatedAttributes() { $class = static::class; if (! isset(static::$mutatorCache[$class])) { static::cacheMutatedAttributes($class); } return static::$mutatorCache[$class]; } /** * Extract and cache all the mutated attributes of a class. * * @param string $class * @return void */ public static function cacheMutatedAttributes($class) { static::$mutatorCache[$class] = collect(static::getMutatorMethods($class))->map(function ($match) { return lcfirst(static::$snakeAttributes ? Str::snake($match) : $match); })->all(); } /** * Get all of the attribute mutator methods. * * @param mixed $class * @return array */ protected static function getMutatorMethods($class) { preg_match_all('/(?<=^|;)get([^;]+?)Attribute(;|$)/', implode(';', get_class_methods($class)), $matches); return $matches[1]; } } database/Eloquent/Concerns/HasEvents.php 0000644 00000023662 14736103231 0014300 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Concerns; use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Support\Arr; use InvalidArgumentException; trait HasEvents { /** * The event map for the model. * * Allows for object-based events for native Eloquent events. * * @var array */ protected $dispatchesEvents = []; /** * User exposed observable events. * * These are extra user-defined events observers may subscribe to. * * @var array */ protected $observables = []; /** * Register observers with the model. * * @param object|array|string $classes * @return void * * @throws \RuntimeException */ public static function observe($classes) { $instance = new static; foreach (Arr::wrap($classes) as $class) { $instance->registerObserver($class); } } /** * Register a single observer with the model. * * @param object|string $class * @return void * * @throws \RuntimeException */ protected function registerObserver($class) { $className = $this->resolveObserverClassName($class); // When registering a model observer, we will spin through the possible events // and determine if this observer has that method. If it does, we will hook // it into the model's event system, making it convenient to watch these. foreach ($this->getObservableEvents() as $event) { if (method_exists($class, $event)) { static::registerModelEvent($event, $className.'@'.$event); } } } /** * Resolve the observer's class name from an object or string. * * @param object|string $class * @return string * * @throws \InvalidArgumentException */ private function resolveObserverClassName($class) { if (is_object($class)) { return get_class($class); } if (class_exists($class)) { return $class; } throw new InvalidArgumentException('Unable to find observer: '.$class); } /** * Get the observable event names. * * @return array */ public function getObservableEvents() { return array_merge( [ 'retrieved', 'creating', 'created', 'updating', 'updated', 'saving', 'saved', 'restoring', 'restored', 'replicating', 'deleting', 'deleted', 'forceDeleted', ], $this->observables ); } /** * Set the observable event names. * * @param array $observables * @return $this */ public function setObservableEvents(array $observables) { $this->observables = $observables; return $this; } /** * Add an observable event name. * * @param array|mixed $observables * @return void */ public function addObservableEvents($observables) { $this->observables = array_unique(array_merge( $this->observables, is_array($observables) ? $observables : func_get_args() )); } /** * Remove an observable event name. * * @param array|mixed $observables * @return void */ public function removeObservableEvents($observables) { $this->observables = array_diff( $this->observables, is_array($observables) ? $observables : func_get_args() ); } /** * Register a model event with the dispatcher. * * @param string $event * @param \Closure|string $callback * @return void */ protected static function registerModelEvent($event, $callback) { if (isset(static::$dispatcher)) { $name = static::class; static::$dispatcher->listen("eloquent.{$event}: {$name}", $callback); } } /** * Fire the given event for the model. * * @param string $event * @param bool $halt * @return mixed */ protected function fireModelEvent($event, $halt = true) { if (! isset(static::$dispatcher)) { return true; } // First, we will get the proper method to call on the event dispatcher, and then we // will attempt to fire a custom, object based event for the given event. If that // returns a result we can return that result, or we'll call the string events. $method = $halt ? 'until' : 'dispatch'; $result = $this->filterModelEventResults( $this->fireCustomModelEvent($event, $method) ); if ($result === false) { return false; } return ! empty($result) ? $result : static::$dispatcher->{$method}( "eloquent.{$event}: ".static::class, $this ); } /** * Fire a custom model event for the given event. * * @param string $event * @param string $method * @return mixed|null */ protected function fireCustomModelEvent($event, $method) { if (! isset($this->dispatchesEvents[$event])) { return; } $result = static::$dispatcher->$method(new $this->dispatchesEvents[$event]($this)); if (! is_null($result)) { return $result; } } /** * Filter the model event results. * * @param mixed $result * @return mixed */ protected function filterModelEventResults($result) { if (is_array($result)) { $result = array_filter($result, function ($response) { return ! is_null($response); }); } return $result; } /** * Register a retrieved model event with the dispatcher. * * @param \Closure|string $callback * @return void */ public static function retrieved($callback) { static::registerModelEvent('retrieved', $callback); } /** * Register a saving model event with the dispatcher. * * @param \Closure|string $callback * @return void */ public static function saving($callback) { static::registerModelEvent('saving', $callback); } /** * Register a saved model event with the dispatcher. * * @param \Closure|string $callback * @return void */ public static function saved($callback) { static::registerModelEvent('saved', $callback); } /** * Register an updating model event with the dispatcher. * * @param \Closure|string $callback * @return void */ public static function updating($callback) { static::registerModelEvent('updating', $callback); } /** * Register an updated model event with the dispatcher. * * @param \Closure|string $callback * @return void */ public static function updated($callback) { static::registerModelEvent('updated', $callback); } /** * Register a creating model event with the dispatcher. * * @param \Closure|string $callback * @return void */ public static function creating($callback) { static::registerModelEvent('creating', $callback); } /** * Register a created model event with the dispatcher. * * @param \Closure|string $callback * @return void */ public static function created($callback) { static::registerModelEvent('created', $callback); } /** * Register a replicating model event with the dispatcher. * * @param \Closure|string $callback * @return void */ public static function replicating($callback) { static::registerModelEvent('replicating', $callback); } /** * Register a deleting model event with the dispatcher. * * @param \Closure|string $callback * @return void */ public static function deleting($callback) { static::registerModelEvent('deleting', $callback); } /** * Register a deleted model event with the dispatcher. * * @param \Closure|string $callback * @return void */ public static function deleted($callback) { static::registerModelEvent('deleted', $callback); } /** * Remove all of the event listeners for the model. * * @return void */ public static function flushEventListeners() { if (! isset(static::$dispatcher)) { return; } $instance = new static; foreach ($instance->getObservableEvents() as $event) { static::$dispatcher->forget("eloquent.{$event}: ".static::class); } foreach (array_values($instance->dispatchesEvents) as $event) { static::$dispatcher->forget($event); } } /** * Get the event dispatcher instance. * * @return \Illuminate\Contracts\Events\Dispatcher */ public static function getEventDispatcher() { return static::$dispatcher; } /** * Set the event dispatcher instance. * * @param \Illuminate\Contracts\Events\Dispatcher $dispatcher * @return void */ public static function setEventDispatcher(Dispatcher $dispatcher) { static::$dispatcher = $dispatcher; } /** * Unset the event dispatcher for models. * * @return void */ public static function unsetEventDispatcher() { static::$dispatcher = null; } /** * Execute a callback without firing any model events for any model type. * * @param callable $callback * @return mixed */ public static function withoutEvents(callable $callback) { $dispatcher = static::getEventDispatcher(); static::unsetEventDispatcher(); try { return $callback(); } finally { if ($dispatcher) { static::setEventDispatcher($dispatcher); } } } } database/Eloquent/SoftDeletingScope.php 0000644 00000007046 14736103231 0014205 0 ustar 00 <?php namespace Illuminate\Database\Eloquent; class SoftDeletingScope implements Scope { /** * All of the extensions to be added to the builder. * * @var array */ protected $extensions = ['Restore', 'WithTrashed', 'WithoutTrashed', 'OnlyTrashed']; /** * Apply the scope to a given Eloquent query builder. * * @param \Illuminate\Database\Eloquent\Builder $builder * @param \Illuminate\Database\Eloquent\Model $model * @return void */ public function apply(Builder $builder, Model $model) { $builder->whereNull($model->getQualifiedDeletedAtColumn()); } /** * Extend the query builder with the needed functions. * * @param \Illuminate\Database\Eloquent\Builder $builder * @return void */ public function extend(Builder $builder) { foreach ($this->extensions as $extension) { $this->{"add{$extension}"}($builder); } $builder->onDelete(function (Builder $builder) { $column = $this->getDeletedAtColumn($builder); return $builder->update([ $column => $builder->getModel()->freshTimestampString(), ]); }); } /** * Get the "deleted at" column for the builder. * * @param \Illuminate\Database\Eloquent\Builder $builder * @return string */ protected function getDeletedAtColumn(Builder $builder) { if (count((array) $builder->getQuery()->joins) > 0) { return $builder->getModel()->getQualifiedDeletedAtColumn(); } return $builder->getModel()->getDeletedAtColumn(); } /** * Add the restore extension to the builder. * * @param \Illuminate\Database\Eloquent\Builder $builder * @return void */ protected function addRestore(Builder $builder) { $builder->macro('restore', function (Builder $builder) { $builder->withTrashed(); return $builder->update([$builder->getModel()->getDeletedAtColumn() => null]); }); } /** * Add the with-trashed extension to the builder. * * @param \Illuminate\Database\Eloquent\Builder $builder * @return void */ protected function addWithTrashed(Builder $builder) { $builder->macro('withTrashed', function (Builder $builder, $withTrashed = true) { if (! $withTrashed) { return $builder->withoutTrashed(); } return $builder->withoutGlobalScope($this); }); } /** * Add the without-trashed extension to the builder. * * @param \Illuminate\Database\Eloquent\Builder $builder * @return void */ protected function addWithoutTrashed(Builder $builder) { $builder->macro('withoutTrashed', function (Builder $builder) { $model = $builder->getModel(); $builder->withoutGlobalScope($this)->whereNull( $model->getQualifiedDeletedAtColumn() ); return $builder; }); } /** * Add the only-trashed extension to the builder. * * @param \Illuminate\Database\Eloquent\Builder $builder * @return void */ protected function addOnlyTrashed(Builder $builder) { $builder->macro('onlyTrashed', function (Builder $builder) { $model = $builder->getModel(); $builder->withoutGlobalScope($this)->whereNotNull( $model->getQualifiedDeletedAtColumn() ); return $builder; }); } } database/Eloquent/Scope.php 0000644 00000000536 14736103231 0011672 0 ustar 00 <?php namespace Illuminate\Database\Eloquent; interface Scope { /** * Apply the scope to a given Eloquent query builder. * * @param \Illuminate\Database\Eloquent\Builder $builder * @param \Illuminate\Database\Eloquent\Model $model * @return void */ public function apply(Builder $builder, Model $model); } database/Eloquent/HigherOrderBuilderProxy.php 0000644 00000002055 14736103231 0015372 0 ustar 00 <?php namespace Illuminate\Database\Eloquent; /** * @mixin \Illuminate\Database\Eloquent\Builder */ class HigherOrderBuilderProxy { /** * The collection being operated on. * * @var \Illuminate\Database\Eloquent\Builder */ protected $builder; /** * The method being proxied. * * @var string */ protected $method; /** * Create a new proxy instance. * * @param \Illuminate\Database\Eloquent\Builder $builder * @param string $method * @return void */ public function __construct(Builder $builder, $method) { $this->method = $method; $this->builder = $builder; } /** * Proxy a scope call onto the query builder. * * @param string $method * @param array $parameters * @return mixed */ public function __call($method, $parameters) { return $this->builder->{$this->method}(function ($value) use ($method, $parameters) { return $value->{$method}(...$parameters); }); } } database/Eloquent/MassAssignmentException.php 0000644 00000000211 14736103231 0015422 0 ustar 00 <?php namespace Illuminate\Database\Eloquent; use RuntimeException; class MassAssignmentException extends RuntimeException { // } database/Eloquent/JsonEncodingException.php 0000644 00000002555 14736103231 0015063 0 ustar 00 <?php namespace Illuminate\Database\Eloquent; use RuntimeException; class JsonEncodingException extends RuntimeException { /** * Create a new JSON encoding exception for the model. * * @param mixed $model * @param string $message * @return static */ public static function forModel($model, $message) { return new static('Error encoding model ['.get_class($model).'] with ID ['.$model->getKey().'] to JSON: '.$message); } /** * Create a new JSON encoding exception for the resource. * * @param \Illuminate\Http\Resources\Json\JsonResource $resource * @param string $message * @return static */ public static function forResource($resource, $message) { $model = $resource->resource; return new static('Error encoding resource ['.get_class($resource).'] with model ['.get_class($model).'] with ID ['.$model->getKey().'] to JSON: '.$message); } /** * Create a new JSON encoding exception for an attribute. * * @param mixed $model * @param mixed $key * @param string $message * @return static */ public static function forAttribute($model, $key, $message) { $class = get_class($model); return new static("Unable to encode attribute [{$key}] for model [{$class}] to JSON: {$message}."); } } database/Eloquent/RelationNotFoundException.php 0000644 00000001431 14736103231 0015725 0 ustar 00 <?php namespace Illuminate\Database\Eloquent; use RuntimeException; class RelationNotFoundException extends RuntimeException { /** * The name of the affected Eloquent model. * * @var string */ public $model; /** * The name of the relation. * * @var string */ public $relation; /** * Create a new exception instance. * * @param object $model * @param string $relation * @return static */ public static function make($model, $relation) { $class = get_class($model); $instance = new static("Call to undefined relationship [{$relation}] on model [{$class}]."); $instance->model = $class; $instance->relation = $relation; return $instance; } } database/Eloquent/Collection.php 0000644 00000036631 14736103231 0012721 0 ustar 00 <?php namespace Illuminate\Database\Eloquent; use Illuminate\Contracts\Queue\QueueableCollection; use Illuminate\Contracts\Queue\QueueableEntity; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Support\Arr; use Illuminate\Support\Collection as BaseCollection; use Illuminate\Support\Str; use LogicException; class Collection extends BaseCollection implements QueueableCollection { /** * Find a model in the collection by key. * * @param mixed $key * @param mixed $default * @return \Illuminate\Database\Eloquent\Model|static|null */ public function find($key, $default = null) { if ($key instanceof Model) { $key = $key->getKey(); } if ($key instanceof Arrayable) { $key = $key->toArray(); } if (is_array($key)) { if ($this->isEmpty()) { return new static; } return $this->whereIn($this->first()->getKeyName(), $key); } return Arr::first($this->items, function ($model) use ($key) { return $model->getKey() == $key; }, $default); } /** * Load a set of relationships onto the collection. * * @param array|string $relations * @return $this */ public function load($relations) { if ($this->isNotEmpty()) { if (is_string($relations)) { $relations = func_get_args(); } $query = $this->first()->newQueryWithoutRelationships()->with($relations); $this->items = $query->eagerLoadRelations($this->items); } return $this; } /** * Load a set of relationship counts onto the collection. * * @param array|string $relations * @return $this */ public function loadCount($relations) { if ($this->isEmpty()) { return $this; } $models = $this->first()->newModelQuery() ->whereKey($this->modelKeys()) ->select($this->first()->getKeyName()) ->withCount(...func_get_args()) ->get(); $attributes = Arr::except( array_keys($models->first()->getAttributes()), $models->first()->getKeyName() ); $models->each(function ($model) use ($attributes) { $this->where($this->first()->getKeyName(), $model->getKey()) ->each ->forceFill(Arr::only($model->getAttributes(), $attributes)) ->each ->syncOriginalAttributes($attributes); }); return $this; } /** * Load a set of relationships onto the collection if they are not already eager loaded. * * @param array|string $relations * @return $this */ public function loadMissing($relations) { if (is_string($relations)) { $relations = func_get_args(); } foreach ($relations as $key => $value) { if (is_numeric($key)) { $key = $value; } $segments = explode('.', explode(':', $key)[0]); if (Str::contains($key, ':')) { $segments[count($segments) - 1] .= ':'.explode(':', $key)[1]; } $path = []; foreach ($segments as $segment) { $path[] = [$segment => $segment]; } if (is_callable($value)) { $path[count($segments) - 1][end($segments)] = $value; } $this->loadMissingRelation($this, $path); } return $this; } /** * Load a relationship path if it is not already eager loaded. * * @param \Illuminate\Database\Eloquent\Collection $models * @param array $path * @return void */ protected function loadMissingRelation(self $models, array $path) { $relation = array_shift($path); $name = explode(':', key($relation))[0]; if (is_string(reset($relation))) { $relation = reset($relation); } $models->filter(function ($model) use ($name) { return ! is_null($model) && ! $model->relationLoaded($name); })->load($relation); if (empty($path)) { return; } $models = $models->pluck($name); if ($models->first() instanceof BaseCollection) { $models = $models->collapse(); } $this->loadMissingRelation(new static($models), $path); } /** * Load a set of relationships onto the mixed relationship collection. * * @param string $relation * @param array $relations * @return $this */ public function loadMorph($relation, $relations) { $this->pluck($relation) ->filter() ->groupBy(function ($model) { return get_class($model); }) ->each(function ($models, $className) use ($relations) { static::make($models)->load($relations[$className] ?? []); }); return $this; } /** * Load a set of relationship counts onto the mixed relationship collection. * * @param string $relation * @param array $relations * @return $this */ public function loadMorphCount($relation, $relations) { $this->pluck($relation) ->filter() ->groupBy(function ($model) { return get_class($model); }) ->each(function ($models, $className) use ($relations) { static::make($models)->loadCount($relations[$className] ?? []); }); return $this; } /** * Determine if a key exists in the collection. * * @param mixed $key * @param mixed $operator * @param mixed $value * @return bool */ public function contains($key, $operator = null, $value = null) { if (func_num_args() > 1 || $this->useAsCallable($key)) { return parent::contains(...func_get_args()); } if ($key instanceof Model) { return parent::contains(function ($model) use ($key) { return $model->is($key); }); } return parent::contains(function ($model) use ($key) { return $model->getKey() == $key; }); } /** * Get the array of primary keys. * * @return array */ public function modelKeys() { return array_map(function ($model) { return $model->getKey(); }, $this->items); } /** * Merge the collection with the given items. * * @param \ArrayAccess|array $items * @return static */ public function merge($items) { $dictionary = $this->getDictionary(); foreach ($items as $item) { $dictionary[$item->getKey()] = $item; } return new static(array_values($dictionary)); } /** * Run a map over each of the items. * * @param callable $callback * @return \Illuminate\Support\Collection|static */ public function map(callable $callback) { $result = parent::map($callback); return $result->contains(function ($item) { return ! $item instanceof Model; }) ? $result->toBase() : $result; } /** * Reload a fresh model instance from the database for all the entities. * * @param array|string $with * @return static */ public function fresh($with = []) { if ($this->isEmpty()) { return new static; } $model = $this->first(); $freshModels = $model->newQueryWithoutScopes() ->with(is_string($with) ? func_get_args() : $with) ->whereIn($model->getKeyName(), $this->modelKeys()) ->get() ->getDictionary(); return $this->map(function ($model) use ($freshModels) { return $model->exists && isset($freshModels[$model->getKey()]) ? $freshModels[$model->getKey()] : null; }); } /** * Diff the collection with the given items. * * @param \ArrayAccess|array $items * @return static */ public function diff($items) { $diff = new static; $dictionary = $this->getDictionary($items); foreach ($this->items as $item) { if (! isset($dictionary[$item->getKey()])) { $diff->add($item); } } return $diff; } /** * Intersect the collection with the given items. * * @param \ArrayAccess|array $items * @return static */ public function intersect($items) { $intersect = new static; if (empty($items)) { return $intersect; } $dictionary = $this->getDictionary($items); foreach ($this->items as $item) { if (isset($dictionary[$item->getKey()])) { $intersect->add($item); } } return $intersect; } /** * Return only unique items from the collection. * * @param string|callable|null $key * @param bool $strict * @return static|\Illuminate\Support\Collection */ public function unique($key = null, $strict = false) { if (! is_null($key)) { return parent::unique($key, $strict); } return new static(array_values($this->getDictionary())); } /** * Returns only the models from the collection with the specified keys. * * @param mixed $keys * @return static */ public function only($keys) { if (is_null($keys)) { return new static($this->items); } $dictionary = Arr::only($this->getDictionary(), $keys); return new static(array_values($dictionary)); } /** * Returns all models in the collection except the models with specified keys. * * @param mixed $keys * @return static */ public function except($keys) { $dictionary = Arr::except($this->getDictionary(), $keys); return new static(array_values($dictionary)); } /** * Make the given, typically visible, attributes hidden across the entire collection. * * @param array|string $attributes * @return $this */ public function makeHidden($attributes) { return $this->each->makeHidden($attributes); } /** * Make the given, typically hidden, attributes visible across the entire collection. * * @param array|string $attributes * @return $this */ public function makeVisible($attributes) { return $this->each->makeVisible($attributes); } /** * Append an attribute across the entire collection. * * @param array|string $attributes * @return $this */ public function append($attributes) { return $this->each->append($attributes); } /** * Get a dictionary keyed by primary keys. * * @param \ArrayAccess|array|null $items * @return array */ public function getDictionary($items = null) { $items = is_null($items) ? $this->items : $items; $dictionary = []; foreach ($items as $value) { $dictionary[$value->getKey()] = $value; } return $dictionary; } /** * The following methods are intercepted to always return base collections. */ /** * Get an array with the values of a given key. * * @param string|array $value * @param string|null $key * @return \Illuminate\Support\Collection */ public function pluck($value, $key = null) { return $this->toBase()->pluck($value, $key); } /** * Get the keys of the collection items. * * @return \Illuminate\Support\Collection */ public function keys() { return $this->toBase()->keys(); } /** * Zip the collection together with one or more arrays. * * @param mixed ...$items * @return \Illuminate\Support\Collection */ public function zip($items) { return call_user_func_array([$this->toBase(), 'zip'], func_get_args()); } /** * Collapse the collection of items into a single array. * * @return \Illuminate\Support\Collection */ public function collapse() { return $this->toBase()->collapse(); } /** * Get a flattened array of the items in the collection. * * @param int $depth * @return \Illuminate\Support\Collection */ public function flatten($depth = INF) { return $this->toBase()->flatten($depth); } /** * Flip the items in the collection. * * @return \Illuminate\Support\Collection */ public function flip() { return $this->toBase()->flip(); } /** * Pad collection to the specified length with a value. * * @param int $size * @param mixed $value * @return \Illuminate\Support\Collection */ public function pad($size, $value) { return $this->toBase()->pad($size, $value); } /** * Get the comparison function to detect duplicates. * * @param bool $strict * @return \Closure */ protected function duplicateComparator($strict) { return function ($a, $b) { return $a->is($b); }; } /** * Get the type of the entities being queued. * * @return string|null * * @throws \LogicException */ public function getQueueableClass() { if ($this->isEmpty()) { return; } $class = get_class($this->first()); $this->each(function ($model) use ($class) { if (get_class($model) !== $class) { throw new LogicException('Queueing collections with multiple model types is not supported.'); } }); return $class; } /** * Get the identifiers for all of the entities. * * @return array */ public function getQueueableIds() { if ($this->isEmpty()) { return []; } return $this->first() instanceof QueueableEntity ? $this->map->getQueueableId()->all() : $this->modelKeys(); } /** * Get the relationships of the entities being queued. * * @return array */ public function getQueueableRelations() { if ($this->isEmpty()) { return []; } $relations = $this->map->getQueueableRelations()->all(); if (count($relations) === 0 || $relations === [[]]) { return []; } elseif (count($relations) === 1) { return reset($relations); } else { return array_intersect(...$relations); } } /** * Get the connection of the entities being queued. * * @return string|null * * @throws \LogicException */ public function getQueueableConnection() { if ($this->isEmpty()) { return; } $connection = $this->first()->getConnectionName(); $this->each(function ($model) use ($connection) { if ($model->getConnectionName() !== $connection) { throw new LogicException('Queueing collections with multiple model connections is not supported.'); } }); return $connection; } } database/Eloquent/Model.php 0000644 00000131330 14736103231 0011656 0 ustar 00 <?php namespace Illuminate\Database\Eloquent; use ArrayAccess; use Exception; use Illuminate\Contracts\Queue\QueueableCollection; use Illuminate\Contracts\Queue\QueueableEntity; use Illuminate\Contracts\Routing\UrlRoutable; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Contracts\Support\Jsonable; use Illuminate\Database\ConnectionResolverInterface as Resolver; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\Concerns\AsPivot; use Illuminate\Database\Eloquent\Relations\HasManyThrough; use Illuminate\Database\Eloquent\Relations\Pivot; use Illuminate\Support\Arr; use Illuminate\Support\Collection as BaseCollection; use Illuminate\Support\Str; use Illuminate\Support\Traits\ForwardsCalls; use JsonSerializable; abstract class Model implements Arrayable, ArrayAccess, Jsonable, JsonSerializable, QueueableEntity, UrlRoutable { use Concerns\HasAttributes, Concerns\HasEvents, Concerns\HasGlobalScopes, Concerns\HasRelationships, Concerns\HasTimestamps, Concerns\HidesAttributes, Concerns\GuardsAttributes, ForwardsCalls; /** * The connection name for the model. * * @var string|null */ protected $connection; /** * The table associated with the model. * * @var string */ protected $table; /** * The primary key for the model. * * @var string */ protected $primaryKey = 'id'; /** * The "type" of the primary key ID. * * @var string */ protected $keyType = 'int'; /** * Indicates if the IDs are auto-incrementing. * * @var bool */ public $incrementing = true; /** * The relations to eager load on every query. * * @var array */ protected $with = []; /** * The relationship counts that should be eager loaded on every query. * * @var array */ protected $withCount = []; /** * The number of models to return for pagination. * * @var int */ protected $perPage = 15; /** * Indicates if the model exists. * * @var bool */ public $exists = false; /** * Indicates if the model was inserted during the current request lifecycle. * * @var bool */ public $wasRecentlyCreated = false; /** * The connection resolver instance. * * @var \Illuminate\Database\ConnectionResolverInterface */ protected static $resolver; /** * The event dispatcher instance. * * @var \Illuminate\Contracts\Events\Dispatcher */ protected static $dispatcher; /** * The array of booted models. * * @var array */ protected static $booted = []; /** * The array of trait initializers that will be called on each new instance. * * @var array */ protected static $traitInitializers = []; /** * The array of global scopes on the model. * * @var array */ protected static $globalScopes = []; /** * The list of models classes that should not be affected with touch. * * @var array */ protected static $ignoreOnTouch = []; /** * The name of the "created at" column. * * @var string */ const CREATED_AT = 'created_at'; /** * The name of the "updated at" column. * * @var string */ const UPDATED_AT = 'updated_at'; /** * Create a new Eloquent model instance. * * @param array $attributes * @return void */ public function __construct(array $attributes = []) { $this->bootIfNotBooted(); $this->initializeTraits(); $this->syncOriginal(); $this->fill($attributes); } /** * Check if the model needs to be booted and if so, do it. * * @return void */ protected function bootIfNotBooted() { if (! isset(static::$booted[static::class])) { static::$booted[static::class] = true; $this->fireModelEvent('booting', false); static::booting(); static::boot(); static::booted(); $this->fireModelEvent('booted', false); } } /** * Perform any actions required before the model boots. * * @return void */ protected static function booting() { // } /** * Bootstrap the model and its traits. * * @return void */ protected static function boot() { static::bootTraits(); } /** * Boot all of the bootable traits on the model. * * @return void */ protected static function bootTraits() { $class = static::class; $booted = []; static::$traitInitializers[$class] = []; foreach (class_uses_recursive($class) as $trait) { $method = 'boot'.class_basename($trait); if (method_exists($class, $method) && ! in_array($method, $booted)) { forward_static_call([$class, $method]); $booted[] = $method; } if (method_exists($class, $method = 'initialize'.class_basename($trait))) { static::$traitInitializers[$class][] = $method; static::$traitInitializers[$class] = array_unique( static::$traitInitializers[$class] ); } } } /** * Initialize any initializable traits on the model. * * @return void */ protected function initializeTraits() { foreach (static::$traitInitializers[static::class] as $method) { $this->{$method}(); } } /** * Perform any actions required after the model boots. * * @return void */ protected static function booted() { // } /** * Clear the list of booted models so they will be re-booted. * * @return void */ public static function clearBootedModels() { static::$booted = []; static::$globalScopes = []; } /** * Disables relationship model touching for the current class during given callback scope. * * @param callable $callback * @return void */ public static function withoutTouching(callable $callback) { static::withoutTouchingOn([static::class], $callback); } /** * Disables relationship model touching for the given model classes during given callback scope. * * @param array $models * @param callable $callback * @return void */ public static function withoutTouchingOn(array $models, callable $callback) { static::$ignoreOnTouch = array_values(array_merge(static::$ignoreOnTouch, $models)); try { $callback(); } finally { static::$ignoreOnTouch = array_values(array_diff(static::$ignoreOnTouch, $models)); } } /** * Determine if the given model is ignoring touches. * * @param string|null $class * @return bool */ public static function isIgnoringTouch($class = null) { $class = $class ?: static::class; if (! get_class_vars($class)['timestamps'] || ! $class::UPDATED_AT) { return true; } foreach (static::$ignoreOnTouch as $ignoredClass) { if ($class === $ignoredClass || is_subclass_of($class, $ignoredClass)) { return true; } } return false; } /** * Fill the model with an array of attributes. * * @param array $attributes * @return $this * * @throws \Illuminate\Database\Eloquent\MassAssignmentException */ public function fill(array $attributes) { $totallyGuarded = $this->totallyGuarded(); foreach ($this->fillableFromArray($attributes) as $key => $value) { $key = $this->removeTableFromKey($key); // The developers may choose to place some attributes in the "fillable" array // which means only those attributes may be set through mass assignment to // the model, and all others will just get ignored for security reasons. if ($this->isFillable($key)) { $this->setAttribute($key, $value); } elseif ($totallyGuarded) { throw new MassAssignmentException(sprintf( 'Add [%s] to fillable property to allow mass assignment on [%s].', $key, get_class($this) )); } } return $this; } /** * Fill the model with an array of attributes. Force mass assignment. * * @param array $attributes * @return $this */ public function forceFill(array $attributes) { return static::unguarded(function () use ($attributes) { return $this->fill($attributes); }); } /** * Qualify the given column name by the model's table. * * @param string $column * @return string */ public function qualifyColumn($column) { if (Str::contains($column, '.')) { return $column; } return $this->getTable().'.'.$column; } /** * Remove the table name from a given key. * * @param string $key * @return string */ protected function removeTableFromKey($key) { return Str::contains($key, '.') ? last(explode('.', $key)) : $key; } /** * Create a new instance of the given model. * * @param array $attributes * @param bool $exists * @return static */ public function newInstance($attributes = [], $exists = false) { // This method just provides a convenient way for us to generate fresh model // instances of this current model. It is particularly useful during the // hydration of new objects via the Eloquent query builder instances. $model = new static((array) $attributes); $model->exists = $exists; $model->setConnection( $this->getConnectionName() ); $model->setTable($this->getTable()); $model->mergeCasts($this->casts); return $model; } /** * Create a new model instance that is existing. * * @param array $attributes * @param string|null $connection * @return static */ public function newFromBuilder($attributes = [], $connection = null) { $model = $this->newInstance([], true); $model->setRawAttributes((array) $attributes, true); $model->setConnection($connection ?: $this->getConnectionName()); $model->fireModelEvent('retrieved', false); return $model; } /** * Begin querying the model on a given connection. * * @param string|null $connection * @return \Illuminate\Database\Eloquent\Builder */ public static function on($connection = null) { // First we will just create a fresh instance of this model, and then we can set the // connection on the model so that it is used for the queries we execute, as well // as being set on every relation we retrieve without a custom connection name. $instance = new static; $instance->setConnection($connection); return $instance->newQuery(); } /** * Begin querying the model on the write connection. * * @return \Illuminate\Database\Query\Builder */ public static function onWriteConnection() { return static::query()->useWritePdo(); } /** * Get all of the models from the database. * * @param array|mixed $columns * @return \Illuminate\Database\Eloquent\Collection|static[] */ public static function all($columns = ['*']) { return static::query()->get( is_array($columns) ? $columns : func_get_args() ); } /** * Begin querying a model with eager loading. * * @param array|string $relations * @return \Illuminate\Database\Eloquent\Builder */ public static function with($relations) { return static::query()->with( is_string($relations) ? func_get_args() : $relations ); } /** * Eager load relations on the model. * * @param array|string $relations * @return $this */ public function load($relations) { $query = $this->newQueryWithoutRelationships()->with( is_string($relations) ? func_get_args() : $relations ); $query->eagerLoadRelations([$this]); return $this; } /** * Eager load relationships on the polymorphic relation of a model. * * @param string $relation * @param array $relations * @return $this */ public function loadMorph($relation, $relations) { $className = get_class($this->{$relation}); $this->{$relation}->load($relations[$className] ?? []); return $this; } /** * Eager load relations on the model if they are not already eager loaded. * * @param array|string $relations * @return $this */ public function loadMissing($relations) { $relations = is_string($relations) ? func_get_args() : $relations; $this->newCollection([$this])->loadMissing($relations); return $this; } /** * Eager load relation counts on the model. * * @param array|string $relations * @return $this */ public function loadCount($relations) { $relations = is_string($relations) ? func_get_args() : $relations; $this->newCollection([$this])->loadCount($relations); return $this; } /** * Eager load relationship counts on the polymorphic relation of a model. * * @param string $relation * @param array $relations * @return $this */ public function loadMorphCount($relation, $relations) { $className = get_class($this->{$relation}); $this->{$relation}->loadCount($relations[$className] ?? []); return $this; } /** * Increment a column's value by a given amount. * * @param string $column * @param float|int $amount * @param array $extra * @return int */ protected function increment($column, $amount = 1, array $extra = []) { return $this->incrementOrDecrement($column, $amount, $extra, 'increment'); } /** * Decrement a column's value by a given amount. * * @param string $column * @param float|int $amount * @param array $extra * @return int */ protected function decrement($column, $amount = 1, array $extra = []) { return $this->incrementOrDecrement($column, $amount, $extra, 'decrement'); } /** * Run the increment or decrement method on the model. * * @param string $column * @param float|int $amount * @param array $extra * @param string $method * @return int */ protected function incrementOrDecrement($column, $amount, $extra, $method) { $query = $this->newQueryWithoutRelationships(); if (! $this->exists) { return $query->{$method}($column, $amount, $extra); } $this->incrementOrDecrementAttributeValue($column, $amount, $extra, $method); return $query->where( $this->getKeyName(), $this->getKey() )->{$method}($column, $amount, $extra); } /** * Increment the underlying attribute value and sync with original. * * @param string $column * @param float|int $amount * @param array $extra * @param string $method * @return void */ protected function incrementOrDecrementAttributeValue($column, $amount, $extra, $method) { $this->{$column} = $this->{$column} + ($method === 'increment' ? $amount : $amount * -1); $this->forceFill($extra); $this->syncOriginalAttribute($column); } /** * Update the model in the database. * * @param array $attributes * @param array $options * @return bool */ public function update(array $attributes = [], array $options = []) { if (! $this->exists) { return false; } return $this->fill($attributes)->save($options); } /** * Save the model and all of its relationships. * * @return bool */ public function push() { if (! $this->save()) { return false; } // To sync all of the relationships to the database, we will simply spin through // the relationships and save each model via this "push" method, which allows // us to recurse into all of these nested relations for the model instance. foreach ($this->relations as $models) { $models = $models instanceof Collection ? $models->all() : [$models]; foreach (array_filter($models) as $model) { if (! $model->push()) { return false; } } } return true; } /** * Save the model to the database. * * @param array $options * @return bool */ public function save(array $options = []) { $this->mergeAttributesFromClassCasts(); $query = $this->newModelQuery(); // If the "saving" event returns false we'll bail out of the save and return // false, indicating that the save failed. This provides a chance for any // listeners to cancel save operations if validations fail or whatever. if ($this->fireModelEvent('saving') === false) { return false; } // If the model already exists in the database we can just update our record // that is already in this database using the current IDs in this "where" // clause to only update this model. Otherwise, we'll just insert them. if ($this->exists) { $saved = $this->isDirty() ? $this->performUpdate($query) : true; } // If the model is brand new, we'll insert it into our database and set the // ID attribute on the model to the value of the newly inserted row's ID // which is typically an auto-increment value managed by the database. else { $saved = $this->performInsert($query); if (! $this->getConnectionName() && $connection = $query->getConnection()) { $this->setConnection($connection->getName()); } } // If the model is successfully saved, we need to do a few more things once // that is done. We will call the "saved" method here to run any actions // we need to happen after a model gets successfully saved right here. if ($saved) { $this->finishSave($options); } return $saved; } /** * Save the model to the database using transaction. * * @param array $options * @return bool * * @throws \Throwable */ public function saveOrFail(array $options = []) { return $this->getConnection()->transaction(function () use ($options) { return $this->save($options); }); } /** * Perform any actions that are necessary after the model is saved. * * @param array $options * @return void */ protected function finishSave(array $options) { $this->fireModelEvent('saved', false); if ($this->isDirty() && ($options['touch'] ?? true)) { $this->touchOwners(); } $this->syncOriginal(); } /** * Perform a model update operation. * * @param \Illuminate\Database\Eloquent\Builder $query * @return bool */ protected function performUpdate(Builder $query) { // If the updating event returns false, we will cancel the update operation so // developers can hook Validation systems into their models and cancel this // operation if the model does not pass validation. Otherwise, we update. if ($this->fireModelEvent('updating') === false) { return false; } // First we need to create a fresh query instance and touch the creation and // update timestamp on the model which are maintained by us for developer // convenience. Then we will just continue saving the model instances. if ($this->usesTimestamps()) { $this->updateTimestamps(); } // Once we have run the update operation, we will fire the "updated" event for // this model instance. This will allow developers to hook into these after // models are updated, giving them a chance to do any special processing. $dirty = $this->getDirty(); if (count($dirty) > 0) { $this->setKeysForSaveQuery($query)->update($dirty); $this->syncChanges(); $this->fireModelEvent('updated', false); } return true; } /** * Set the keys for a save update query. * * @param \Illuminate\Database\Eloquent\Builder $query * @return \Illuminate\Database\Eloquent\Builder */ protected function setKeysForSaveQuery(Builder $query) { $query->where($this->getKeyName(), '=', $this->getKeyForSaveQuery()); return $query; } /** * Get the primary key value for a save query. * * @return mixed */ protected function getKeyForSaveQuery() { return $this->original[$this->getKeyName()] ?? $this->getKey(); } /** * Perform a model insert operation. * * @param \Illuminate\Database\Eloquent\Builder $query * @return bool */ protected function performInsert(Builder $query) { if ($this->fireModelEvent('creating') === false) { return false; } // First we'll need to create a fresh query instance and touch the creation and // update timestamps on this model, which are maintained by us for developer // convenience. After, we will just continue saving these model instances. if ($this->usesTimestamps()) { $this->updateTimestamps(); } // If the model has an incrementing key, we can use the "insertGetId" method on // the query builder, which will give us back the final inserted ID for this // table from the database. Not all tables have to be incrementing though. $attributes = $this->getAttributes(); if ($this->getIncrementing()) { $this->insertAndSetId($query, $attributes); } // If the table isn't incrementing we'll simply insert these attributes as they // are. These attribute arrays must contain an "id" column previously placed // there by the developer as the manually determined key for these models. else { if (empty($attributes)) { return true; } $query->insert($attributes); } // We will go ahead and set the exists property to true, so that it is set when // the created event is fired, just in case the developer tries to update it // during the event. This will allow them to do so and run an update here. $this->exists = true; $this->wasRecentlyCreated = true; $this->fireModelEvent('created', false); return true; } /** * Insert the given attributes and set the ID on the model. * * @param \Illuminate\Database\Eloquent\Builder $query * @param array $attributes * @return void */ protected function insertAndSetId(Builder $query, $attributes) { $id = $query->insertGetId($attributes, $keyName = $this->getKeyName()); $this->setAttribute($keyName, $id); } /** * Destroy the models for the given IDs. * * @param \Illuminate\Support\Collection|array|int|string $ids * @return int */ public static function destroy($ids) { // We'll initialize a count here so we will return the total number of deletes // for the operation. The developers can then check this number as a boolean // type value or get this total count of records deleted for logging, etc. $count = 0; if ($ids instanceof BaseCollection) { $ids = $ids->all(); } $ids = is_array($ids) ? $ids : func_get_args(); // We will actually pull the models from the database table and call delete on // each of them individually so that their events get fired properly with a // correct set of attributes in case the developers wants to check these. $key = ($instance = new static)->getKeyName(); foreach ($instance->whereIn($key, $ids)->get() as $model) { if ($model->delete()) { $count++; } } return $count; } /** * Delete the model from the database. * * @return bool|null * * @throws \Exception */ public function delete() { $this->mergeAttributesFromClassCasts(); if (is_null($this->getKeyName())) { throw new Exception('No primary key defined on model.'); } // If the model doesn't exist, there is nothing to delete so we'll just return // immediately and not do anything else. Otherwise, we will continue with a // deletion process on the model, firing the proper events, and so forth. if (! $this->exists) { return; } if ($this->fireModelEvent('deleting') === false) { return false; } // Here, we'll touch the owning models, verifying these timestamps get updated // for the models. This will allow any caching to get broken on the parents // by the timestamp. Then we will go ahead and delete the model instance. $this->touchOwners(); $this->performDeleteOnModel(); // Once the model has been deleted, we will fire off the deleted event so that // the developers may hook into post-delete operations. We will then return // a boolean true as the delete is presumably successful on the database. $this->fireModelEvent('deleted', false); return true; } /** * Force a hard delete on a soft deleted model. * * This method protects developers from running forceDelete when trait is missing. * * @return bool|null */ public function forceDelete() { return $this->delete(); } /** * Perform the actual delete query on this model instance. * * @return void */ protected function performDeleteOnModel() { $this->setKeysForSaveQuery($this->newModelQuery())->delete(); $this->exists = false; } /** * Begin querying the model. * * @return \Illuminate\Database\Eloquent\Builder */ public static function query() { return (new static)->newQuery(); } /** * Get a new query builder for the model's table. * * @return \Illuminate\Database\Eloquent\Builder */ public function newQuery() { return $this->registerGlobalScopes($this->newQueryWithoutScopes()); } /** * Get a new query builder that doesn't have any global scopes or eager loading. * * @return \Illuminate\Database\Eloquent\Builder|static */ public function newModelQuery() { return $this->newEloquentBuilder( $this->newBaseQueryBuilder() )->setModel($this); } /** * Get a new query builder with no relationships loaded. * * @return \Illuminate\Database\Eloquent\Builder */ public function newQueryWithoutRelationships() { return $this->registerGlobalScopes($this->newModelQuery()); } /** * Register the global scopes for this builder instance. * * @param \Illuminate\Database\Eloquent\Builder $builder * @return \Illuminate\Database\Eloquent\Builder */ public function registerGlobalScopes($builder) { foreach ($this->getGlobalScopes() as $identifier => $scope) { $builder->withGlobalScope($identifier, $scope); } return $builder; } /** * Get a new query builder that doesn't have any global scopes. * * @return \Illuminate\Database\Eloquent\Builder|static */ public function newQueryWithoutScopes() { return $this->newModelQuery() ->with($this->with) ->withCount($this->withCount); } /** * Get a new query instance without a given scope. * * @param \Illuminate\Database\Eloquent\Scope|string $scope * @return \Illuminate\Database\Eloquent\Builder */ public function newQueryWithoutScope($scope) { return $this->newQuery()->withoutGlobalScope($scope); } /** * Get a new query to restore one or more models by their queueable IDs. * * @param array|int $ids * @return \Illuminate\Database\Eloquent\Builder */ public function newQueryForRestoration($ids) { return is_array($ids) ? $this->newQueryWithoutScopes()->whereIn($this->getQualifiedKeyName(), $ids) : $this->newQueryWithoutScopes()->whereKey($ids); } /** * Create a new Eloquent query builder for the model. * * @param \Illuminate\Database\Query\Builder $query * @return \Illuminate\Database\Eloquent\Builder|static */ public function newEloquentBuilder($query) { return new Builder($query); } /** * Get a new query builder instance for the connection. * * @return \Illuminate\Database\Query\Builder */ protected function newBaseQueryBuilder() { return $this->getConnection()->query(); } /** * Create a new Eloquent Collection instance. * * @param array $models * @return \Illuminate\Database\Eloquent\Collection */ public function newCollection(array $models = []) { return new Collection($models); } /** * Create a new pivot model instance. * * @param \Illuminate\Database\Eloquent\Model $parent * @param array $attributes * @param string $table * @param bool $exists * @param string|null $using * @return \Illuminate\Database\Eloquent\Relations\Pivot */ public function newPivot(self $parent, array $attributes, $table, $exists, $using = null) { return $using ? $using::fromRawAttributes($parent, $attributes, $table, $exists) : Pivot::fromAttributes($parent, $attributes, $table, $exists); } /** * Determine if the model has a given scope. * * @param string $scope * @return bool */ public function hasNamedScope($scope) { return method_exists($this, 'scope'.ucfirst($scope)); } /** * Apply the given named scope if possible. * * @param string $scope * @param array $parameters * @return mixed */ public function callNamedScope($scope, array $parameters = []) { return $this->{'scope'.ucfirst($scope)}(...$parameters); } /** * Convert the model instance to an array. * * @return array */ public function toArray() { return array_merge($this->attributesToArray(), $this->relationsToArray()); } /** * Convert the model instance to JSON. * * @param int $options * @return string * * @throws \Illuminate\Database\Eloquent\JsonEncodingException */ public function toJson($options = 0) { $json = json_encode($this->jsonSerialize(), $options); if (JSON_ERROR_NONE !== json_last_error()) { throw JsonEncodingException::forModel($this, json_last_error_msg()); } return $json; } /** * Convert the object into something JSON serializable. * * @return array */ #[\ReturnTypeWillChange] public function jsonSerialize() { return $this->toArray(); } /** * Reload a fresh model instance from the database. * * @param array|string $with * @return static|null */ public function fresh($with = []) { if (! $this->exists) { return; } return static::newQueryWithoutScopes() ->with(is_string($with) ? func_get_args() : $with) ->where($this->getKeyName(), $this->getKey()) ->first(); } /** * Reload the current model instance with fresh attributes from the database. * * @return $this */ public function refresh() { if (! $this->exists) { return $this; } $this->setRawAttributes( static::newQueryWithoutScopes()->findOrFail($this->getKey())->attributes ); $this->load(collect($this->relations)->reject(function ($relation) { return $relation instanceof Pivot || (is_object($relation) && in_array(AsPivot::class, class_uses_recursive($relation), true)); })->keys()->all()); $this->syncOriginal(); return $this; } /** * Clone the model into a new, non-existing instance. * * @param array|null $except * @return static */ public function replicate(array $except = null) { $defaults = [ $this->getKeyName(), $this->getCreatedAtColumn(), $this->getUpdatedAtColumn(), ]; $attributes = Arr::except( $this->getAttributes(), $except ? array_unique(array_merge($except, $defaults)) : $defaults ); return tap(new static, function ($instance) use ($attributes) { $instance->setRawAttributes($attributes); $instance->setRelations($this->relations); $instance->fireModelEvent('replicating', false); }); } /** * Determine if two models have the same ID and belong to the same table. * * @param \Illuminate\Database\Eloquent\Model|null $model * @return bool */ public function is($model) { return ! is_null($model) && $this->getKey() === $model->getKey() && $this->getTable() === $model->getTable() && $this->getConnectionName() === $model->getConnectionName(); } /** * Determine if two models are not the same. * * @param \Illuminate\Database\Eloquent\Model|null $model * @return bool */ public function isNot($model) { return ! $this->is($model); } /** * Get the database connection for the model. * * @return \Illuminate\Database\Connection */ public function getConnection() { return static::resolveConnection($this->getConnectionName()); } /** * Get the current connection name for the model. * * @return string|null */ public function getConnectionName() { return $this->connection; } /** * Set the connection associated with the model. * * @param string|null $name * @return $this */ public function setConnection($name) { $this->connection = $name; return $this; } /** * Resolve a connection instance. * * @param string|null $connection * @return \Illuminate\Database\Connection */ public static function resolveConnection($connection = null) { return static::$resolver->connection($connection); } /** * Get the connection resolver instance. * * @return \Illuminate\Database\ConnectionResolverInterface */ public static function getConnectionResolver() { return static::$resolver; } /** * Set the connection resolver instance. * * @param \Illuminate\Database\ConnectionResolverInterface $resolver * @return void */ public static function setConnectionResolver(Resolver $resolver) { static::$resolver = $resolver; } /** * Unset the connection resolver for models. * * @return void */ public static function unsetConnectionResolver() { static::$resolver = null; } /** * Get the table associated with the model. * * @return string */ public function getTable() { return $this->table ?? Str::snake(Str::pluralStudly(class_basename($this))); } /** * Set the table associated with the model. * * @param string $table * @return $this */ public function setTable($table) { $this->table = $table; return $this; } /** * Get the primary key for the model. * * @return string */ public function getKeyName() { return $this->primaryKey; } /** * Set the primary key for the model. * * @param string $key * @return $this */ public function setKeyName($key) { $this->primaryKey = $key; return $this; } /** * Get the table qualified key name. * * @return string */ public function getQualifiedKeyName() { return $this->qualifyColumn($this->getKeyName()); } /** * Get the auto-incrementing key type. * * @return string */ public function getKeyType() { return $this->keyType; } /** * Set the data type for the primary key. * * @param string $type * @return $this */ public function setKeyType($type) { $this->keyType = $type; return $this; } /** * Get the value indicating whether the IDs are incrementing. * * @return bool */ public function getIncrementing() { return $this->incrementing; } /** * Set whether IDs are incrementing. * * @param bool $value * @return $this */ public function setIncrementing($value) { $this->incrementing = $value; return $this; } /** * Get the value of the model's primary key. * * @return mixed */ public function getKey() { return $this->getAttribute($this->getKeyName()); } /** * Get the queueable identity for the entity. * * @return mixed */ public function getQueueableId() { return $this->getKey(); } /** * Get the queueable relationships for the entity. * * @return array */ public function getQueueableRelations() { $relations = []; foreach ($this->getRelations() as $key => $relation) { if (! method_exists($this, $key)) { continue; } $relations[] = $key; if ($relation instanceof QueueableCollection) { foreach ($relation->getQueueableRelations() as $collectionValue) { $relations[] = $key.'.'.$collectionValue; } } if ($relation instanceof QueueableEntity) { foreach ($relation->getQueueableRelations() as $entityKey => $entityValue) { $relations[] = $key.'.'.$entityValue; } } } return array_unique($relations); } /** * Get the queueable connection for the entity. * * @return string|null */ public function getQueueableConnection() { return $this->getConnectionName(); } /** * Get the value of the model's route key. * * @return mixed */ public function getRouteKey() { return $this->getAttribute($this->getRouteKeyName()); } /** * Get the route key for the model. * * @return string */ public function getRouteKeyName() { return $this->getKeyName(); } /** * Retrieve the model for a bound value. * * @param mixed $value * @param string|null $field * @return \Illuminate\Database\Eloquent\Model|null */ public function resolveRouteBinding($value, $field = null) { return $this->where($field ?? $this->getRouteKeyName(), $value)->first(); } /** * Retrieve the child model for a bound value. * * @param string $childType * @param mixed $value * @param string|null $field * @return \Illuminate\Database\Eloquent\Model|null */ public function resolveChildRouteBinding($childType, $value, $field) { $relationship = $this->{Str::plural(Str::camel($childType))}(); if ($relationship instanceof HasManyThrough || $relationship instanceof BelongsToMany) { return $relationship->where($relationship->getRelated()->getTable().'.'.$field, $value)->first(); } else { return $relationship->where($field, $value)->first(); } } /** * Get the default foreign key name for the model. * * @return string */ public function getForeignKey() { return Str::snake(class_basename($this)).'_'.$this->getKeyName(); } /** * Get the number of models to return per page. * * @return int */ public function getPerPage() { return $this->perPage; } /** * Set the number of models to return per page. * * @param int $perPage * @return $this */ public function setPerPage($perPage) { $this->perPage = $perPage; return $this; } /** * Dynamically retrieve attributes on the model. * * @param string $key * @return mixed */ public function __get($key) { return $this->getAttribute($key); } /** * Dynamically set attributes on the model. * * @param string $key * @param mixed $value * @return void */ public function __set($key, $value) { $this->setAttribute($key, $value); } /** * Determine if the given attribute exists. * * @param mixed $offset * @return bool */ #[\ReturnTypeWillChange] public function offsetExists($offset) { return ! is_null($this->getAttribute($offset)); } /** * Get the value for a given offset. * * @param mixed $offset * @return mixed */ #[\ReturnTypeWillChange] public function offsetGet($offset) { return $this->getAttribute($offset); } /** * Set the value for a given offset. * * @param mixed $offset * @param mixed $value * @return void */ #[\ReturnTypeWillChange] public function offsetSet($offset, $value) { $this->setAttribute($offset, $value); } /** * Unset the value for a given offset. * * @param mixed $offset * @return void */ #[\ReturnTypeWillChange] public function offsetUnset($offset) { unset($this->attributes[$offset], $this->relations[$offset]); } /** * Determine if an attribute or relation exists on the model. * * @param string $key * @return bool */ public function __isset($key) { return $this->offsetExists($key); } /** * Unset an attribute on the model. * * @param string $key * @return void */ public function __unset($key) { $this->offsetUnset($key); } /** * Handle dynamic method calls into the model. * * @param string $method * @param array $parameters * @return mixed */ public function __call($method, $parameters) { if (in_array($method, ['increment', 'decrement'])) { return $this->$method(...$parameters); } return $this->forwardCallTo($this->newQuery(), $method, $parameters); } /** * Handle dynamic static method calls into the model. * * @param string $method * @param array $parameters * @return mixed */ public static function __callStatic($method, $parameters) { return (new static)->$method(...$parameters); } /** * Convert the model to its string representation. * * @return string */ public function __toString() { return $this->toJson(); } /** * Prepare the object for serialization. * * @return array */ public function __sleep() { $this->mergeAttributesFromClassCasts(); $this->classCastCache = []; return array_keys(get_object_vars($this)); } /** * When a model is being unserialized, check if it needs to be booted. * * @return void */ public function __wakeup() { $this->bootIfNotBooted(); } } database/Eloquent/Factory.php 0000644 00000013700 14736103231 0012225 0 ustar 00 <?php namespace Illuminate\Database\Eloquent; use ArrayAccess; use Faker\Generator as Faker; use Symfony\Component\Finder\Finder; class Factory implements ArrayAccess { /** * The model definitions in the container. * * @var array */ protected $definitions = []; /** * The registered model states. * * @var array */ protected $states = []; /** * The registered after making callbacks. * * @var array */ protected $afterMaking = []; /** * The registered after creating callbacks. * * @var array */ protected $afterCreating = []; /** * The Faker instance for the builder. * * @var \Faker\Generator */ protected $faker; /** * Create a new factory instance. * * @param \Faker\Generator $faker * @return void */ public function __construct(Faker $faker) { $this->faker = $faker; } /** * Create a new factory container. * * @param \Faker\Generator $faker * @param string|null $pathToFactories * @return static */ public static function construct(Faker $faker, $pathToFactories = null) { $pathToFactories = $pathToFactories ?: database_path('factories'); return (new static($faker))->load($pathToFactories); } /** * Define a class with a given set of attributes. * * @param string $class * @param callable $attributes * @return $this */ public function define($class, callable $attributes) { $this->definitions[$class] = $attributes; return $this; } /** * Define a state with a given set of attributes. * * @param string $class * @param string $state * @param callable|array $attributes * @return $this */ public function state($class, $state, $attributes) { $this->states[$class][$state] = $attributes; return $this; } /** * Define a callback to run after making a model. * * @param string $class * @param callable $callback * @param string $name * @return $this */ public function afterMaking($class, callable $callback, $name = 'default') { $this->afterMaking[$class][$name][] = $callback; return $this; } /** * Define a callback to run after making a model with given state. * * @param string $class * @param string $state * @param callable $callback * @return $this */ public function afterMakingState($class, $state, callable $callback) { return $this->afterMaking($class, $callback, $state); } /** * Define a callback to run after creating a model. * * @param string $class * @param callable $callback * @param string $name * @return $this */ public function afterCreating($class, callable $callback, $name = 'default') { $this->afterCreating[$class][$name][] = $callback; return $this; } /** * Define a callback to run after creating a model with given state. * * @param string $class * @param string $state * @param callable $callback * @return $this */ public function afterCreatingState($class, $state, callable $callback) { return $this->afterCreating($class, $callback, $state); } /** * Create an instance of the given model and persist it to the database. * * @param string $class * @param array $attributes * @return mixed */ public function create($class, array $attributes = []) { return $this->of($class)->create($attributes); } /** * Create an instance of the given model. * * @param string $class * @param array $attributes * @return mixed */ public function make($class, array $attributes = []) { return $this->of($class)->make($attributes); } /** * Get the raw attribute array for a given model. * * @param string $class * @param array $attributes * @return array */ public function raw($class, array $attributes = []) { return array_merge( call_user_func($this->definitions[$class], $this->faker), $attributes ); } /** * Create a builder for the given model. * * @param string $class * @return \Illuminate\Database\Eloquent\FactoryBuilder */ public function of($class) { return new FactoryBuilder( $class, $this->definitions, $this->states, $this->afterMaking, $this->afterCreating, $this->faker ); } /** * Load factories from path. * * @param string $path * @return $this */ public function load($path) { $factory = $this; if (is_dir($path)) { foreach (Finder::create()->files()->name('*.php')->in($path) as $file) { require $file->getRealPath(); } } return $factory; } /** * Determine if the given offset exists. * * @param string $offset * @return bool */ public function offsetExists($offset) { return isset($this->definitions[$offset]); } /** * Get the value of the given offset. * * @param string $offset * @return mixed */ public function offsetGet($offset) { return $this->make($offset); } /** * Set the given offset to the given value. * * @param string $offset * @param callable $value * @return void */ public function offsetSet($offset, $value) { $this->define($offset, $value); } /** * Unset the value at the given offset. * * @param string $offset * @return void */ public function offsetUnset($offset) { unset($this->definitions[$offset]); } } database/Eloquent/Relations/HasOneOrMany.php 0000644 00000026452 14736103231 0015071 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Relations; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; abstract class HasOneOrMany extends Relation { /** * The foreign key of the parent model. * * @var string */ protected $foreignKey; /** * The local key of the parent model. * * @var string */ protected $localKey; /** * The count of self joins. * * @var int */ protected static $selfJoinCount = 0; /** * Create a new has one or many relationship instance. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Model $parent * @param string $foreignKey * @param string $localKey * @return void */ public function __construct(Builder $query, Model $parent, $foreignKey, $localKey) { $this->localKey = $localKey; $this->foreignKey = $foreignKey; parent::__construct($query, $parent); } /** * Create and return an un-saved instance of the related model. * * @param array $attributes * @return \Illuminate\Database\Eloquent\Model */ public function make(array $attributes = []) { return tap($this->related->newInstance($attributes), function ($instance) { $this->setForeignAttributesForCreate($instance); }); } /** * Set the base constraints on the relation query. * * @return void */ public function addConstraints() { if (static::$constraints) { $this->query->where($this->foreignKey, '=', $this->getParentKey()); $this->query->whereNotNull($this->foreignKey); } } /** * Set the constraints for an eager load of the relation. * * @param array $models * @return void */ public function addEagerConstraints(array $models) { $whereIn = $this->whereInMethod($this->parent, $this->localKey); $this->query->{$whereIn}( $this->foreignKey, $this->getKeys($models, $this->localKey) ); } /** * Match the eagerly loaded results to their single parents. * * @param array $models * @param \Illuminate\Database\Eloquent\Collection $results * @param string $relation * @return array */ public function matchOne(array $models, Collection $results, $relation) { return $this->matchOneOrMany($models, $results, $relation, 'one'); } /** * Match the eagerly loaded results to their many parents. * * @param array $models * @param \Illuminate\Database\Eloquent\Collection $results * @param string $relation * @return array */ public function matchMany(array $models, Collection $results, $relation) { return $this->matchOneOrMany($models, $results, $relation, 'many'); } /** * Match the eagerly loaded results to their many parents. * * @param array $models * @param \Illuminate\Database\Eloquent\Collection $results * @param string $relation * @param string $type * @return array */ protected function matchOneOrMany(array $models, Collection $results, $relation, $type) { $dictionary = $this->buildDictionary($results); // Once we have the dictionary we can simply spin through the parent models to // link them up with their children using the keyed dictionary to make the // matching very convenient and easy work. Then we'll just return them. foreach ($models as $model) { if (isset($dictionary[$key = $model->getAttribute($this->localKey)])) { $model->setRelation( $relation, $this->getRelationValue($dictionary, $key, $type) ); } } return $models; } /** * Get the value of a relationship by one or many type. * * @param array $dictionary * @param string $key * @param string $type * @return mixed */ protected function getRelationValue(array $dictionary, $key, $type) { $value = $dictionary[$key]; return $type === 'one' ? reset($value) : $this->related->newCollection($value); } /** * Build model dictionary keyed by the relation's foreign key. * * @param \Illuminate\Database\Eloquent\Collection $results * @return array */ protected function buildDictionary(Collection $results) { $foreign = $this->getForeignKeyName(); return $results->mapToDictionary(function ($result) use ($foreign) { return [$result->{$foreign} => $result]; })->all(); } /** * Find a model by its primary key or return new instance of the related model. * * @param mixed $id * @param array $columns * @return \Illuminate\Support\Collection|\Illuminate\Database\Eloquent\Model */ public function findOrNew($id, $columns = ['*']) { if (is_null($instance = $this->find($id, $columns))) { $instance = $this->related->newInstance(); $this->setForeignAttributesForCreate($instance); } return $instance; } /** * Get the first related model record matching the attributes or instantiate it. * * @param array $attributes * @param array $values * @return \Illuminate\Database\Eloquent\Model */ public function firstOrNew(array $attributes, array $values = []) { if (is_null($instance = $this->where($attributes)->first())) { $instance = $this->related->newInstance($attributes + $values); $this->setForeignAttributesForCreate($instance); } return $instance; } /** * Get the first related record matching the attributes or create it. * * @param array $attributes * @param array $values * @return \Illuminate\Database\Eloquent\Model */ public function firstOrCreate(array $attributes, array $values = []) { if (is_null($instance = $this->where($attributes)->first())) { $instance = $this->create($attributes + $values); } return $instance; } /** * Create or update a related record matching the attributes, and fill it with values. * * @param array $attributes * @param array $values * @return \Illuminate\Database\Eloquent\Model */ public function updateOrCreate(array $attributes, array $values = []) { return tap($this->firstOrNew($attributes), function ($instance) use ($values) { $instance->fill($values); $instance->save(); }); } /** * Attach a model instance to the parent model. * * @param \Illuminate\Database\Eloquent\Model $model * @return \Illuminate\Database\Eloquent\Model|false */ public function save(Model $model) { $this->setForeignAttributesForCreate($model); return $model->save() ? $model : false; } /** * Attach a collection of models to the parent instance. * * @param iterable $models * @return iterable */ public function saveMany($models) { foreach ($models as $model) { $this->save($model); } return $models; } /** * Create a new instance of the related model. * * @param array $attributes * @return \Illuminate\Database\Eloquent\Model */ public function create(array $attributes = []) { return tap($this->related->newInstance($attributes), function ($instance) { $this->setForeignAttributesForCreate($instance); $instance->save(); }); } /** * Create a Collection of new instances of the related model. * * @param iterable $records * @return \Illuminate\Database\Eloquent\Collection */ public function createMany(iterable $records) { $instances = $this->related->newCollection(); foreach ($records as $record) { $instances->push($this->create($record)); } return $instances; } /** * Set the foreign ID for creating a related model. * * @param \Illuminate\Database\Eloquent\Model $model * @return void */ protected function setForeignAttributesForCreate(Model $model) { $model->setAttribute($this->getForeignKeyName(), $this->getParentKey()); } /** * Add the constraints for a relationship query. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Builder $parentQuery * @param array|mixed $columns * @return \Illuminate\Database\Eloquent\Builder */ public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*']) { if ($query->getQuery()->from == $parentQuery->getQuery()->from) { return $this->getRelationExistenceQueryForSelfRelation($query, $parentQuery, $columns); } return parent::getRelationExistenceQuery($query, $parentQuery, $columns); } /** * Add the constraints for a relationship query on the same table. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Builder $parentQuery * @param array|mixed $columns * @return \Illuminate\Database\Eloquent\Builder */ public function getRelationExistenceQueryForSelfRelation(Builder $query, Builder $parentQuery, $columns = ['*']) { $query->from($query->getModel()->getTable().' as '.$hash = $this->getRelationCountHash()); $query->getModel()->setTable($hash); return $query->select($columns)->whereColumn( $this->getQualifiedParentKeyName(), '=', $hash.'.'.$this->getForeignKeyName() ); } /** * Get a relationship join table hash. * * @return string */ public function getRelationCountHash() { return 'laravel_reserved_'.static::$selfJoinCount++; } /** * Get the key for comparing against the parent key in "has" query. * * @return string */ public function getExistenceCompareKey() { return $this->getQualifiedForeignKeyName(); } /** * Get the key value of the parent's local key. * * @return mixed */ public function getParentKey() { return $this->parent->getAttribute($this->localKey); } /** * Get the fully qualified parent key name. * * @return string */ public function getQualifiedParentKeyName() { return $this->parent->qualifyColumn($this->localKey); } /** * Get the plain foreign key. * * @return string */ public function getForeignKeyName() { $segments = explode('.', $this->getQualifiedForeignKeyName()); return end($segments); } /** * Get the foreign key for the relationship. * * @return string */ public function getQualifiedForeignKeyName() { return $this->foreignKey; } /** * Get the local key for the relationship. * * @return string */ public function getLocalKeyName() { return $this->localKey; } } database/Eloquent/Relations/MorphOneOrMany.php 0000644 00000006045 14736103231 0015437 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Relations; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; abstract class MorphOneOrMany extends HasOneOrMany { /** * The foreign key type for the relationship. * * @var string */ protected $morphType; /** * The class name of the parent model. * * @var string */ protected $morphClass; /** * Create a new morph one or many relationship instance. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Model $parent * @param string $type * @param string $id * @param string $localKey * @return void */ public function __construct(Builder $query, Model $parent, $type, $id, $localKey) { $this->morphType = $type; $this->morphClass = $parent->getMorphClass(); parent::__construct($query, $parent, $id, $localKey); } /** * Set the base constraints on the relation query. * * @return void */ public function addConstraints() { if (static::$constraints) { parent::addConstraints(); $this->query->where($this->morphType, $this->morphClass); } } /** * Set the constraints for an eager load of the relation. * * @param array $models * @return void */ public function addEagerConstraints(array $models) { parent::addEagerConstraints($models); $this->query->where($this->morphType, $this->morphClass); } /** * Set the foreign ID and type for creating a related model. * * @param \Illuminate\Database\Eloquent\Model $model * @return void */ protected function setForeignAttributesForCreate(Model $model) { $model->{$this->getForeignKeyName()} = $this->getParentKey(); $model->{$this->getMorphType()} = $this->morphClass; } /** * Get the relationship query. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Builder $parentQuery * @param array|mixed $columns * @return \Illuminate\Database\Eloquent\Builder */ public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*']) { return parent::getRelationExistenceQuery($query, $parentQuery, $columns)->where( $query->qualifyColumn($this->getMorphType()), $this->morphClass ); } /** * Get the foreign key "type" name. * * @return string */ public function getQualifiedMorphType() { return $this->morphType; } /** * Get the plain morph type name without the table. * * @return string */ public function getMorphType() { return last(explode('.', $this->morphType)); } /** * Get the class name of the parent model. * * @return string */ public function getMorphClass() { return $this->morphClass; } } database/Eloquent/Relations/Pivot.php 0000644 00000000707 14736103231 0013662 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Relations; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\Concerns\AsPivot; class Pivot extends Model { use AsPivot; /** * Indicates if the IDs are auto-incrementing. * * @var bool */ public $incrementing = false; /** * The attributes that aren't mass assignable. * * @var array */ protected $guarded = []; } database/Eloquent/Relations/MorphMany.php 0000644 00000002231 14736103231 0014465 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Relations; use Illuminate\Database\Eloquent\Collection; class MorphMany extends MorphOneOrMany { /** * Get the results of the relationship. * * @return mixed */ public function getResults() { return ! is_null($this->getParentKey()) ? $this->query->get() : $this->related->newCollection(); } /** * Initialize the relation on a set of models. * * @param array $models * @param string $relation * @return array */ public function initRelation(array $models, $relation) { foreach ($models as $model) { $model->setRelation($relation, $this->related->newCollection()); } return $models; } /** * Match the eagerly loaded results to their parents. * * @param array $models * @param \Illuminate\Database\Eloquent\Collection $results * @param string $relation * @return array */ public function match(array $models, Collection $results, $relation) { return $this->matchMany($models, $results, $relation); } } database/Eloquent/Relations/BelongsTo.php 0000644 00000024042 14736103231 0014453 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Relations; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\Concerns\SupportsDefaultModels; class BelongsTo extends Relation { use SupportsDefaultModels; /** * The child model instance of the relation. * * @var \Illuminate\Database\Eloquent\Model */ protected $child; /** * The foreign key of the parent model. * * @var string */ protected $foreignKey; /** * The associated key on the parent model. * * @var string */ protected $ownerKey; /** * The name of the relationship. * * @var string */ protected $relationName; /** * The count of self joins. * * @var int */ protected static $selfJoinCount = 0; /** * Create a new belongs to relationship instance. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Model $child * @param string $foreignKey * @param string $ownerKey * @param string $relationName * * @return void */ public function __construct(Builder $query, Model $child, $foreignKey, $ownerKey, $relationName) { $this->ownerKey = $ownerKey; $this->relationName = $relationName; $this->foreignKey = $foreignKey; // In the underlying base relationship class, this variable is referred to as // the "parent" since most relationships are not inversed. But, since this // one is we will create a "child" variable for much better readability. $this->child = $child; parent::__construct($query, $child); } /** * Get the results of the relationship. * * @return mixed */ public function getResults() { if (is_null($this->child->{$this->foreignKey})) { return $this->getDefaultFor($this->parent); } return $this->query->first() ?: $this->getDefaultFor($this->parent); } /** * Set the base constraints on the relation query. * * @return void */ public function addConstraints() { if (static::$constraints) { // For belongs to relationships, which are essentially the inverse of has one // or has many relationships, we need to actually query on the primary key // of the related models matching on the foreign key that's on a parent. $table = $this->related->getTable(); $this->query->where($table.'.'.$this->ownerKey, '=', $this->child->{$this->foreignKey}); } } /** * Set the constraints for an eager load of the relation. * * @param array $models * @return void */ public function addEagerConstraints(array $models) { // We'll grab the primary key name of the related models since it could be set to // a non-standard name and not "id". We will then construct the constraint for // our eagerly loading query so it returns the proper models from execution. $key = $this->related->getTable().'.'.$this->ownerKey; $whereIn = $this->whereInMethod($this->related, $this->ownerKey); $this->query->{$whereIn}($key, $this->getEagerModelKeys($models)); } /** * Gather the keys from an array of related models. * * @param array $models * @return array */ protected function getEagerModelKeys(array $models) { $keys = []; // First we need to gather all of the keys from the parent models so we know what // to query for via the eager loading query. We will add them to an array then // execute a "where in" statement to gather up all of those related records. foreach ($models as $model) { if (! is_null($value = $model->{$this->foreignKey})) { $keys[] = $value; } } sort($keys); return array_values(array_unique($keys)); } /** * Initialize the relation on a set of models. * * @param array $models * @param string $relation * @return array */ public function initRelation(array $models, $relation) { foreach ($models as $model) { $model->setRelation($relation, $this->getDefaultFor($model)); } return $models; } /** * Match the eagerly loaded results to their parents. * * @param array $models * @param \Illuminate\Database\Eloquent\Collection $results * @param string $relation * @return array */ public function match(array $models, Collection $results, $relation) { $foreign = $this->foreignKey; $owner = $this->ownerKey; // First we will get to build a dictionary of the child models by their primary // key of the relationship, then we can easily match the children back onto // the parents using that dictionary and the primary key of the children. $dictionary = []; foreach ($results as $result) { $dictionary[$result->getAttribute($owner)] = $result; } // Once we have the dictionary constructed, we can loop through all the parents // and match back onto their children using these keys of the dictionary and // the primary key of the children to map them onto the correct instances. foreach ($models as $model) { if (isset($dictionary[$model->{$foreign}])) { $model->setRelation($relation, $dictionary[$model->{$foreign}]); } } return $models; } /** * Associate the model instance to the given parent. * * @param \Illuminate\Database\Eloquent\Model|int|string $model * @return \Illuminate\Database\Eloquent\Model */ public function associate($model) { $ownerKey = $model instanceof Model ? $model->getAttribute($this->ownerKey) : $model; $this->child->setAttribute($this->foreignKey, $ownerKey); if ($model instanceof Model) { $this->child->setRelation($this->relationName, $model); } else { $this->child->unsetRelation($this->relationName); } return $this->child; } /** * Dissociate previously associated model from the given parent. * * @return \Illuminate\Database\Eloquent\Model */ public function dissociate() { $this->child->setAttribute($this->foreignKey, null); return $this->child->setRelation($this->relationName, null); } /** * Add the constraints for a relationship query. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Builder $parentQuery * @param array|mixed $columns * @return \Illuminate\Database\Eloquent\Builder */ public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*']) { if ($parentQuery->getQuery()->from == $query->getQuery()->from) { return $this->getRelationExistenceQueryForSelfRelation($query, $parentQuery, $columns); } return $query->select($columns)->whereColumn( $this->getQualifiedForeignKeyName(), '=', $query->qualifyColumn($this->ownerKey) ); } /** * Add the constraints for a relationship query on the same table. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Builder $parentQuery * @param array|mixed $columns * @return \Illuminate\Database\Eloquent\Builder */ public function getRelationExistenceQueryForSelfRelation(Builder $query, Builder $parentQuery, $columns = ['*']) { $query->select($columns)->from( $query->getModel()->getTable().' as '.$hash = $this->getRelationCountHash() ); $query->getModel()->setTable($hash); return $query->whereColumn( $hash.'.'.$this->ownerKey, '=', $this->getQualifiedForeignKeyName() ); } /** * Get a relationship join table hash. * * @return string */ public function getRelationCountHash() { return 'laravel_reserved_'.static::$selfJoinCount++; } /** * Determine if the related model has an auto-incrementing ID. * * @return bool */ protected function relationHasIncrementingId() { return $this->related->getIncrementing() && in_array($this->related->getKeyType(), ['int', 'integer']); } /** * Make a new related instance for the given model. * * @param \Illuminate\Database\Eloquent\Model $parent * @return \Illuminate\Database\Eloquent\Model */ protected function newRelatedInstanceFor(Model $parent) { return $this->related->newInstance(); } /** * Get the child of the relationship. * * @return \Illuminate\Database\Eloquent\Model */ public function getChild() { return $this->child; } /** * Get the foreign key of the relationship. * * @return string */ public function getForeignKeyName() { return $this->foreignKey; } /** * Get the fully qualified foreign key of the relationship. * * @return string */ public function getQualifiedForeignKeyName() { return $this->child->qualifyColumn($this->foreignKey); } /** * Get the associated key of the relationship. * * @return string */ public function getOwnerKeyName() { return $this->ownerKey; } /** * Get the fully qualified associated key of the relationship. * * @return string */ public function getQualifiedOwnerKeyName() { return $this->related->qualifyColumn($this->ownerKey); } /** * Get the name of the relationship. * * @return string */ public function getRelationName() { return $this->relationName; } } database/Eloquent/Relations/HasMany.php 0000644 00000002225 14736103231 0014116 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Relations; use Illuminate\Database\Eloquent\Collection; class HasMany extends HasOneOrMany { /** * Get the results of the relationship. * * @return mixed */ public function getResults() { return ! is_null($this->getParentKey()) ? $this->query->get() : $this->related->newCollection(); } /** * Initialize the relation on a set of models. * * @param array $models * @param string $relation * @return array */ public function initRelation(array $models, $relation) { foreach ($models as $model) { $model->setRelation($relation, $this->related->newCollection()); } return $models; } /** * Match the eagerly loaded results to their parents. * * @param array $models * @param \Illuminate\Database\Eloquent\Collection $results * @param string $relation * @return array */ public function match(array $models, Collection $results, $relation) { return $this->matchMany($models, $results, $relation); } } database/Eloquent/Relations/BelongsToMany.php 0000644 00000105475 14736103231 0015312 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Relations; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Support\Str; use InvalidArgumentException; class BelongsToMany extends Relation { use Concerns\InteractsWithPivotTable; /** * The intermediate table for the relation. * * @var string */ protected $table; /** * The foreign key of the parent model. * * @var string */ protected $foreignPivotKey; /** * The associated key of the relation. * * @var string */ protected $relatedPivotKey; /** * The key name of the parent model. * * @var string */ protected $parentKey; /** * The key name of the related model. * * @var string */ protected $relatedKey; /** * The "name" of the relationship. * * @var string */ protected $relationName; /** * The pivot table columns to retrieve. * * @var array */ protected $pivotColumns = []; /** * Any pivot table restrictions for where clauses. * * @var array */ protected $pivotWheres = []; /** * Any pivot table restrictions for whereIn clauses. * * @var array */ protected $pivotWhereIns = []; /** * Any pivot table restrictions for whereNull clauses. * * @var array */ protected $pivotWhereNulls = []; /** * The default values for the pivot columns. * * @var array */ protected $pivotValues = []; /** * Indicates if timestamps are available on the pivot table. * * @var bool */ public $withTimestamps = false; /** * The custom pivot table column for the created_at timestamp. * * @var string */ protected $pivotCreatedAt; /** * The custom pivot table column for the updated_at timestamp. * * @var string */ protected $pivotUpdatedAt; /** * The class name of the custom pivot model to use for the relationship. * * @var string */ protected $using; /** * The name of the accessor to use for the "pivot" relationship. * * @var string */ protected $accessor = 'pivot'; /** * The count of self joins. * * @var int */ protected static $selfJoinCount = 0; /** * Create a new belongs to many relationship instance. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Model $parent * @param string $table * @param string $foreignPivotKey * @param string $relatedPivotKey * @param string $parentKey * @param string $relatedKey * @param string|null $relationName * @return void */ public function __construct(Builder $query, Model $parent, $table, $foreignPivotKey, $relatedPivotKey, $parentKey, $relatedKey, $relationName = null) { $this->parentKey = $parentKey; $this->relatedKey = $relatedKey; $this->relationName = $relationName; $this->relatedPivotKey = $relatedPivotKey; $this->foreignPivotKey = $foreignPivotKey; $this->table = $this->resolveTableName($table); parent::__construct($query, $parent); } /** * Attempt to resolve the intermediate table name from the given string. * * @param string $table * @return string */ protected function resolveTableName($table) { if (! Str::contains($table, '\\') || ! class_exists($table)) { return $table; } $model = new $table; if (! $model instanceof Model) { return $table; } if ($model instanceof Pivot) { $this->using($table); } return $model->getTable(); } /** * Set the base constraints on the relation query. * * @return void */ public function addConstraints() { $this->performJoin(); if (static::$constraints) { $this->addWhereConstraints(); } } /** * Set the join clause for the relation query. * * @param \Illuminate\Database\Eloquent\Builder|null $query * @return $this */ protected function performJoin($query = null) { $query = $query ?: $this->query; // We need to join to the intermediate table on the related model's primary // key column with the intermediate table's foreign key for the related // model instance. Then we can set the "where" for the parent models. $baseTable = $this->related->getTable(); $key = $baseTable.'.'.$this->relatedKey; $query->join($this->table, $key, '=', $this->getQualifiedRelatedPivotKeyName()); return $this; } /** * Set the where clause for the relation query. * * @return $this */ protected function addWhereConstraints() { $this->query->where( $this->getQualifiedForeignPivotKeyName(), '=', $this->parent->{$this->parentKey} ); return $this; } /** * Set the constraints for an eager load of the relation. * * @param array $models * @return void */ public function addEagerConstraints(array $models) { $whereIn = $this->whereInMethod($this->parent, $this->parentKey); $this->query->{$whereIn}( $this->getQualifiedForeignPivotKeyName(), $this->getKeys($models, $this->parentKey) ); } /** * Initialize the relation on a set of models. * * @param array $models * @param string $relation * @return array */ public function initRelation(array $models, $relation) { foreach ($models as $model) { $model->setRelation($relation, $this->related->newCollection()); } return $models; } /** * Match the eagerly loaded results to their parents. * * @param array $models * @param \Illuminate\Database\Eloquent\Collection $results * @param string $relation * @return array */ public function match(array $models, Collection $results, $relation) { $dictionary = $this->buildDictionary($results); // Once we have an array dictionary of child objects we can easily match the // children back to their parent using the dictionary and the keys on the // the parent models. Then we will return the hydrated models back out. foreach ($models as $model) { if (isset($dictionary[$key = $model->{$this->parentKey}])) { $model->setRelation( $relation, $this->related->newCollection($dictionary[$key]) ); } } return $models; } /** * Build model dictionary keyed by the relation's foreign key. * * @param \Illuminate\Database\Eloquent\Collection $results * @return array */ protected function buildDictionary(Collection $results) { // First we will build a dictionary of child models keyed by the foreign key // of the relation so that we will easily and quickly match them to their // parents without having a possibly slow inner loops for every models. $dictionary = []; foreach ($results as $result) { $dictionary[$result->{$this->accessor}->{$this->foreignPivotKey}][] = $result; } return $dictionary; } /** * Get the class being used for pivot models. * * @return string */ public function getPivotClass() { return $this->using ?? Pivot::class; } /** * Specify the custom pivot model to use for the relationship. * * @param string $class * @return $this */ public function using($class) { $this->using = $class; return $this; } /** * Specify the custom pivot accessor to use for the relationship. * * @param string $accessor * @return $this */ public function as($accessor) { $this->accessor = $accessor; return $this; } /** * Set a where clause for a pivot table column. * * @param string $column * @param mixed $operator * @param mixed $value * @param string $boolean * @return $this */ public function wherePivot($column, $operator = null, $value = null, $boolean = 'and') { $this->pivotWheres[] = func_get_args(); return $this->where($this->table.'.'.$column, $operator, $value, $boolean); } /** * Set a "where between" clause for a pivot table column. * * @param string $column * @param array $values * @param string $boolean * @param bool $not * @return $this */ public function wherePivotBetween($column, array $values, $boolean = 'and', $not = false) { return $this->whereBetween($this->table.'.'.$column, $values, $boolean, $not); } /** * Set a "or where between" clause for a pivot table column. * * @param string $column * @param array $values * @return $this */ public function orWherePivotBetween($column, array $values) { return $this->wherePivotBetween($column, $values, 'or'); } /** * Set a "where pivot not between" clause for a pivot table column. * * @param string $column * @param array $values * @param string $boolean * @return $this */ public function wherePivotNotBetween($column, array $values, $boolean = 'and') { return $this->wherePivotBetween($column, $values, $boolean, true); } /** * Set a "or where not between" clause for a pivot table column. * * @param string $column * @param array $values * @return $this */ public function orWherePivotNotBetween($column, array $values) { return $this->wherePivotBetween($column, $values, 'or', true); } /** * Set a "where in" clause for a pivot table column. * * @param string $column * @param mixed $values * @param string $boolean * @param bool $not * @return $this */ public function wherePivotIn($column, $values, $boolean = 'and', $not = false) { $this->pivotWhereIns[] = func_get_args(); return $this->whereIn($this->table.'.'.$column, $values, $boolean, $not); } /** * Set an "or where" clause for a pivot table column. * * @param string $column * @param mixed $operator * @param mixed $value * @return $this */ public function orWherePivot($column, $operator = null, $value = null) { return $this->wherePivot($column, $operator, $value, 'or'); } /** * Set a where clause for a pivot table column. * * In addition, new pivot records will receive this value. * * @param string|array $column * @param mixed $value * @return $this * * @throws \InvalidArgumentException */ public function withPivotValue($column, $value = null) { if (is_array($column)) { foreach ($column as $name => $value) { $this->withPivotValue($name, $value); } return $this; } if (is_null($value)) { throw new InvalidArgumentException('The provided value may not be null.'); } $this->pivotValues[] = compact('column', 'value'); return $this->wherePivot($column, '=', $value); } /** * Set an "or where in" clause for a pivot table column. * * @param string $column * @param mixed $values * @return $this */ public function orWherePivotIn($column, $values) { return $this->wherePivotIn($column, $values, 'or'); } /** * Set a "where not in" clause for a pivot table column. * * @param string $column * @param mixed $values * @param string $boolean * @return $this */ public function wherePivotNotIn($column, $values, $boolean = 'and') { return $this->wherePivotIn($column, $values, $boolean, true); } /** * Set an "or where not in" clause for a pivot table column. * * @param string $column * @param mixed $values * @return $this */ public function orWherePivotNotIn($column, $values) { return $this->wherePivotNotIn($column, $values, 'or'); } /** * Set a "where null" clause for a pivot table column. * * @param string $column * @param string $boolean * @param bool $not * @return $this */ public function wherePivotNull($column, $boolean = 'and', $not = false) { $this->pivotWhereNulls[] = func_get_args(); return $this->whereNull($this->table.'.'.$column, $boolean, $not); } /** * Set a "where not null" clause for a pivot table column. * * @param string $column * @param string $boolean * @return $this */ public function wherePivotNotNull($column, $boolean = 'and') { return $this->wherePivotNull($column, $boolean, true); } /** * Set a "or where null" clause for a pivot table column. * * @param string $column * @param bool $not * @return $this */ public function orWherePivotNull($column, $not = false) { return $this->wherePivotNull($column, 'or', $not); } /** * Set a "or where not null" clause for a pivot table column. * * @param string $column * @param bool $not * @return $this */ public function orWherePivotNotNull($column) { return $this->orWherePivotNull($column, true); } /** * Find a related model by its primary key or return new instance of the related model. * * @param mixed $id * @param array $columns * @return \Illuminate\Support\Collection|\Illuminate\Database\Eloquent\Model */ public function findOrNew($id, $columns = ['*']) { if (is_null($instance = $this->find($id, $columns))) { $instance = $this->related->newInstance(); } return $instance; } /** * Get the first related model record matching the attributes or instantiate it. * * @param array $attributes * @return \Illuminate\Database\Eloquent\Model */ public function firstOrNew(array $attributes) { if (is_null($instance = $this->where($attributes)->first())) { $instance = $this->related->newInstance($attributes); } return $instance; } /** * Get the first related record matching the attributes or create it. * * @param array $attributes * @param array $joining * @param bool $touch * @return \Illuminate\Database\Eloquent\Model */ public function firstOrCreate(array $attributes, array $joining = [], $touch = true) { if (is_null($instance = $this->where($attributes)->first())) { $instance = $this->create($attributes, $joining, $touch); } return $instance; } /** * Create or update a related record matching the attributes, and fill it with values. * * @param array $attributes * @param array $values * @param array $joining * @param bool $touch * @return \Illuminate\Database\Eloquent\Model */ public function updateOrCreate(array $attributes, array $values = [], array $joining = [], $touch = true) { if (is_null($instance = $this->where($attributes)->first())) { return $this->create($values, $joining, $touch); } $instance->fill($values); $instance->save(['touch' => false]); return $instance; } /** * Find a related model by its primary key. * * @param mixed $id * @param array $columns * @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection|null */ public function find($id, $columns = ['*']) { if (! $id instanceof Model && (is_array($id) || $id instanceof Arrayable)) { return $this->findMany($id, $columns); } return $this->where( $this->getRelated()->getQualifiedKeyName(), '=', $this->parseId($id) )->first($columns); } /** * Find multiple related models by their primary keys. * * @param \Illuminate\Contracts\Support\Arrayable|array $ids * @param array $columns * @return \Illuminate\Database\Eloquent\Collection */ public function findMany($ids, $columns = ['*']) { $ids = $ids instanceof Arrayable ? $ids->toArray() : $ids; if (empty($ids)) { return $this->getRelated()->newCollection(); } return $this->whereIn( $this->getRelated()->getQualifiedKeyName(), $this->parseIds($ids) )->get($columns); } /** * Find a related model by its primary key or throw an exception. * * @param mixed $id * @param array $columns * @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection * * @throws \Illuminate\Database\Eloquent\ModelNotFoundException */ public function findOrFail($id, $columns = ['*']) { $result = $this->find($id, $columns); $id = $id instanceof Arrayable ? $id->toArray() : $id; if (is_array($id)) { if (count($result) === count(array_unique($id))) { return $result; } } elseif (! is_null($result)) { return $result; } throw (new ModelNotFoundException)->setModel(get_class($this->related), $id); } /** * Add a basic where clause to the query, and return the first result. * * @param \Closure|string|array $column * @param mixed $operator * @param mixed $value * @param string $boolean * @return \Illuminate\Database\Eloquent\Model|static */ public function firstWhere($column, $operator = null, $value = null, $boolean = 'and') { return $this->where($column, $operator, $value, $boolean)->first(); } /** * Execute the query and get the first result. * * @param array $columns * @return mixed */ public function first($columns = ['*']) { $results = $this->take(1)->get($columns); return count($results) > 0 ? $results->first() : null; } /** * Execute the query and get the first result or throw an exception. * * @param array $columns * @return \Illuminate\Database\Eloquent\Model|static * * @throws \Illuminate\Database\Eloquent\ModelNotFoundException */ public function firstOrFail($columns = ['*']) { if (! is_null($model = $this->first($columns))) { return $model; } throw (new ModelNotFoundException)->setModel(get_class($this->related)); } /** * Get the results of the relationship. * * @return mixed */ public function getResults() { return ! is_null($this->parent->{$this->parentKey}) ? $this->get() : $this->related->newCollection(); } /** * Execute the query as a "select" statement. * * @param array $columns * @return \Illuminate\Database\Eloquent\Collection */ public function get($columns = ['*']) { // First we'll add the proper select columns onto the query so it is run with // the proper columns. Then, we will get the results and hydrate out pivot // models with the result of those columns as a separate model relation. $builder = $this->query->applyScopes(); $columns = $builder->getQuery()->columns ? [] : $columns; $models = $builder->addSelect( $this->shouldSelect($columns) )->getModels(); $this->hydratePivotRelation($models); // If we actually found models we will also eager load any relationships that // have been specified as needing to be eager loaded. This will solve the // n + 1 query problem for the developer and also increase performance. if (count($models) > 0) { $models = $builder->eagerLoadRelations($models); } return $this->related->newCollection($models); } /** * Get the select columns for the relation query. * * @param array $columns * @return array */ protected function shouldSelect(array $columns = ['*']) { if ($columns == ['*']) { $columns = [$this->related->getTable().'.*']; } return array_merge($columns, $this->aliasedPivotColumns()); } /** * Get the pivot columns for the relation. * * "pivot_" is prefixed ot each column for easy removal later. * * @return array */ protected function aliasedPivotColumns() { $defaults = [$this->foreignPivotKey, $this->relatedPivotKey]; return collect(array_merge($defaults, $this->pivotColumns))->map(function ($column) { return $this->table.'.'.$column.' as pivot_'.$column; })->unique()->all(); } /** * Get a paginator for the "select" statement. * * @param int|null $perPage * @param array $columns * @param string $pageName * @param int|null $page * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator */ public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null) { $this->query->addSelect($this->shouldSelect($columns)); return tap($this->query->paginate($perPage, $columns, $pageName, $page), function ($paginator) { $this->hydratePivotRelation($paginator->items()); }); } /** * Paginate the given query into a simple paginator. * * @param int|null $perPage * @param array $columns * @param string $pageName * @param int|null $page * @return \Illuminate\Contracts\Pagination\Paginator */ public function simplePaginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null) { $this->query->addSelect($this->shouldSelect($columns)); return tap($this->query->simplePaginate($perPage, $columns, $pageName, $page), function ($paginator) { $this->hydratePivotRelation($paginator->items()); }); } /** * Chunk the results of the query. * * @param int $count * @param callable $callback * @return bool */ public function chunk($count, callable $callback) { $this->query->addSelect($this->shouldSelect()); return $this->query->chunk($count, function ($results) use ($callback) { $this->hydratePivotRelation($results->all()); return $callback($results); }); } /** * Chunk the results of a query by comparing numeric IDs. * * @param int $count * @param callable $callback * @param string|null $column * @param string|null $alias * @return bool */ public function chunkById($count, callable $callback, $column = null, $alias = null) { $this->query->addSelect($this->shouldSelect()); $column = $column ?? $this->getRelated()->qualifyColumn( $this->getRelatedKeyName() ); $alias = $alias ?? $this->getRelatedKeyName(); return $this->query->chunkById($count, function ($results) use ($callback) { $this->hydratePivotRelation($results->all()); return $callback($results); }, $column, $alias); } /** * Execute a callback over each item while chunking. * * @param callable $callback * @param int $count * @return bool */ public function each(callable $callback, $count = 1000) { return $this->chunk($count, function ($results) use ($callback) { foreach ($results as $key => $value) { if ($callback($value, $key) === false) { return false; } } }); } /** * Get a lazy collection for the given query. * * @return \Illuminate\Support\LazyCollection */ public function cursor() { $this->query->addSelect($this->shouldSelect()); return $this->query->cursor()->map(function ($model) { $this->hydratePivotRelation([$model]); return $model; }); } /** * Hydrate the pivot table relationship on the models. * * @param array $models * @return void */ protected function hydratePivotRelation(array $models) { // To hydrate the pivot relationship, we will just gather the pivot attributes // and create a new Pivot model, which is basically a dynamic model that we // will set the attributes, table, and connections on it so it will work. foreach ($models as $model) { $model->setRelation($this->accessor, $this->newExistingPivot( $this->migratePivotAttributes($model) )); } } /** * Get the pivot attributes from a model. * * @param \Illuminate\Database\Eloquent\Model $model * @return array */ protected function migratePivotAttributes(Model $model) { $values = []; foreach ($model->getAttributes() as $key => $value) { // To get the pivots attributes we will just take any of the attributes which // begin with "pivot_" and add those to this arrays, as well as unsetting // them from the parent's models since they exist in a different table. if (strpos($key, 'pivot_') === 0) { $values[substr($key, 6)] = $value; unset($model->$key); } } return $values; } /** * If we're touching the parent model, touch. * * @return void */ public function touchIfTouching() { if ($this->touchingParent()) { $this->getParent()->touch(); } if ($this->getParent()->touches($this->relationName)) { $this->touch(); } } /** * Determine if we should touch the parent on sync. * * @return bool */ protected function touchingParent() { return $this->getRelated()->touches($this->guessInverseRelation()); } /** * Attempt to guess the name of the inverse of the relation. * * @return string */ protected function guessInverseRelation() { return Str::camel(Str::pluralStudly(class_basename($this->getParent()))); } /** * Touch all of the related models for the relationship. * * E.g.: Touch all roles associated with this user. * * @return void */ public function touch() { $key = $this->getRelated()->getKeyName(); $columns = [ $this->related->getUpdatedAtColumn() => $this->related->freshTimestampString(), ]; // If we actually have IDs for the relation, we will run the query to update all // the related model's timestamps, to make sure these all reflect the changes // to the parent models. This will help us keep any caching synced up here. if (count($ids = $this->allRelatedIds()) > 0) { $this->getRelated()->newQueryWithoutRelationships()->whereIn($key, $ids)->update($columns); } } /** * Get all of the IDs for the related models. * * @return \Illuminate\Support\Collection */ public function allRelatedIds() { return $this->newPivotQuery()->pluck($this->relatedPivotKey); } /** * Save a new model and attach it to the parent model. * * @param \Illuminate\Database\Eloquent\Model $model * @param array $pivotAttributes * @param bool $touch * @return \Illuminate\Database\Eloquent\Model */ public function save(Model $model, array $pivotAttributes = [], $touch = true) { $model->save(['touch' => false]); $this->attach($model, $pivotAttributes, $touch); return $model; } /** * Save an array of new models and attach them to the parent model. * * @param \Illuminate\Support\Collection|array $models * @param array $pivotAttributes * @return array */ public function saveMany($models, array $pivotAttributes = []) { foreach ($models as $key => $model) { $this->save($model, (array) ($pivotAttributes[$key] ?? []), false); } $this->touchIfTouching(); return $models; } /** * Create a new instance of the related model. * * @param array $attributes * @param array $joining * @param bool $touch * @return \Illuminate\Database\Eloquent\Model */ public function create(array $attributes = [], array $joining = [], $touch = true) { $instance = $this->related->newInstance($attributes); // Once we save the related model, we need to attach it to the base model via // through intermediate table so we'll use the existing "attach" method to // accomplish this which will insert the record and any more attributes. $instance->save(['touch' => false]); $this->attach($instance, $joining, $touch); return $instance; } /** * Create an array of new instances of the related models. * * @param iterable $records * @param array $joinings * @return array */ public function createMany(iterable $records, array $joinings = []) { $instances = []; foreach ($records as $key => $record) { $instances[] = $this->create($record, (array) ($joinings[$key] ?? []), false); } $this->touchIfTouching(); return $instances; } /** * Add the constraints for a relationship query. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Builder $parentQuery * @param array|mixed $columns * @return \Illuminate\Database\Eloquent\Builder */ public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*']) { if ($parentQuery->getQuery()->from == $query->getQuery()->from) { return $this->getRelationExistenceQueryForSelfJoin($query, $parentQuery, $columns); } $this->performJoin($query); return parent::getRelationExistenceQuery($query, $parentQuery, $columns); } /** * Add the constraints for a relationship query on the same table. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Builder $parentQuery * @param array|mixed $columns * @return \Illuminate\Database\Eloquent\Builder */ public function getRelationExistenceQueryForSelfJoin(Builder $query, Builder $parentQuery, $columns = ['*']) { $query->select($columns); $query->from($this->related->getTable().' as '.$hash = $this->getRelationCountHash()); $this->related->setTable($hash); $this->performJoin($query); return parent::getRelationExistenceQuery($query, $parentQuery, $columns); } /** * Get the key for comparing against the parent key in "has" query. * * @return string */ public function getExistenceCompareKey() { return $this->getQualifiedForeignPivotKeyName(); } /** * Get a relationship join table hash. * * @return string */ public function getRelationCountHash() { return 'laravel_reserved_'.static::$selfJoinCount++; } /** * Specify that the pivot table has creation and update timestamps. * * @param mixed $createdAt * @param mixed $updatedAt * @return $this */ public function withTimestamps($createdAt = null, $updatedAt = null) { $this->withTimestamps = true; $this->pivotCreatedAt = $createdAt; $this->pivotUpdatedAt = $updatedAt; return $this->withPivot($this->createdAt(), $this->updatedAt()); } /** * Get the name of the "created at" column. * * @return string */ public function createdAt() { return $this->pivotCreatedAt ?: $this->parent->getCreatedAtColumn(); } /** * Get the name of the "updated at" column. * * @return string */ public function updatedAt() { return $this->pivotUpdatedAt ?: $this->parent->getUpdatedAtColumn(); } /** * Get the foreign key for the relation. * * @return string */ public function getForeignPivotKeyName() { return $this->foreignPivotKey; } /** * Get the fully qualified foreign key for the relation. * * @return string */ public function getQualifiedForeignPivotKeyName() { return $this->table.'.'.$this->foreignPivotKey; } /** * Get the "related key" for the relation. * * @return string */ public function getRelatedPivotKeyName() { return $this->relatedPivotKey; } /** * Get the fully qualified "related key" for the relation. * * @return string */ public function getQualifiedRelatedPivotKeyName() { return $this->table.'.'.$this->relatedPivotKey; } /** * Get the parent key for the relationship. * * @return string */ public function getParentKeyName() { return $this->parentKey; } /** * Get the fully qualified parent key name for the relation. * * @return string */ public function getQualifiedParentKeyName() { return $this->parent->qualifyColumn($this->parentKey); } /** * Get the related key for the relationship. * * @return string */ public function getRelatedKeyName() { return $this->relatedKey; } /** * Get the intermediate table for the relationship. * * @return string */ public function getTable() { return $this->table; } /** * Get the relationship name for the relationship. * * @return string */ public function getRelationName() { return $this->relationName; } /** * Get the name of the pivot accessor for this relationship. * * @return string */ public function getPivotAccessor() { return $this->accessor; } /** * Get the pivot columns for this relationship. * * @return array */ public function getPivotColumns() { return $this->pivotColumns; } } database/Eloquent/Relations/Relation.php 0000644 00000023502 14736103231 0014334 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Relations; use Closure; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Query\Expression; use Illuminate\Support\Arr; use Illuminate\Support\Traits\ForwardsCalls; use Illuminate\Support\Traits\Macroable; /** * @mixin \Illuminate\Database\Eloquent\Builder */ abstract class Relation { use ForwardsCalls, Macroable { __call as macroCall; } /** * The Eloquent query builder instance. * * @var \Illuminate\Database\Eloquent\Builder */ protected $query; /** * The parent model instance. * * @var \Illuminate\Database\Eloquent\Model */ protected $parent; /** * The related model instance. * * @var \Illuminate\Database\Eloquent\Model */ protected $related; /** * Indicates if the relation is adding constraints. * * @var bool */ protected static $constraints = true; /** * An array to map class names to their morph names in database. * * @var array */ public static $morphMap = []; /** * Create a new relation instance. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Model $parent * @return void */ public function __construct(Builder $query, Model $parent) { $this->query = $query; $this->parent = $parent; $this->related = $query->getModel(); $this->addConstraints(); } /** * Run a callback with constraints disabled on the relation. * * @param \Closure $callback * @return mixed */ public static function noConstraints(Closure $callback) { $previous = static::$constraints; static::$constraints = false; // When resetting the relation where clause, we want to shift the first element // off of the bindings, leaving only the constraints that the developers put // as "extra" on the relationships, and not original relation constraints. try { return $callback(); } finally { static::$constraints = $previous; } } /** * Set the base constraints on the relation query. * * @return void */ abstract public function addConstraints(); /** * Set the constraints for an eager load of the relation. * * @param array $models * @return void */ abstract public function addEagerConstraints(array $models); /** * Initialize the relation on a set of models. * * @param array $models * @param string $relation * @return array */ abstract public function initRelation(array $models, $relation); /** * Match the eagerly loaded results to their parents. * * @param array $models * @param \Illuminate\Database\Eloquent\Collection $results * @param string $relation * @return array */ abstract public function match(array $models, Collection $results, $relation); /** * Get the results of the relationship. * * @return mixed */ abstract public function getResults(); /** * Get the relationship for eager loading. * * @return \Illuminate\Database\Eloquent\Collection */ public function getEager() { return $this->get(); } /** * Execute the query as a "select" statement. * * @param array $columns * @return \Illuminate\Database\Eloquent\Collection */ public function get($columns = ['*']) { return $this->query->get($columns); } /** * Touch all of the related models for the relationship. * * @return void */ public function touch() { $model = $this->getRelated(); if (! $model::isIgnoringTouch()) { $this->rawUpdate([ $model->getUpdatedAtColumn() => $model->freshTimestampString(), ]); } } /** * Run a raw update against the base query. * * @param array $attributes * @return int */ public function rawUpdate(array $attributes = []) { return $this->query->withoutGlobalScopes()->update($attributes); } /** * Add the constraints for a relationship count query. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Builder $parentQuery * @return \Illuminate\Database\Eloquent\Builder */ public function getRelationExistenceCountQuery(Builder $query, Builder $parentQuery) { return $this->getRelationExistenceQuery( $query, $parentQuery, new Expression('count(*)') )->setBindings([], 'select'); } /** * Add the constraints for an internal relationship existence query. * * Essentially, these queries compare on column names like whereColumn. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Builder $parentQuery * @param array|mixed $columns * @return \Illuminate\Database\Eloquent\Builder */ public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*']) { return $query->select($columns)->whereColumn( $this->getQualifiedParentKeyName(), '=', $this->getExistenceCompareKey() ); } /** * Get all of the primary keys for an array of models. * * @param array $models * @param string|null $key * @return array */ protected function getKeys(array $models, $key = null) { return collect($models)->map(function ($value) use ($key) { return $key ? $value->getAttribute($key) : $value->getKey(); })->values()->unique(null, true)->sort()->all(); } /** * Get the underlying query for the relation. * * @return \Illuminate\Database\Eloquent\Builder */ public function getQuery() { return $this->query; } /** * Get the base query builder driving the Eloquent builder. * * @return \Illuminate\Database\Query\Builder */ public function getBaseQuery() { return $this->query->getQuery(); } /** * Get the parent model of the relation. * * @return \Illuminate\Database\Eloquent\Model */ public function getParent() { return $this->parent; } /** * Get the fully qualified parent key name. * * @return string */ public function getQualifiedParentKeyName() { return $this->parent->getQualifiedKeyName(); } /** * Get the related model of the relation. * * @return \Illuminate\Database\Eloquent\Model */ public function getRelated() { return $this->related; } /** * Get the name of the "created at" column. * * @return string */ public function createdAt() { return $this->parent->getCreatedAtColumn(); } /** * Get the name of the "updated at" column. * * @return string */ public function updatedAt() { return $this->parent->getUpdatedAtColumn(); } /** * Get the name of the related model's "updated at" column. * * @return string */ public function relatedUpdatedAt() { return $this->related->getUpdatedAtColumn(); } /** * Get the name of the "where in" method for eager loading. * * @param \Illuminate\Database\Eloquent\Model $model * @param string $key * @return string */ protected function whereInMethod(Model $model, $key) { return $model->getKeyName() === last(explode('.', $key)) && in_array($model->getKeyType(), ['int', 'integer']) ? 'whereIntegerInRaw' : 'whereIn'; } /** * Set or get the morph map for polymorphic relations. * * @param array|null $map * @param bool $merge * @return array */ public static function morphMap(array $map = null, $merge = true) { $map = static::buildMorphMapFromModels($map); if (is_array($map)) { static::$morphMap = $merge && static::$morphMap ? $map + static::$morphMap : $map; } return static::$morphMap; } /** * Builds a table-keyed array from model class names. * * @param string[]|null $models * @return array|null */ protected static function buildMorphMapFromModels(array $models = null) { if (is_null($models) || Arr::isAssoc($models)) { return $models; } return array_combine(array_map(function ($model) { return (new $model)->getTable(); }, $models), $models); } /** * Get the model associated with a custom polymorphic type. * * @param string $alias * @return string|null */ public static function getMorphedModel($alias) { return static::$morphMap[$alias] ?? null; } /** * Handle dynamic method calls to the relationship. * * @param string $method * @param array $parameters * @return mixed */ public function __call($method, $parameters) { if (static::hasMacro($method)) { return $this->macroCall($method, $parameters); } $result = $this->forwardCallTo($this->query, $method, $parameters); if ($result === $this->query) { return $this; } return $result; } /** * Force a clone of the underlying query builder when cloning. * * @return void */ public function __clone() { $this->query = clone $this->query; } } database/Eloquent/Relations/MorphToMany.php 0000644 00000012174 14736103231 0014777 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Relations; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Arr; class MorphToMany extends BelongsToMany { /** * The type of the polymorphic relation. * * @var string */ protected $morphType; /** * The class name of the morph type constraint. * * @var string */ protected $morphClass; /** * Indicates if we are connecting the inverse of the relation. * * This primarily affects the morphClass constraint. * * @var bool */ protected $inverse; /** * Create a new morph to many relationship instance. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Model $parent * @param string $name * @param string $table * @param string $foreignPivotKey * @param string $relatedPivotKey * @param string $parentKey * @param string $relatedKey * @param string|null $relationName * @param bool $inverse * @return void */ public function __construct(Builder $query, Model $parent, $name, $table, $foreignPivotKey, $relatedPivotKey, $parentKey, $relatedKey, $relationName = null, $inverse = false) { $this->inverse = $inverse; $this->morphType = $name.'_type'; $this->morphClass = $inverse ? $query->getModel()->getMorphClass() : $parent->getMorphClass(); parent::__construct( $query, $parent, $table, $foreignPivotKey, $relatedPivotKey, $parentKey, $relatedKey, $relationName ); } /** * Set the where clause for the relation query. * * @return $this */ protected function addWhereConstraints() { parent::addWhereConstraints(); $this->query->where($this->table.'.'.$this->morphType, $this->morphClass); return $this; } /** * Set the constraints for an eager load of the relation. * * @param array $models * @return void */ public function addEagerConstraints(array $models) { parent::addEagerConstraints($models); $this->query->where($this->table.'.'.$this->morphType, $this->morphClass); } /** * Create a new pivot attachment record. * * @param int $id * @param bool $timed * @return array */ protected function baseAttachRecord($id, $timed) { return Arr::add( parent::baseAttachRecord($id, $timed), $this->morphType, $this->morphClass ); } /** * Add the constraints for a relationship count query. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Builder $parentQuery * @param array|mixed $columns * @return \Illuminate\Database\Eloquent\Builder */ public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*']) { return parent::getRelationExistenceQuery($query, $parentQuery, $columns)->where( $this->table.'.'.$this->morphType, $this->morphClass ); } /** * Create a new query builder for the pivot table. * * @return \Illuminate\Database\Query\Builder */ public function newPivotQuery() { return parent::newPivotQuery()->where($this->morphType, $this->morphClass); } /** * Create a new pivot model instance. * * @param array $attributes * @param bool $exists * @return \Illuminate\Database\Eloquent\Relations\Pivot */ public function newPivot(array $attributes = [], $exists = false) { $using = $this->using; $pivot = $using ? $using::fromRawAttributes($this->parent, $attributes, $this->table, $exists) : MorphPivot::fromAttributes($this->parent, $attributes, $this->table, $exists); $pivot->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey) ->setMorphType($this->morphType) ->setMorphClass($this->morphClass); return $pivot; } /** * Get the pivot columns for the relation. * * "pivot_" is prefixed at each column for easy removal later. * * @return array */ protected function aliasedPivotColumns() { $defaults = [$this->foreignPivotKey, $this->relatedPivotKey, $this->morphType]; return collect(array_merge($defaults, $this->pivotColumns))->map(function ($column) { return $this->table.'.'.$column.' as pivot_'.$column; })->unique()->all(); } /** * Get the foreign key "type" name. * * @return string */ public function getMorphType() { return $this->morphType; } /** * Get the class name of the parent model. * * @return string */ public function getMorphClass() { return $this->morphClass; } /** * Get the indicator for a reverse relationship. * * @return bool */ public function getInverse() { return $this->inverse; } } database/Eloquent/Relations/MorphTo.php 0000644 00000022567 14736103231 0014161 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Relations; use BadMethodCallException; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; class MorphTo extends BelongsTo { /** * The type of the polymorphic relation. * * @var string */ protected $morphType; /** * The models whose relations are being eager loaded. * * @var \Illuminate\Database\Eloquent\Collection */ protected $models; /** * All of the models keyed by ID. * * @var array */ protected $dictionary = []; /** * A buffer of dynamic calls to query macros. * * @var array */ protected $macroBuffer = []; /** * A map of relations to load for each individual morph type. * * @var array */ protected $morphableEagerLoads = []; /** * A map of relationship counts to load for each individual morph type. * * @var array */ protected $morphableEagerLoadCounts = []; /** * Create a new morph to relationship instance. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Model $parent * @param string $foreignKey * @param string $ownerKey * @param string $type * @param string $relation * @return void */ public function __construct(Builder $query, Model $parent, $foreignKey, $ownerKey, $type, $relation) { $this->morphType = $type; parent::__construct($query, $parent, $foreignKey, $ownerKey, $relation); } /** * Set the constraints for an eager load of the relation. * * @param array $models * @return void */ public function addEagerConstraints(array $models) { $this->buildDictionary($this->models = Collection::make($models)); } /** * Build a dictionary with the models. * * @param \Illuminate\Database\Eloquent\Collection $models * @return void */ protected function buildDictionary(Collection $models) { foreach ($models as $model) { if ($model->{$this->morphType}) { $this->dictionary[$model->{$this->morphType}][$model->{$this->foreignKey}][] = $model; } } } /** * Get the results of the relationship. * * Called via eager load method of Eloquent query builder. * * @return mixed */ public function getEager() { foreach (array_keys($this->dictionary) as $type) { $this->matchToMorphParents($type, $this->getResultsByType($type)); } return $this->models; } /** * Get all of the relation results for a type. * * @param string $type * @return \Illuminate\Database\Eloquent\Collection */ protected function getResultsByType($type) { $instance = $this->createModelByType($type); $ownerKey = $this->ownerKey ?? $instance->getKeyName(); $query = $this->replayMacros($instance->newQuery()) ->mergeConstraintsFrom($this->getQuery()) ->with(array_merge( $this->getQuery()->getEagerLoads(), (array) ($this->morphableEagerLoads[get_class($instance)] ?? []) )) ->withCount( (array) ($this->morphableEagerLoadCounts[get_class($instance)] ?? []) ); $whereIn = $this->whereInMethod($instance, $ownerKey); return $query->{$whereIn}( $instance->getTable().'.'.$ownerKey, $this->gatherKeysByType($type) )->get(); } /** * Gather all of the foreign keys for a given type. * * @param string $type * @return array */ protected function gatherKeysByType($type) { return array_keys($this->dictionary[$type]); } /** * Create a new model instance by type. * * @param string $type * @return \Illuminate\Database\Eloquent\Model */ public function createModelByType($type) { $class = Model::getActualClassNameForMorph($type); return tap(new $class, function ($instance) { if (! $instance->getConnectionName()) { $instance->setConnection($this->getConnection()->getName()); } }); } /** * Match the eagerly loaded results to their parents. * * @param array $models * @param \Illuminate\Database\Eloquent\Collection $results * @param string $relation * @return array */ public function match(array $models, Collection $results, $relation) { return $models; } /** * Match the results for a given type to their parents. * * @param string $type * @param \Illuminate\Database\Eloquent\Collection $results * @return void */ protected function matchToMorphParents($type, Collection $results) { foreach ($results as $result) { $ownerKey = ! is_null($this->ownerKey) ? $result->{$this->ownerKey} : $result->getKey(); if (isset($this->dictionary[$type][$ownerKey])) { foreach ($this->dictionary[$type][$ownerKey] as $model) { $model->setRelation($this->relationName, $result); } } } } /** * Associate the model instance to the given parent. * * @param \Illuminate\Database\Eloquent\Model $model * @return \Illuminate\Database\Eloquent\Model */ public function associate($model) { $this->parent->setAttribute( $this->foreignKey, $model instanceof Model ? $model->getKey() : null ); $this->parent->setAttribute( $this->morphType, $model instanceof Model ? $model->getMorphClass() : null ); return $this->parent->setRelation($this->relationName, $model); } /** * Dissociate previously associated model from the given parent. * * @return \Illuminate\Database\Eloquent\Model */ public function dissociate() { $this->parent->setAttribute($this->foreignKey, null); $this->parent->setAttribute($this->morphType, null); return $this->parent->setRelation($this->relationName, null); } /** * Touch all of the related models for the relationship. * * @return void */ public function touch() { if (! is_null($this->child->{$this->foreignKey})) { parent::touch(); } } /** * Make a new related instance for the given model. * * @param \Illuminate\Database\Eloquent\Model $parent * @return \Illuminate\Database\Eloquent\Model */ protected function newRelatedInstanceFor(Model $parent) { return $parent->{$this->getRelationName()}()->getRelated()->newInstance(); } /** * Get the foreign key "type" name. * * @return string */ public function getMorphType() { return $this->morphType; } /** * Get the dictionary used by the relationship. * * @return array */ public function getDictionary() { return $this->dictionary; } /** * Specify which relations to load for a given morph type. * * @param array $with * @return \Illuminate\Database\Eloquent\Relations\MorphTo */ public function morphWith(array $with) { $this->morphableEagerLoads = array_merge( $this->morphableEagerLoads, $with ); return $this; } /** * Specify which relationship counts to load for a given morph type. * * @param array $withCount * @return \Illuminate\Database\Eloquent\Relations\MorphTo */ public function morphWithCount(array $withCount) { $this->morphableEagerLoadCounts = array_merge( $this->morphableEagerLoadCounts, $withCount ); return $this; } /** * Replay stored macro calls on the actual related instance. * * @param \Illuminate\Database\Eloquent\Builder $query * @return \Illuminate\Database\Eloquent\Builder */ protected function replayMacros(Builder $query) { foreach ($this->macroBuffer as $macro) { $query->{$macro['method']}(...$macro['parameters']); } return $query; } /** * Handle dynamic method calls to the relationship. * * @param string $method * @param array $parameters * @return mixed */ public function __call($method, $parameters) { try { $result = parent::__call($method, $parameters); if (in_array($method, ['select', 'selectRaw', 'selectSub', 'addSelect', 'withoutGlobalScopes'])) { $this->macroBuffer[] = compact('method', 'parameters'); } return $result; } // If we tried to call a method that does not exist on the parent Builder instance, // we'll assume that we want to call a query macro (e.g. withTrashed) that only // exists on related models. We will just store the call and replay it later. catch (BadMethodCallException $e) { $this->macroBuffer[] = compact('method', 'parameters'); return $this; } } } database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php 0000644 00000047455 14736103231 0021130 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Relations\Concerns; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\Pivot; use Illuminate\Support\Collection as BaseCollection; trait InteractsWithPivotTable { /** * Toggles a model (or models) from the parent. * * Each existing model is detached, and non existing ones are attached. * * @param mixed $ids * @param bool $touch * @return array */ public function toggle($ids, $touch = true) { $changes = [ 'attached' => [], 'detached' => [], ]; $records = $this->formatRecordsList($this->parseIds($ids)); // Next, we will determine which IDs should get removed from the join table by // checking which of the given ID/records is in the list of current records // and removing all of those rows from this "intermediate" joining table. $detach = array_values(array_intersect( $this->newPivotQuery()->pluck($this->relatedPivotKey)->all(), array_keys($records) )); if (count($detach) > 0) { $this->detach($detach, false); $changes['detached'] = $this->castKeys($detach); } // Finally, for all of the records which were not "detached", we'll attach the // records into the intermediate table. Then, we will add those attaches to // this change list and get ready to return these results to the callers. $attach = array_diff_key($records, array_flip($detach)); if (count($attach) > 0) { $this->attach($attach, [], false); $changes['attached'] = array_keys($attach); } // Once we have finished attaching or detaching the records, we will see if we // have done any attaching or detaching, and if we have we will touch these // relationships if they are configured to touch on any database updates. if ($touch && (count($changes['attached']) || count($changes['detached']))) { $this->touchIfTouching(); } return $changes; } /** * Sync the intermediate tables with a list of IDs without detaching. * * @param \Illuminate\Support\Collection|\Illuminate\Database\Eloquent\Model|array $ids * @return array */ public function syncWithoutDetaching($ids) { return $this->sync($ids, false); } /** * Sync the intermediate tables with a list of IDs or collection of models. * * @param \Illuminate\Support\Collection|\Illuminate\Database\Eloquent\Model|array $ids * @param bool $detaching * @return array */ public function sync($ids, $detaching = true) { $changes = [ 'attached' => [], 'detached' => [], 'updated' => [], ]; // First we need to attach any of the associated models that are not currently // in this joining table. We'll spin through the given IDs, checking to see // if they exist in the array of current ones, and if not we will insert. $current = $this->getCurrentlyAttachedPivots() ->pluck($this->relatedPivotKey)->all(); $detach = array_diff($current, array_keys( $records = $this->formatRecordsList($this->parseIds($ids)) )); // Next, we will take the differences of the currents and given IDs and detach // all of the entities that exist in the "current" array but are not in the // array of the new IDs given to the method which will complete the sync. if ($detaching && count($detach) > 0) { $this->detach($detach); $changes['detached'] = $this->castKeys($detach); } // Now we are finally ready to attach the new records. Note that we'll disable // touching until after the entire operation is complete so we don't fire a // ton of touch operations until we are totally done syncing the records. $changes = array_merge( $changes, $this->attachNew($records, $current, false) ); // Once we have finished attaching or detaching the records, we will see if we // have done any attaching or detaching, and if we have we will touch these // relationships if they are configured to touch on any database updates. if (count($changes['attached']) || count($changes['updated'])) { $this->touchIfTouching(); } return $changes; } /** * Format the sync / toggle record list so that it is keyed by ID. * * @param array $records * @return array */ protected function formatRecordsList(array $records) { return collect($records)->mapWithKeys(function ($attributes, $id) { if (! is_array($attributes)) { [$id, $attributes] = [$attributes, []]; } return [$id => $attributes]; })->all(); } /** * Attach all of the records that aren't in the given current records. * * @param array $records * @param array $current * @param bool $touch * @return array */ protected function attachNew(array $records, array $current, $touch = true) { $changes = ['attached' => [], 'updated' => []]; foreach ($records as $id => $attributes) { // If the ID is not in the list of existing pivot IDs, we will insert a new pivot // record, otherwise, we will just update this existing record on this joining // table, so that the developers will easily update these records pain free. if (! in_array($id, $current)) { $this->attach($id, $attributes, $touch); $changes['attached'][] = $this->castKey($id); } // Now we'll try to update an existing pivot record with the attributes that were // given to the method. If the model is actually updated we will add it to the // list of updated pivot records so we return them back out to the consumer. elseif (count($attributes) > 0 && $this->updateExistingPivot($id, $attributes, $touch)) { $changes['updated'][] = $this->castKey($id); } } return $changes; } /** * Update an existing pivot record on the table. * * @param mixed $id * @param array $attributes * @param bool $touch * @return int */ public function updateExistingPivot($id, array $attributes, $touch = true) { if ($this->using && empty($this->pivotWheres) && empty($this->pivotWhereIns) && empty($this->pivotWhereNulls)) { return $this->updateExistingPivotUsingCustomClass($id, $attributes, $touch); } if (in_array($this->updatedAt(), $this->pivotColumns)) { $attributes = $this->addTimestampsToAttachment($attributes, true); } $updated = $this->newPivotStatementForId($this->parseId($id))->update( $this->castAttributes($attributes) ); if ($touch) { $this->touchIfTouching(); } return $updated; } /** * Update an existing pivot record on the table via a custom class. * * @param mixed $id * @param array $attributes * @param bool $touch * @return int */ protected function updateExistingPivotUsingCustomClass($id, array $attributes, $touch) { $pivot = $this->getCurrentlyAttachedPivots() ->where($this->foreignPivotKey, $this->parent->{$this->parentKey}) ->where($this->relatedPivotKey, $this->parseId($id)) ->first(); $updated = $pivot ? $pivot->fill($attributes)->isDirty() : false; if ($updated) { $pivot->save(); } if ($touch) { $this->touchIfTouching(); } return (int) $updated; } /** * Attach a model to the parent. * * @param mixed $id * @param array $attributes * @param bool $touch * @return void */ public function attach($id, array $attributes = [], $touch = true) { if ($this->using) { $this->attachUsingCustomClass($id, $attributes); } else { // Here we will insert the attachment records into the pivot table. Once we have // inserted the records, we will touch the relationships if necessary and the // function will return. We can parse the IDs before inserting the records. $this->newPivotStatement()->insert($this->formatAttachRecords( $this->parseIds($id), $attributes )); } if ($touch) { $this->touchIfTouching(); } } /** * Attach a model to the parent using a custom class. * * @param mixed $id * @param array $attributes * @return void */ protected function attachUsingCustomClass($id, array $attributes) { $records = $this->formatAttachRecords( $this->parseIds($id), $attributes ); foreach ($records as $record) { $this->newPivot($record, false)->save(); } } /** * Create an array of records to insert into the pivot table. * * @param array $ids * @param array $attributes * @return array */ protected function formatAttachRecords($ids, array $attributes) { $records = []; $hasTimestamps = ($this->hasPivotColumn($this->createdAt()) || $this->hasPivotColumn($this->updatedAt())); // To create the attachment records, we will simply spin through the IDs given // and create a new record to insert for each ID. Each ID may actually be a // key in the array, with extra attributes to be placed in other columns. foreach ($ids as $key => $value) { $records[] = $this->formatAttachRecord( $key, $value, $attributes, $hasTimestamps ); } return $records; } /** * Create a full attachment record payload. * * @param int $key * @param mixed $value * @param array $attributes * @param bool $hasTimestamps * @return array */ protected function formatAttachRecord($key, $value, $attributes, $hasTimestamps) { [$id, $attributes] = $this->extractAttachIdAndAttributes($key, $value, $attributes); return array_merge( $this->baseAttachRecord($id, $hasTimestamps), $this->castAttributes($attributes) ); } /** * Get the attach record ID and extra attributes. * * @param mixed $key * @param mixed $value * @param array $attributes * @return array */ protected function extractAttachIdAndAttributes($key, $value, array $attributes) { return is_array($value) ? [$key, array_merge($value, $attributes)] : [$value, $attributes]; } /** * Create a new pivot attachment record. * * @param int $id * @param bool $timed * @return array */ protected function baseAttachRecord($id, $timed) { $record[$this->relatedPivotKey] = $id; $record[$this->foreignPivotKey] = $this->parent->{$this->parentKey}; // If the record needs to have creation and update timestamps, we will make // them by calling the parent model's "freshTimestamp" method which will // provide us with a fresh timestamp in this model's preferred format. if ($timed) { $record = $this->addTimestampsToAttachment($record); } foreach ($this->pivotValues as $value) { $record[$value['column']] = $value['value']; } return $record; } /** * Set the creation and update timestamps on an attach record. * * @param array $record * @param bool $exists * @return array */ protected function addTimestampsToAttachment(array $record, $exists = false) { $fresh = $this->parent->freshTimestamp(); if ($this->using) { $pivotModel = new $this->using; $fresh = $fresh->format($pivotModel->getDateFormat()); } if (! $exists && $this->hasPivotColumn($this->createdAt())) { $record[$this->createdAt()] = $fresh; } if ($this->hasPivotColumn($this->updatedAt())) { $record[$this->updatedAt()] = $fresh; } return $record; } /** * Determine whether the given column is defined as a pivot column. * * @param string $column * @return bool */ public function hasPivotColumn($column) { return in_array($column, $this->pivotColumns); } /** * Detach models from the relationship. * * @param mixed $ids * @param bool $touch * @return int */ public function detach($ids = null, $touch = true) { if ($this->using && ! empty($ids) && empty($this->pivotWheres) && empty($this->pivotWhereIns) && empty($this->pivotWhereNulls)) { $results = $this->detachUsingCustomClass($ids); } else { $query = $this->newPivotQuery(); // If associated IDs were passed to the method we will only delete those // associations, otherwise all of the association ties will be broken. // We'll return the numbers of affected rows when we do the deletes. if (! is_null($ids)) { $ids = $this->parseIds($ids); if (empty($ids)) { return 0; } $query->whereIn($this->relatedPivotKey, (array) $ids); } // Once we have all of the conditions set on the statement, we are ready // to run the delete on the pivot table. Then, if the touch parameter // is true, we will go ahead and touch all related models to sync. $results = $query->delete(); } if ($touch) { $this->touchIfTouching(); } return $results; } /** * Detach models from the relationship using a custom class. * * @param mixed $ids * @return int */ protected function detachUsingCustomClass($ids) { $results = 0; foreach ($this->parseIds($ids) as $id) { $results += $this->newPivot([ $this->foreignPivotKey => $this->parent->{$this->parentKey}, $this->relatedPivotKey => $id, ], true)->delete(); } return $results; } /** * Get the pivot models that are currently attached. * * @return \Illuminate\Support\Collection */ protected function getCurrentlyAttachedPivots() { return $this->newPivotQuery()->get()->map(function ($record) { $class = $this->using ? $this->using : Pivot::class; $pivot = $class::fromRawAttributes($this->parent, (array) $record, $this->getTable(), true); return $pivot->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey); }); } /** * Create a new pivot model instance. * * @param array $attributes * @param bool $exists * @return \Illuminate\Database\Eloquent\Relations\Pivot */ public function newPivot(array $attributes = [], $exists = false) { $pivot = $this->related->newPivot( $this->parent, $attributes, $this->table, $exists, $this->using ); return $pivot->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey); } /** * Create a new existing pivot model instance. * * @param array $attributes * @return \Illuminate\Database\Eloquent\Relations\Pivot */ public function newExistingPivot(array $attributes = []) { return $this->newPivot($attributes, true); } /** * Get a new plain query builder for the pivot table. * * @return \Illuminate\Database\Query\Builder */ public function newPivotStatement() { return $this->query->getQuery()->newQuery()->from($this->table); } /** * Get a new pivot statement for a given "other" ID. * * @param mixed $id * @return \Illuminate\Database\Query\Builder */ public function newPivotStatementForId($id) { return $this->newPivotQuery()->whereIn($this->relatedPivotKey, $this->parseIds($id)); } /** * Create a new query builder for the pivot table. * * @return \Illuminate\Database\Query\Builder */ public function newPivotQuery() { $query = $this->newPivotStatement(); foreach ($this->pivotWheres as $arguments) { call_user_func_array([$query, 'where'], $arguments); } foreach ($this->pivotWhereIns as $arguments) { call_user_func_array([$query, 'whereIn'], $arguments); } foreach ($this->pivotWhereNulls as $arguments) { call_user_func_array([$query, 'whereNull'], $arguments); } return $query->where($this->foreignPivotKey, $this->parent->{$this->parentKey}); } /** * Set the columns on the pivot table to retrieve. * * @param array|mixed $columns * @return $this */ public function withPivot($columns) { $this->pivotColumns = array_merge( $this->pivotColumns, is_array($columns) ? $columns : func_get_args() ); return $this; } /** * Get all of the IDs from the given mixed value. * * @param mixed $value * @return array */ protected function parseIds($value) { if ($value instanceof Model) { return [$value->{$this->relatedKey}]; } if ($value instanceof Collection) { return $value->pluck($this->relatedKey)->all(); } if ($value instanceof BaseCollection) { return $value->toArray(); } return (array) $value; } /** * Get the ID from the given mixed value. * * @param mixed $value * @return mixed */ protected function parseId($value) { return $value instanceof Model ? $value->{$this->relatedKey} : $value; } /** * Cast the given keys to integers if they are numeric and string otherwise. * * @param array $keys * @return array */ protected function castKeys(array $keys) { return array_map(function ($v) { return $this->castKey($v); }, $keys); } /** * Cast the given key to convert to primary key type. * * @param mixed $key * @return mixed */ protected function castKey($key) { return $this->getTypeSwapValue( $this->related->getKeyType(), $key ); } /** * Cast the given pivot attributes. * * @param array $attributes * @return array */ protected function castAttributes($attributes) { return $this->using ? $this->newPivot()->fill($attributes)->getAttributes() : $attributes; } /** * Converts a given value to a given type value. * * @param string $type * @param mixed $value * @return mixed */ protected function getTypeSwapValue($type, $value) { switch (strtolower($type)) { case 'int': case 'integer': return (int) $value; case 'real': case 'float': case 'double': return (float) $value; case 'string': return (string) $value; default: return $value; } } } database/Eloquent/Relations/Concerns/SupportsDefaultModels.php 0000644 00000003021 14736103231 0020633 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Relations\Concerns; use Illuminate\Database\Eloquent\Model; trait SupportsDefaultModels { /** * Indicates if a default model instance should be used. * * Alternatively, may be a Closure or array. * * @var \Closure|array|bool */ protected $withDefault; /** * Make a new related instance for the given model. * * @param \Illuminate\Database\Eloquent\Model $parent * @return \Illuminate\Database\Eloquent\Model */ abstract protected function newRelatedInstanceFor(Model $parent); /** * Return a new model instance in case the relationship does not exist. * * @param \Closure|array|bool $callback * @return $this */ public function withDefault($callback = true) { $this->withDefault = $callback; return $this; } /** * Get the default value for this relation. * * @param \Illuminate\Database\Eloquent\Model $parent * @return \Illuminate\Database\Eloquent\Model|null */ protected function getDefaultFor(Model $parent) { if (! $this->withDefault) { return; } $instance = $this->newRelatedInstanceFor($parent); if (is_callable($this->withDefault)) { return call_user_func($this->withDefault, $instance, $parent) ?: $instance; } if (is_array($this->withDefault)) { $instance->forceFill($this->withDefault); } return $instance; } } database/Eloquent/Relations/Concerns/AsPivot.php 0000644 00000020163 14736103231 0015716 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Relations\Concerns; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Str; trait AsPivot { /** * The parent model of the relationship. * * @var \Illuminate\Database\Eloquent\Model */ public $pivotParent; /** * The name of the foreign key column. * * @var string */ protected $foreignKey; /** * The name of the "other key" column. * * @var string */ protected $relatedKey; /** * Create a new pivot model instance. * * @param \Illuminate\Database\Eloquent\Model $parent * @param array $attributes * @param string $table * @param bool $exists * @return static */ public static function fromAttributes(Model $parent, $attributes, $table, $exists = false) { $instance = new static; $instance->timestamps = $instance->hasTimestampAttributes($attributes); // The pivot model is a "dynamic" model since we will set the tables dynamically // for the instance. This allows it work for any intermediate tables for the // many to many relationship that are defined by this developer's classes. $instance->setConnection($parent->getConnectionName()) ->setTable($table) ->forceFill($attributes) ->syncOriginal(); // We store off the parent instance so we will access the timestamp column names // for the model, since the pivot model timestamps aren't easily configurable // from the developer's point of view. We can use the parents to get these. $instance->pivotParent = $parent; $instance->exists = $exists; return $instance; } /** * Create a new pivot model from raw values returned from a query. * * @param \Illuminate\Database\Eloquent\Model $parent * @param array $attributes * @param string $table * @param bool $exists * @return static */ public static function fromRawAttributes(Model $parent, $attributes, $table, $exists = false) { $instance = static::fromAttributes($parent, [], $table, $exists); $instance->timestamps = $instance->hasTimestampAttributes($attributes); $instance->setRawAttributes($attributes, $exists); return $instance; } /** * Set the keys for a save update query. * * @param \Illuminate\Database\Eloquent\Builder $query * @return \Illuminate\Database\Eloquent\Builder */ protected function setKeysForSaveQuery(Builder $query) { if (isset($this->attributes[$this->getKeyName()])) { return parent::setKeysForSaveQuery($query); } $query->where($this->foreignKey, $this->getOriginal( $this->foreignKey, $this->getAttribute($this->foreignKey) )); return $query->where($this->relatedKey, $this->getOriginal( $this->relatedKey, $this->getAttribute($this->relatedKey) )); } /** * Delete the pivot model record from the database. * * @return int */ public function delete() { if (isset($this->attributes[$this->getKeyName()])) { return (int) parent::delete(); } if ($this->fireModelEvent('deleting') === false) { return 0; } $this->touchOwners(); return tap($this->getDeleteQuery()->delete(), function () { $this->fireModelEvent('deleted', false); }); } /** * Get the query builder for a delete operation on the pivot. * * @return \Illuminate\Database\Eloquent\Builder */ protected function getDeleteQuery() { return $this->newQueryWithoutRelationships()->where([ $this->foreignKey => $this->getOriginal($this->foreignKey, $this->getAttribute($this->foreignKey)), $this->relatedKey => $this->getOriginal($this->relatedKey, $this->getAttribute($this->relatedKey)), ]); } /** * Get the table associated with the model. * * @return string */ public function getTable() { if (! isset($this->table)) { $this->setTable(str_replace( '\\', '', Str::snake(Str::singular(class_basename($this))) )); } return $this->table; } /** * Get the foreign key column name. * * @return string */ public function getForeignKey() { return $this->foreignKey; } /** * Get the "related key" column name. * * @return string */ public function getRelatedKey() { return $this->relatedKey; } /** * Get the "related key" column name. * * @return string */ public function getOtherKey() { return $this->getRelatedKey(); } /** * Set the key names for the pivot model instance. * * @param string $foreignKey * @param string $relatedKey * @return $this */ public function setPivotKeys($foreignKey, $relatedKey) { $this->foreignKey = $foreignKey; $this->relatedKey = $relatedKey; return $this; } /** * Determine if the pivot model or given attributes has timestamp attributes. * * @param array|null $attributes * @return bool */ public function hasTimestampAttributes($attributes = null) { return array_key_exists($this->getCreatedAtColumn(), $attributes ?? $this->attributes); } /** * Get the name of the "created at" column. * * @return string */ public function getCreatedAtColumn() { return $this->pivotParent ? $this->pivotParent->getCreatedAtColumn() : parent::getCreatedAtColumn(); } /** * Get the name of the "updated at" column. * * @return string */ public function getUpdatedAtColumn() { return $this->pivotParent ? $this->pivotParent->getUpdatedAtColumn() : parent::getUpdatedAtColumn(); } /** * Get the queueable identity for the entity. * * @return mixed */ public function getQueueableId() { if (isset($this->attributes[$this->getKeyName()])) { return $this->getKey(); } return sprintf( '%s:%s:%s:%s', $this->foreignKey, $this->getAttribute($this->foreignKey), $this->relatedKey, $this->getAttribute($this->relatedKey) ); } /** * Get a new query to restore one or more models by their queueable IDs. * * @param int[]|string[]|string $ids * @return \Illuminate\Database\Eloquent\Builder */ public function newQueryForRestoration($ids) { if (is_array($ids)) { return $this->newQueryForCollectionRestoration($ids); } if (! Str::contains($ids, ':')) { return parent::newQueryForRestoration($ids); } $segments = explode(':', $ids); return $this->newQueryWithoutScopes() ->where($segments[0], $segments[1]) ->where($segments[2], $segments[3]); } /** * Get a new query to restore multiple models by their queueable IDs. * * @param int[]|string[] $ids * @return \Illuminate\Database\Eloquent\Builder */ protected function newQueryForCollectionRestoration(array $ids) { if (! Str::contains($ids[0], ':')) { return parent::newQueryForRestoration($ids); } $query = $this->newQueryWithoutScopes(); foreach ($ids as $id) { $segments = explode(':', $id); $query->orWhere(function ($query) use ($segments) { return $query->where($segments[0], $segments[1]) ->where($segments[2], $segments[3]); }); } return $query; } /** * Unset all the loaded relations for the instance. * * @return $this */ public function unsetRelations() { $this->pivotParent = null; $this->relations = []; return $this; } } database/Eloquent/Relations/HasOne.php 0000644 00000003346 14736103231 0013740 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Relations; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\Concerns\SupportsDefaultModels; class HasOne extends HasOneOrMany { use SupportsDefaultModels; /** * Get the results of the relationship. * * @return mixed */ public function getResults() { if (is_null($this->getParentKey())) { return $this->getDefaultFor($this->parent); } return $this->query->first() ?: $this->getDefaultFor($this->parent); } /** * Initialize the relation on a set of models. * * @param array $models * @param string $relation * @return array */ public function initRelation(array $models, $relation) { foreach ($models as $model) { $model->setRelation($relation, $this->getDefaultFor($model)); } return $models; } /** * Match the eagerly loaded results to their parents. * * @param array $models * @param \Illuminate\Database\Eloquent\Collection $results * @param string $relation * @return array */ public function match(array $models, Collection $results, $relation) { return $this->matchOne($models, $results, $relation); } /** * Make a new related instance for the given model. * * @param \Illuminate\Database\Eloquent\Model $parent * @return \Illuminate\Database\Eloquent\Model */ public function newRelatedInstanceFor(Model $parent) { return $this->related->newInstance()->setAttribute( $this->getForeignKeyName(), $parent->{$this->localKey} ); } } database/Eloquent/Relations/HasManyThrough.php 0000644 00000046214 14736103231 0015465 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Relations; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\SoftDeletes; class HasManyThrough extends Relation { /** * The "through" parent model instance. * * @var \Illuminate\Database\Eloquent\Model */ protected $throughParent; /** * The far parent model instance. * * @var \Illuminate\Database\Eloquent\Model */ protected $farParent; /** * The near key on the relationship. * * @var string */ protected $firstKey; /** * The far key on the relationship. * * @var string */ protected $secondKey; /** * The local key on the relationship. * * @var string */ protected $localKey; /** * The local key on the intermediary model. * * @var string */ protected $secondLocalKey; /** * The count of self joins. * * @var int */ protected static $selfJoinCount = 0; /** * Create a new has many through relationship instance. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Model $farParent * @param \Illuminate\Database\Eloquent\Model $throughParent * @param string $firstKey * @param string $secondKey * @param string $localKey * @param string $secondLocalKey * @return void */ public function __construct(Builder $query, Model $farParent, Model $throughParent, $firstKey, $secondKey, $localKey, $secondLocalKey) { $this->localKey = $localKey; $this->firstKey = $firstKey; $this->secondKey = $secondKey; $this->farParent = $farParent; $this->throughParent = $throughParent; $this->secondLocalKey = $secondLocalKey; parent::__construct($query, $throughParent); } /** * Set the base constraints on the relation query. * * @return void */ public function addConstraints() { $localValue = $this->farParent[$this->localKey]; $this->performJoin(); if (static::$constraints) { $this->query->where($this->getQualifiedFirstKeyName(), '=', $localValue); } } /** * Set the join clause on the query. * * @param \Illuminate\Database\Eloquent\Builder|null $query * @return void */ protected function performJoin(Builder $query = null) { $query = $query ?: $this->query; $farKey = $this->getQualifiedFarKeyName(); $query->join($this->throughParent->getTable(), $this->getQualifiedParentKeyName(), '=', $farKey); if ($this->throughParentSoftDeletes()) { $query->withGlobalScope('SoftDeletableHasManyThrough', function ($query) { $query->whereNull($this->throughParent->getQualifiedDeletedAtColumn()); }); } } /** * Get the fully qualified parent key name. * * @return string */ public function getQualifiedParentKeyName() { return $this->parent->qualifyColumn($this->secondLocalKey); } /** * Determine whether "through" parent of the relation uses Soft Deletes. * * @return bool */ public function throughParentSoftDeletes() { return in_array(SoftDeletes::class, class_uses_recursive($this->throughParent)); } /** * Indicate that trashed "through" parents should be included in the query. * * @return $this */ public function withTrashedParents() { $this->query->withoutGlobalScope('SoftDeletableHasManyThrough'); return $this; } /** * Set the constraints for an eager load of the relation. * * @param array $models * @return void */ public function addEagerConstraints(array $models) { $whereIn = $this->whereInMethod($this->farParent, $this->localKey); $this->query->{$whereIn}( $this->getQualifiedFirstKeyName(), $this->getKeys($models, $this->localKey) ); } /** * Initialize the relation on a set of models. * * @param array $models * @param string $relation * @return array */ public function initRelation(array $models, $relation) { foreach ($models as $model) { $model->setRelation($relation, $this->related->newCollection()); } return $models; } /** * Match the eagerly loaded results to their parents. * * @param array $models * @param \Illuminate\Database\Eloquent\Collection $results * @param string $relation * @return array */ public function match(array $models, Collection $results, $relation) { $dictionary = $this->buildDictionary($results); // Once we have the dictionary we can simply spin through the parent models to // link them up with their children using the keyed dictionary to make the // matching very convenient and easy work. Then we'll just return them. foreach ($models as $model) { if (isset($dictionary[$key = $model->getAttribute($this->localKey)])) { $model->setRelation( $relation, $this->related->newCollection($dictionary[$key]) ); } } return $models; } /** * Build model dictionary keyed by the relation's foreign key. * * @param \Illuminate\Database\Eloquent\Collection $results * @return array */ protected function buildDictionary(Collection $results) { $dictionary = []; // First we will create a dictionary of models keyed by the foreign key of the // relationship as this will allow us to quickly access all of the related // models without having to do nested looping which will be quite slow. foreach ($results as $result) { $dictionary[$result->laravel_through_key][] = $result; } return $dictionary; } /** * Get the first related model record matching the attributes or instantiate it. * * @param array $attributes * @return \Illuminate\Database\Eloquent\Model */ public function firstOrNew(array $attributes) { if (is_null($instance = $this->where($attributes)->first())) { $instance = $this->related->newInstance($attributes); } return $instance; } /** * Create or update a related record matching the attributes, and fill it with values. * * @param array $attributes * @param array $values * @return \Illuminate\Database\Eloquent\Model */ public function updateOrCreate(array $attributes, array $values = []) { $instance = $this->firstOrNew($attributes); $instance->fill($values)->save(); return $instance; } /** * Add a basic where clause to the query, and return the first result. * * @param \Closure|string|array $column * @param mixed $operator * @param mixed $value * @param string $boolean * @return \Illuminate\Database\Eloquent\Model|static */ public function firstWhere($column, $operator = null, $value = null, $boolean = 'and') { return $this->where($column, $operator, $value, $boolean)->first(); } /** * Execute the query and get the first related model. * * @param array $columns * @return mixed */ public function first($columns = ['*']) { $results = $this->take(1)->get($columns); return count($results) > 0 ? $results->first() : null; } /** * Execute the query and get the first result or throw an exception. * * @param array $columns * @return \Illuminate\Database\Eloquent\Model|static * * @throws \Illuminate\Database\Eloquent\ModelNotFoundException */ public function firstOrFail($columns = ['*']) { if (! is_null($model = $this->first($columns))) { return $model; } throw (new ModelNotFoundException)->setModel(get_class($this->related)); } /** * Find a related model by its primary key. * * @param mixed $id * @param array $columns * @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection|null */ public function find($id, $columns = ['*']) { if (is_array($id) || $id instanceof Arrayable) { return $this->findMany($id, $columns); } return $this->where( $this->getRelated()->getQualifiedKeyName(), '=', $id )->first($columns); } /** * Find multiple related models by their primary keys. * * @param \Illuminate\Contracts\Support\Arrayable|array $ids * @param array $columns * @return \Illuminate\Database\Eloquent\Collection */ public function findMany($ids, $columns = ['*']) { $ids = $ids instanceof Arrayable ? $ids->toArray() : $ids; if (empty($ids)) { return $this->getRelated()->newCollection(); } return $this->whereIn( $this->getRelated()->getQualifiedKeyName(), $ids )->get($columns); } /** * Find a related model by its primary key or throw an exception. * * @param mixed $id * @param array $columns * @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection * * @throws \Illuminate\Database\Eloquent\ModelNotFoundException */ public function findOrFail($id, $columns = ['*']) { $result = $this->find($id, $columns); $id = $id instanceof Arrayable ? $id->toArray() : $id; if (is_array($id)) { if (count($result) === count(array_unique($id))) { return $result; } } elseif (! is_null($result)) { return $result; } throw (new ModelNotFoundException)->setModel(get_class($this->related), $id); } /** * Get the results of the relationship. * * @return mixed */ public function getResults() { return ! is_null($this->farParent->{$this->localKey}) ? $this->get() : $this->related->newCollection(); } /** * Execute the query as a "select" statement. * * @param array $columns * @return \Illuminate\Database\Eloquent\Collection */ public function get($columns = ['*']) { $builder = $this->prepareQueryBuilder($columns); $models = $builder->getModels(); // If we actually found models we will also eager load any relationships that // have been specified as needing to be eager loaded. This will solve the // n + 1 query problem for the developer and also increase performance. if (count($models) > 0) { $models = $builder->eagerLoadRelations($models); } return $this->related->newCollection($models); } /** * Get a paginator for the "select" statement. * * @param int|null $perPage * @param array $columns * @param string $pageName * @param int $page * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator */ public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null) { $this->query->addSelect($this->shouldSelect($columns)); return $this->query->paginate($perPage, $columns, $pageName, $page); } /** * Paginate the given query into a simple paginator. * * @param int|null $perPage * @param array $columns * @param string $pageName * @param int|null $page * @return \Illuminate\Contracts\Pagination\Paginator */ public function simplePaginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null) { $this->query->addSelect($this->shouldSelect($columns)); return $this->query->simplePaginate($perPage, $columns, $pageName, $page); } /** * Set the select clause for the relation query. * * @param array $columns * @return array */ protected function shouldSelect(array $columns = ['*']) { if ($columns == ['*']) { $columns = [$this->related->getTable().'.*']; } return array_merge($columns, [$this->getQualifiedFirstKeyName().' as laravel_through_key']); } /** * Chunk the results of the query. * * @param int $count * @param callable $callback * @return bool */ public function chunk($count, callable $callback) { return $this->prepareQueryBuilder()->chunk($count, $callback); } /** * Chunk the results of a query by comparing numeric IDs. * * @param int $count * @param callable $callback * @param string|null $column * @param string|null $alias * @return bool */ public function chunkById($count, callable $callback, $column = null, $alias = null) { $column = $column ?? $this->getRelated()->getQualifiedKeyName(); $alias = $alias ?? $this->getRelated()->getKeyName(); return $this->prepareQueryBuilder()->chunkById($count, $callback, $column, $alias); } /** * Get a generator for the given query. * * @return \Generator */ public function cursor() { return $this->prepareQueryBuilder()->cursor(); } /** * Execute a callback over each item while chunking. * * @param callable $callback * @param int $count * @return bool */ public function each(callable $callback, $count = 1000) { return $this->chunk($count, function ($results) use ($callback) { foreach ($results as $key => $value) { if ($callback($value, $key) === false) { return false; } } }); } /** * Prepare the query builder for query execution. * * @param array $columns * @return \Illuminate\Database\Eloquent\Builder */ protected function prepareQueryBuilder($columns = ['*']) { $builder = $this->query->applyScopes(); return $builder->addSelect( $this->shouldSelect($builder->getQuery()->columns ? [] : $columns) ); } /** * Add the constraints for a relationship query. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Builder $parentQuery * @param array|mixed $columns * @return \Illuminate\Database\Eloquent\Builder */ public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*']) { if ($parentQuery->getQuery()->from === $query->getQuery()->from) { return $this->getRelationExistenceQueryForSelfRelation($query, $parentQuery, $columns); } if ($parentQuery->getQuery()->from === $this->throughParent->getTable()) { return $this->getRelationExistenceQueryForThroughSelfRelation($query, $parentQuery, $columns); } $this->performJoin($query); return $query->select($columns)->whereColumn( $this->getQualifiedLocalKeyName(), '=', $this->getQualifiedFirstKeyName() ); } /** * Add the constraints for a relationship query on the same table. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Builder $parentQuery * @param array|mixed $columns * @return \Illuminate\Database\Eloquent\Builder */ public function getRelationExistenceQueryForSelfRelation(Builder $query, Builder $parentQuery, $columns = ['*']) { $query->from($query->getModel()->getTable().' as '.$hash = $this->getRelationCountHash()); $query->join($this->throughParent->getTable(), $this->getQualifiedParentKeyName(), '=', $hash.'.'.$this->secondKey); if ($this->throughParentSoftDeletes()) { $query->whereNull($this->throughParent->getQualifiedDeletedAtColumn()); } $query->getModel()->setTable($hash); return $query->select($columns)->whereColumn( $parentQuery->getQuery()->from.'.'.$this->localKey, '=', $this->getQualifiedFirstKeyName() ); } /** * Add the constraints for a relationship query on the same table as the through parent. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Builder $parentQuery * @param array|mixed $columns * @return \Illuminate\Database\Eloquent\Builder */ public function getRelationExistenceQueryForThroughSelfRelation(Builder $query, Builder $parentQuery, $columns = ['*']) { $table = $this->throughParent->getTable().' as '.$hash = $this->getRelationCountHash(); $query->join($table, $hash.'.'.$this->secondLocalKey, '=', $this->getQualifiedFarKeyName()); if ($this->throughParentSoftDeletes()) { $query->whereNull($hash.'.'.$this->throughParent->getDeletedAtColumn()); } return $query->select($columns)->whereColumn( $parentQuery->getQuery()->from.'.'.$this->localKey, '=', $hash.'.'.$this->firstKey ); } /** * Get a relationship join table hash. * * @return string */ public function getRelationCountHash() { return 'laravel_reserved_'.static::$selfJoinCount++; } /** * Get the qualified foreign key on the related model. * * @return string */ public function getQualifiedFarKeyName() { return $this->getQualifiedForeignKeyName(); } /** * Get the foreign key on the "through" model. * * @return string */ public function getFirstKeyName() { return $this->firstKey; } /** * Get the qualified foreign key on the "through" model. * * @return string */ public function getQualifiedFirstKeyName() { return $this->throughParent->qualifyColumn($this->firstKey); } /** * Get the foreign key on the related model. * * @return string */ public function getForeignKeyName() { return $this->secondKey; } /** * Get the qualified foreign key on the related model. * * @return string */ public function getQualifiedForeignKeyName() { return $this->related->qualifyColumn($this->secondKey); } /** * Get the local key on the far parent model. * * @return string */ public function getLocalKeyName() { return $this->localKey; } /** * Get the qualified local key on the far parent model. * * @return string */ public function getQualifiedLocalKeyName() { return $this->farParent->qualifyColumn($this->localKey); } /** * Get the local key on the intermediary model. * * @return string */ public function getSecondLocalKeyName() { return $this->secondLocalKey; } } database/Eloquent/Relations/MorphOne.php 0000644 00000003466 14736103231 0014315 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Relations; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\Concerns\SupportsDefaultModels; class MorphOne extends MorphOneOrMany { use SupportsDefaultModels; /** * Get the results of the relationship. * * @return mixed */ public function getResults() { if (is_null($this->getParentKey())) { return $this->getDefaultFor($this->parent); } return $this->query->first() ?: $this->getDefaultFor($this->parent); } /** * Initialize the relation on a set of models. * * @param array $models * @param string $relation * @return array */ public function initRelation(array $models, $relation) { foreach ($models as $model) { $model->setRelation($relation, $this->getDefaultFor($model)); } return $models; } /** * Match the eagerly loaded results to their parents. * * @param array $models * @param \Illuminate\Database\Eloquent\Collection $results * @param string $relation * @return array */ public function match(array $models, Collection $results, $relation) { return $this->matchOne($models, $results, $relation); } /** * Make a new related instance for the given model. * * @param \Illuminate\Database\Eloquent\Model $parent * @return \Illuminate\Database\Eloquent\Model */ public function newRelatedInstanceFor(Model $parent) { return $this->related->newInstance() ->setAttribute($this->getForeignKeyName(), $parent->{$this->localKey}) ->setAttribute($this->getMorphType(), $this->morphClass); } } database/Eloquent/Relations/MorphPivot.php 0000644 00000007736 14736103231 0014701 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Relations; use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Str; class MorphPivot extends Pivot { /** * The type of the polymorphic relation. * * Explicitly define this so it's not included in saved attributes. * * @var string */ protected $morphType; /** * The value of the polymorphic relation. * * Explicitly define this so it's not included in saved attributes. * * @var string */ protected $morphClass; /** * Set the keys for a save update query. * * @param \Illuminate\Database\Eloquent\Builder $query * @return \Illuminate\Database\Eloquent\Builder */ protected function setKeysForSaveQuery(Builder $query) { $query->where($this->morphType, $this->morphClass); return parent::setKeysForSaveQuery($query); } /** * Delete the pivot model record from the database. * * @return int */ public function delete() { if (isset($this->attributes[$this->getKeyName()])) { return (int) parent::delete(); } if ($this->fireModelEvent('deleting') === false) { return 0; } $query = $this->getDeleteQuery(); $query->where($this->morphType, $this->morphClass); return tap($query->delete(), function () { $this->fireModelEvent('deleted', false); }); } /** * Set the morph type for the pivot. * * @param string $morphType * @return $this */ public function setMorphType($morphType) { $this->morphType = $morphType; return $this; } /** * Set the morph class for the pivot. * * @param string $morphClass * @return \Illuminate\Database\Eloquent\Relations\MorphPivot */ public function setMorphClass($morphClass) { $this->morphClass = $morphClass; return $this; } /** * Get the queueable identity for the entity. * * @return mixed */ public function getQueueableId() { if (isset($this->attributes[$this->getKeyName()])) { return $this->getKey(); } return sprintf( '%s:%s:%s:%s:%s:%s', $this->foreignKey, $this->getAttribute($this->foreignKey), $this->relatedKey, $this->getAttribute($this->relatedKey), $this->morphType, $this->morphClass ); } /** * Get a new query to restore one or more models by their queueable IDs. * * @param array|int $ids * @return \Illuminate\Database\Eloquent\Builder */ public function newQueryForRestoration($ids) { if (is_array($ids)) { return $this->newQueryForCollectionRestoration($ids); } if (! Str::contains($ids, ':')) { return parent::newQueryForRestoration($ids); } $segments = explode(':', $ids); return $this->newQueryWithoutScopes() ->where($segments[0], $segments[1]) ->where($segments[2], $segments[3]) ->where($segments[4], $segments[5]); } /** * Get a new query to restore multiple models by their queueable IDs. * * @param array $ids * @return \Illuminate\Database\Eloquent\Builder */ protected function newQueryForCollectionRestoration(array $ids) { if (! Str::contains($ids[0], ':')) { return parent::newQueryForRestoration($ids); } $query = $this->newQueryWithoutScopes(); foreach ($ids as $id) { $segments = explode(':', $id); $query->orWhere(function ($query) use ($segments) { return $query->where($segments[0], $segments[1]) ->where($segments[2], $segments[3]) ->where($segments[4], $segments[5]); }); } return $query; } } database/Eloquent/Relations/HasOneThrough.php 0000644 00000004117 14736103231 0015276 0 ustar 00 <?php namespace Illuminate\Database\Eloquent\Relations; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\Concerns\SupportsDefaultModels; class HasOneThrough extends HasManyThrough { use SupportsDefaultModels; /** * Get the results of the relationship. * * @return mixed */ public function getResults() { return $this->first() ?: $this->getDefaultFor($this->farParent); } /** * Initialize the relation on a set of models. * * @param array $models * @param string $relation * @return array */ public function initRelation(array $models, $relation) { foreach ($models as $model) { $model->setRelation($relation, $this->getDefaultFor($model)); } return $models; } /** * Match the eagerly loaded results to their parents. * * @param array $models * @param \Illuminate\Database\Eloquent\Collection $results * @param string $relation * @return array */ public function match(array $models, Collection $results, $relation) { $dictionary = $this->buildDictionary($results); // Once we have the dictionary we can simply spin through the parent models to // link them up with their children using the keyed dictionary to make the // matching very convenient and easy work. Then we'll just return them. foreach ($models as $model) { if (isset($dictionary[$key = $model->getAttribute($this->localKey)])) { $value = $dictionary[$key]; $model->setRelation( $relation, reset($value) ); } } return $models; } /** * Make a new related instance for the given model. * * @param \Illuminate\Database\Eloquent\Model $parent * @return \Illuminate\Database\Eloquent\Model */ public function newRelatedInstanceFor(Model $parent) { return $this->related->newInstance(); } } database/Eloquent/Builder.php 0000644 00000120453 14736103231 0012210 0 ustar 00 <?php namespace Illuminate\Database\Eloquent; use BadMethodCallException; use Closure; use Exception; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Database\Concerns\BuildsQueries; use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Database\Query\Builder as QueryBuilder; use Illuminate\Pagination\Paginator; use Illuminate\Support\Arr; use Illuminate\Support\Str; use Illuminate\Support\Traits\ForwardsCalls; use ReflectionClass; use ReflectionMethod; /** * @property-read HigherOrderBuilderProxy $orWhere * * @mixin \Illuminate\Database\Query\Builder */ class Builder { use BuildsQueries, Concerns\QueriesRelationships, ForwardsCalls; /** * The base query builder instance. * * @var \Illuminate\Database\Query\Builder */ protected $query; /** * The model being queried. * * @var \Illuminate\Database\Eloquent\Model */ protected $model; /** * The relationships that should be eager loaded. * * @var array */ protected $eagerLoad = []; /** * All of the globally registered builder macros. * * @var array */ protected static $macros = []; /** * All of the locally registered builder macros. * * @var array */ protected $localMacros = []; /** * A replacement for the typical delete function. * * @var \Closure */ protected $onDelete; /** * The methods that should be returned from query builder. * * @var array */ protected $passthru = [ 'insert', 'insertOrIgnore', 'insertGetId', 'insertUsing', 'getBindings', 'toSql', 'dump', 'dd', 'exists', 'doesntExist', 'count', 'min', 'max', 'avg', 'average', 'sum', 'getConnection', 'raw', 'getGrammar', ]; /** * Applied global scopes. * * @var array */ protected $scopes = []; /** * Removed global scopes. * * @var array */ protected $removedScopes = []; /** * Create a new Eloquent query builder instance. * * @param \Illuminate\Database\Query\Builder $query * @return void */ public function __construct(QueryBuilder $query) { $this->query = $query; } /** * Create and return an un-saved model instance. * * @param array $attributes * @return \Illuminate\Database\Eloquent\Model|static */ public function make(array $attributes = []) { return $this->newModelInstance($attributes); } /** * Register a new global scope. * * @param string $identifier * @param \Illuminate\Database\Eloquent\Scope|\Closure $scope * @return $this */ public function withGlobalScope($identifier, $scope) { $this->scopes[$identifier] = $scope; if (method_exists($scope, 'extend')) { $scope->extend($this); } return $this; } /** * Remove a registered global scope. * * @param \Illuminate\Database\Eloquent\Scope|string $scope * @return $this */ public function withoutGlobalScope($scope) { if (! is_string($scope)) { $scope = get_class($scope); } unset($this->scopes[$scope]); $this->removedScopes[] = $scope; return $this; } /** * Remove all or passed registered global scopes. * * @param array|null $scopes * @return $this */ public function withoutGlobalScopes(array $scopes = null) { if (! is_array($scopes)) { $scopes = array_keys($this->scopes); } foreach ($scopes as $scope) { $this->withoutGlobalScope($scope); } return $this; } /** * Get an array of global scopes that were removed from the query. * * @return array */ public function removedScopes() { return $this->removedScopes; } /** * Add a where clause on the primary key to the query. * * @param mixed $id * @return $this */ public function whereKey($id) { if (is_array($id) || $id instanceof Arrayable) { $this->query->whereIn($this->model->getQualifiedKeyName(), $id); return $this; } return $this->where($this->model->getQualifiedKeyName(), '=', $id); } /** * Add a where clause on the primary key to the query. * * @param mixed $id * @return $this */ public function whereKeyNot($id) { if (is_array($id) || $id instanceof Arrayable) { $this->query->whereNotIn($this->model->getQualifiedKeyName(), $id); return $this; } return $this->where($this->model->getQualifiedKeyName(), '!=', $id); } /** * Add a basic where clause to the query. * * @param \Closure|string|array $column * @param mixed $operator * @param mixed $value * @param string $boolean * @return $this */ public function where($column, $operator = null, $value = null, $boolean = 'and') { if ($column instanceof Closure && is_null($operator)) { $column($query = $this->model->newQueryWithoutRelationships()); $this->query->addNestedWhereQuery($query->getQuery(), $boolean); } else { $this->query->where(...func_get_args()); } return $this; } /** * Add a basic where clause to the query, and return the first result. * * @param \Closure|string|array $column * @param mixed $operator * @param mixed $value * @param string $boolean * @return \Illuminate\Database\Eloquent\Model|static */ public function firstWhere($column, $operator = null, $value = null, $boolean = 'and') { return $this->where($column, $operator, $value, $boolean)->first(); } /** * Add an "or where" clause to the query. * * @param \Closure|array|string $column * @param mixed $operator * @param mixed $value * @return $this */ public function orWhere($column, $operator = null, $value = null) { [$value, $operator] = $this->query->prepareValueAndOperator( $value, $operator, func_num_args() === 2 ); return $this->where($column, $operator, $value, 'or'); } /** * Add an "order by" clause for a timestamp to the query. * * @param string $column * @return $this */ public function latest($column = null) { if (is_null($column)) { $column = $this->model->getCreatedAtColumn() ?? 'created_at'; } $this->query->latest($column); return $this; } /** * Add an "order by" clause for a timestamp to the query. * * @param string $column * @return $this */ public function oldest($column = null) { if (is_null($column)) { $column = $this->model->getCreatedAtColumn() ?? 'created_at'; } $this->query->oldest($column); return $this; } /** * Create a collection of models from plain arrays. * * @param array $items * @return \Illuminate\Database\Eloquent\Collection */ public function hydrate(array $items) { $instance = $this->newModelInstance(); return $instance->newCollection(array_map(function ($item) use ($instance) { return $instance->newFromBuilder($item); }, $items)); } /** * Create a collection of models from a raw query. * * @param string $query * @param array $bindings * @return \Illuminate\Database\Eloquent\Collection */ public function fromQuery($query, $bindings = []) { return $this->hydrate( $this->query->getConnection()->select($query, $bindings) ); } /** * Find a model by its primary key. * * @param mixed $id * @param array $columns * @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection|static[]|static|null */ public function find($id, $columns = ['*']) { if (is_array($id) || $id instanceof Arrayable) { return $this->findMany($id, $columns); } return $this->whereKey($id)->first($columns); } /** * Find multiple models by their primary keys. * * @param \Illuminate\Contracts\Support\Arrayable|array $ids * @param array $columns * @return \Illuminate\Database\Eloquent\Collection */ public function findMany($ids, $columns = ['*']) { $ids = $ids instanceof Arrayable ? $ids->toArray() : $ids; if (empty($ids)) { return $this->model->newCollection(); } return $this->whereKey($ids)->get($columns); } /** * Find a model by its primary key or throw an exception. * * @param mixed $id * @param array $columns * @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection|static|static[] * * @throws \Illuminate\Database\Eloquent\ModelNotFoundException */ public function findOrFail($id, $columns = ['*']) { $result = $this->find($id, $columns); $id = $id instanceof Arrayable ? $id->toArray() : $id; if (is_array($id)) { if (count($result) === count(array_unique($id))) { return $result; } } elseif (! is_null($result)) { return $result; } throw (new ModelNotFoundException)->setModel( get_class($this->model), $id ); } /** * Find a model by its primary key or return fresh model instance. * * @param mixed $id * @param array $columns * @return \Illuminate\Database\Eloquent\Model|static */ public function findOrNew($id, $columns = ['*']) { if (! is_null($model = $this->find($id, $columns))) { return $model; } return $this->newModelInstance(); } /** * Get the first record matching the attributes or instantiate it. * * @param array $attributes * @param array $values * @return \Illuminate\Database\Eloquent\Model|static */ public function firstOrNew(array $attributes = [], array $values = []) { if (! is_null($instance = $this->where($attributes)->first())) { return $instance; } return $this->newModelInstance($attributes + $values); } /** * Get the first record matching the attributes or create it. * * @param array $attributes * @param array $values * @return \Illuminate\Database\Eloquent\Model|static */ public function firstOrCreate(array $attributes, array $values = []) { if (! is_null($instance = $this->where($attributes)->first())) { return $instance; } return tap($this->newModelInstance($attributes + $values), function ($instance) { $instance->save(); }); } /** * Create or update a record matching the attributes, and fill it with values. * * @param array $attributes * @param array $values * @return \Illuminate\Database\Eloquent\Model|static */ public function updateOrCreate(array $attributes, array $values = []) { return tap($this->firstOrNew($attributes), function ($instance) use ($values) { $instance->fill($values)->save(); }); } /** * Execute the query and get the first result or throw an exception. * * @param array $columns * @return \Illuminate\Database\Eloquent\Model|static * * @throws \Illuminate\Database\Eloquent\ModelNotFoundException */ public function firstOrFail($columns = ['*']) { if (! is_null($model = $this->first($columns))) { return $model; } throw (new ModelNotFoundException)->setModel(get_class($this->model)); } /** * Execute the query and get the first result or call a callback. * * @param \Closure|array $columns * @param \Closure|null $callback * @return \Illuminate\Database\Eloquent\Model|static|mixed */ public function firstOr($columns = ['*'], Closure $callback = null) { if ($columns instanceof Closure) { $callback = $columns; $columns = ['*']; } if (! is_null($model = $this->first($columns))) { return $model; } return $callback(); } /** * Get a single column's value from the first result of a query. * * @param string $column * @return mixed */ public function value($column) { if ($result = $this->first([$column])) { return $result->{$column}; } } /** * Execute the query as a "select" statement. * * @param array|string $columns * @return \Illuminate\Database\Eloquent\Collection|static[] */ public function get($columns = ['*']) { $builder = $this->applyScopes(); // If we actually found models we will also eager load any relationships that // have been specified as needing to be eager loaded, which will solve the // n+1 query issue for the developers to avoid running a lot of queries. if (count($models = $builder->getModels($columns)) > 0) { $models = $builder->eagerLoadRelations($models); } return $builder->getModel()->newCollection($models); } /** * Get the hydrated models without eager loading. * * @param array|string $columns * @return \Illuminate\Database\Eloquent\Model[]|static[] */ public function getModels($columns = ['*']) { return $this->model->hydrate( $this->query->get($columns)->all() )->all(); } /** * Eager load the relationships for the models. * * @param array $models * @return array */ public function eagerLoadRelations(array $models) { foreach ($this->eagerLoad as $name => $constraints) { // For nested eager loads we'll skip loading them here and they will be set as an // eager load on the query to retrieve the relation so that they will be eager // loaded on that query, because that is where they get hydrated as models. if (strpos($name, '.') === false) { $models = $this->eagerLoadRelation($models, $name, $constraints); } } return $models; } /** * Eagerly load the relationship on a set of models. * * @param array $models * @param string $name * @param \Closure $constraints * @return array */ protected function eagerLoadRelation(array $models, $name, Closure $constraints) { // First we will "back up" the existing where conditions on the query so we can // add our eager constraints. Then we will merge the wheres that were on the // query back to it in order that any where conditions might be specified. $relation = $this->getRelation($name); $relation->addEagerConstraints($models); $constraints($relation); // Once we have the results, we just match those back up to their parent models // using the relationship instance. Then we just return the finished arrays // of models which have been eagerly hydrated and are readied for return. return $relation->match( $relation->initRelation($models, $name), $relation->getEager(), $name ); } /** * Get the relation instance for the given relation name. * * @param string $name * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function getRelation($name) { // We want to run a relationship query without any constrains so that we will // not have to remove these where clauses manually which gets really hacky // and error prone. We don't want constraints because we add eager ones. $relation = Relation::noConstraints(function () use ($name) { try { return $this->getModel()->newInstance()->$name(); } catch (BadMethodCallException $e) { throw RelationNotFoundException::make($this->getModel(), $name); } }); $nested = $this->relationsNestedUnder($name); // If there are nested relationships set on the query, we will put those onto // the query instances so that they can be handled after this relationship // is loaded. In this way they will all trickle down as they are loaded. if (count($nested) > 0) { $relation->getQuery()->with($nested); } return $relation; } /** * Get the deeply nested relations for a given top-level relation. * * @param string $relation * @return array */ protected function relationsNestedUnder($relation) { $nested = []; // We are basically looking for any relationships that are nested deeper than // the given top-level relationship. We will just check for any relations // that start with the given top relations and adds them to our arrays. foreach ($this->eagerLoad as $name => $constraints) { if ($this->isNestedUnder($relation, $name)) { $nested[substr($name, strlen($relation.'.'))] = $constraints; } } return $nested; } /** * Determine if the relationship is nested. * * @param string $relation * @param string $name * @return bool */ protected function isNestedUnder($relation, $name) { return Str::contains($name, '.') && Str::startsWith($name, $relation.'.'); } /** * Get a lazy collection for the given query. * * @return \Illuminate\Support\LazyCollection */ public function cursor() { return $this->applyScopes()->query->cursor()->map(function ($record) { return $this->newModelInstance()->newFromBuilder($record); }); } /** * Add a generic "order by" clause if the query doesn't already have one. * * @return void */ protected function enforceOrderBy() { if (empty($this->query->orders) && empty($this->query->unionOrders)) { $this->orderBy($this->model->getQualifiedKeyName(), 'asc'); } } /** * Get an array with the values of a given column. * * @param string $column * @param string|null $key * @return \Illuminate\Support\Collection */ public function pluck($column, $key = null) { $results = $this->toBase()->pluck($column, $key); // If the model has a mutator for the requested column, we will spin through // the results and mutate the values so that the mutated version of these // columns are returned as you would expect from these Eloquent models. if (! $this->model->hasGetMutator($column) && ! $this->model->hasCast($column) && ! in_array($column, $this->model->getDates())) { return $results; } return $results->map(function ($value) use ($column) { return $this->model->newFromBuilder([$column => $value])->{$column}; }); } /** * Paginate the given query. * * @param int|null $perPage * @param array $columns * @param string $pageName * @param int|null $page * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator * * @throws \InvalidArgumentException */ public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null) { $page = $page ?: Paginator::resolveCurrentPage($pageName); $perPage = $perPage ?: $this->model->getPerPage(); $results = ($total = $this->toBase()->getCountForPagination()) ? $this->forPage($page, $perPage)->get($columns) : $this->model->newCollection(); return $this->paginator($results, $total, $perPage, $page, [ 'path' => Paginator::resolveCurrentPath(), 'pageName' => $pageName, ]); } /** * Paginate the given query into a simple paginator. * * @param int|null $perPage * @param array $columns * @param string $pageName * @param int|null $page * @return \Illuminate\Contracts\Pagination\Paginator */ public function simplePaginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null) { $page = $page ?: Paginator::resolveCurrentPage($pageName); $perPage = $perPage ?: $this->model->getPerPage(); // Next we will set the limit and offset for this query so that when we get the // results we get the proper section of results. Then, we'll create the full // paginator instances for these results with the given page and per page. $this->skip(($page - 1) * $perPage)->take($perPage + 1); return $this->simplePaginator($this->get($columns), $perPage, $page, [ 'path' => Paginator::resolveCurrentPath(), 'pageName' => $pageName, ]); } /** * Save a new model and return the instance. * * @param array $attributes * @return \Illuminate\Database\Eloquent\Model|$this */ public function create(array $attributes = []) { return tap($this->newModelInstance($attributes), function ($instance) { $instance->save(); }); } /** * Save a new model and return the instance. Allow mass-assignment. * * @param array $attributes * @return \Illuminate\Database\Eloquent\Model|$this */ public function forceCreate(array $attributes) { return $this->model->unguarded(function () use ($attributes) { return $this->newModelInstance()->create($attributes); }); } /** * Update a record in the database. * * @param array $values * @return int */ public function update(array $values) { return $this->toBase()->update($this->addUpdatedAtColumn($values)); } /** * Increment a column's value by a given amount. * * @param string $column * @param float|int $amount * @param array $extra * @return int */ public function increment($column, $amount = 1, array $extra = []) { return $this->toBase()->increment( $column, $amount, $this->addUpdatedAtColumn($extra) ); } /** * Decrement a column's value by a given amount. * * @param string $column * @param float|int $amount * @param array $extra * @return int */ public function decrement($column, $amount = 1, array $extra = []) { return $this->toBase()->decrement( $column, $amount, $this->addUpdatedAtColumn($extra) ); } /** * Add the "updated at" column to an array of values. * * @param array $values * @return array */ protected function addUpdatedAtColumn(array $values) { if (! $this->model->usesTimestamps() || is_null($this->model->getUpdatedAtColumn())) { return $values; } $column = $this->model->getUpdatedAtColumn(); $values = array_merge( [$column => $this->model->freshTimestampString()], $values ); $segments = preg_split('/\s+as\s+/i', $this->query->from); $qualifiedColumn = end($segments).'.'.$column; $values[$qualifiedColumn] = $values[$column]; unset($values[$column]); return $values; } /** * Delete a record from the database. * * @return mixed */ public function delete() { if (isset($this->onDelete)) { return call_user_func($this->onDelete, $this); } return $this->toBase()->delete(); } /** * Run the default delete function on the builder. * * Since we do not apply scopes here, the row will actually be deleted. * * @return mixed */ public function forceDelete() { return $this->query->delete(); } /** * Register a replacement for the default delete function. * * @param \Closure $callback * @return void */ public function onDelete(Closure $callback) { $this->onDelete = $callback; } /** * Determine if the given model has a scope. * * @param string $scope * @return bool */ public function hasNamedScope($scope) { return $this->model && $this->model->hasNamedScope($scope); } /** * Call the given local model scopes. * * @param array|string $scopes * @return static|mixed */ public function scopes($scopes) { $builder = $this; foreach (Arr::wrap($scopes) as $scope => $parameters) { // If the scope key is an integer, then the scope was passed as the value and // the parameter list is empty, so we will format the scope name and these // parameters here. Then, we'll be ready to call the scope on the model. if (is_int($scope)) { [$scope, $parameters] = [$parameters, []]; } // Next we'll pass the scope callback to the callScope method which will take // care of grouping the "wheres" properly so the logical order doesn't get // messed up when adding scopes. Then we'll return back out the builder. $builder = $builder->callNamedScope($scope, (array) $parameters); } return $builder; } /** * Apply the scopes to the Eloquent builder instance and return it. * * @return static */ public function applyScopes() { if (! $this->scopes) { return $this; } $builder = clone $this; foreach ($this->scopes as $identifier => $scope) { if (! isset($builder->scopes[$identifier])) { continue; } $builder->callScope(function (self $builder) use ($scope) { // If the scope is a Closure we will just go ahead and call the scope with the // builder instance. The "callScope" method will properly group the clauses // that are added to this query so "where" clauses maintain proper logic. if ($scope instanceof Closure) { $scope($builder); } // If the scope is a scope object, we will call the apply method on this scope // passing in the builder and the model instance. After we run all of these // scopes we will return back the builder instance to the outside caller. if ($scope instanceof Scope) { $scope->apply($builder, $this->getModel()); } }); } return $builder; } /** * Apply the given scope on the current builder instance. * * @param callable $scope * @param array $parameters * @return mixed */ protected function callScope(callable $scope, array $parameters = []) { array_unshift($parameters, $this); $query = $this->getQuery(); // We will keep track of how many wheres are on the query before running the // scope so that we can properly group the added scope constraints in the // query as their own isolated nested where statement and avoid issues. $originalWhereCount = is_null($query->wheres) ? 0 : count($query->wheres); $result = $scope(...array_values($parameters)) ?? $this; if (count((array) $query->wheres) > $originalWhereCount) { $this->addNewWheresWithinGroup($query, $originalWhereCount); } return $result; } /** * Apply the given named scope on the current builder instance. * * @param string $scope * @param array $parameters * @return mixed */ protected function callNamedScope($scope, array $parameters = []) { return $this->callScope(function (...$parameters) use ($scope) { return $this->model->callNamedScope($scope, $parameters); }, $parameters); } /** * Nest where conditions by slicing them at the given where count. * * @param \Illuminate\Database\Query\Builder $query * @param int $originalWhereCount * @return void */ protected function addNewWheresWithinGroup(QueryBuilder $query, $originalWhereCount) { // Here, we totally remove all of the where clauses since we are going to // rebuild them as nested queries by slicing the groups of wheres into // their own sections. This is to prevent any confusing logic order. $allWheres = $query->wheres; $query->wheres = []; $this->groupWhereSliceForScope( $query, array_slice($allWheres, 0, $originalWhereCount) ); $this->groupWhereSliceForScope( $query, array_slice($allWheres, $originalWhereCount) ); } /** * Slice where conditions at the given offset and add them to the query as a nested condition. * * @param \Illuminate\Database\Query\Builder $query * @param array $whereSlice * @return void */ protected function groupWhereSliceForScope(QueryBuilder $query, $whereSlice) { $whereBooleans = collect($whereSlice)->pluck('boolean'); // Here we'll check if the given subset of where clauses contains any "or" // booleans and in this case create a nested where expression. That way // we don't add any unnecessary nesting thus keeping the query clean. if ($whereBooleans->contains('or')) { $query->wheres[] = $this->createNestedWhere( $whereSlice, $whereBooleans->first() ); } else { $query->wheres = array_merge($query->wheres, $whereSlice); } } /** * Create a where array with nested where conditions. * * @param array $whereSlice * @param string $boolean * @return array */ protected function createNestedWhere($whereSlice, $boolean = 'and') { $whereGroup = $this->getQuery()->forNestedWhere(); $whereGroup->wheres = $whereSlice; return ['type' => 'Nested', 'query' => $whereGroup, 'boolean' => $boolean]; } /** * Set the relationships that should be eager loaded. * * @param mixed $relations * @return $this */ public function with($relations) { $eagerLoad = $this->parseWithRelations(is_string($relations) ? func_get_args() : $relations); $this->eagerLoad = array_merge($this->eagerLoad, $eagerLoad); return $this; } /** * Prevent the specified relations from being eager loaded. * * @param mixed $relations * @return $this */ public function without($relations) { $this->eagerLoad = array_diff_key($this->eagerLoad, array_flip( is_string($relations) ? func_get_args() : $relations )); return $this; } /** * Create a new instance of the model being queried. * * @param array $attributes * @return \Illuminate\Database\Eloquent\Model|static */ public function newModelInstance($attributes = []) { return $this->model->newInstance($attributes)->setConnection( $this->query->getConnection()->getName() ); } /** * Parse a list of relations into individuals. * * @param array $relations * @return array */ protected function parseWithRelations(array $relations) { $results = []; foreach ($relations as $name => $constraints) { // If the "name" value is a numeric key, we can assume that no constraints // have been specified. We will just put an empty Closure there so that // we can treat these all the same while we are looping through them. if (is_numeric($name)) { $name = $constraints; [$name, $constraints] = Str::contains($name, ':') ? $this->createSelectWithConstraint($name) : [$name, static function () { // }]; } // We need to separate out any nested includes, which allows the developers // to load deep relationships using "dots" without stating each level of // the relationship with its own key in the array of eager-load names. $results = $this->addNestedWiths($name, $results); $results[$name] = $constraints; } return $results; } /** * Create a constraint to select the given columns for the relation. * * @param string $name * @return array */ protected function createSelectWithConstraint($name) { return [explode(':', $name)[0], static function ($query) use ($name) { $query->select(explode(',', explode(':', $name)[1])); }]; } /** * Parse the nested relationships in a relation. * * @param string $name * @param array $results * @return array */ protected function addNestedWiths($name, $results) { $progress = []; // If the relation has already been set on the result array, we will not set it // again, since that would override any constraints that were already placed // on the relationships. We will only set the ones that are not specified. foreach (explode('.', $name) as $segment) { $progress[] = $segment; if (! isset($results[$last = implode('.', $progress)])) { $results[$last] = static function () { // }; } } return $results; } /** * Apply query-time casts to the model instance. * * @param array $casts * @return $this */ public function withCasts($casts) { $this->model->mergeCasts($casts); return $this; } /** * Get the underlying query builder instance. * * @return \Illuminate\Database\Query\Builder */ public function getQuery() { return $this->query; } /** * Set the underlying query builder instance. * * @param \Illuminate\Database\Query\Builder $query * @return $this */ public function setQuery($query) { $this->query = $query; return $this; } /** * Get a base query builder instance. * * @return \Illuminate\Database\Query\Builder */ public function toBase() { return $this->applyScopes()->getQuery(); } /** * Get the relationships being eagerly loaded. * * @return array */ public function getEagerLoads() { return $this->eagerLoad; } /** * Set the relationships being eagerly loaded. * * @param array $eagerLoad * @return $this */ public function setEagerLoads(array $eagerLoad) { $this->eagerLoad = $eagerLoad; return $this; } /** * Get the default key name of the table. * * @return string */ protected function defaultKeyName() { return $this->getModel()->getKeyName(); } /** * Get the model instance being queried. * * @return \Illuminate\Database\Eloquent\Model|static */ public function getModel() { return $this->model; } /** * Set a model instance for the model being queried. * * @param \Illuminate\Database\Eloquent\Model $model * @return $this */ public function setModel(Model $model) { $this->model = $model; $this->query->from($model->getTable()); return $this; } /** * Qualify the given column name by the model's table. * * @param string $column * @return string */ public function qualifyColumn($column) { return $this->model->qualifyColumn($column); } /** * Get the given macro by name. * * @param string $name * @return \Closure */ public function getMacro($name) { return Arr::get($this->localMacros, $name); } /** * Checks if a macro is registered. * * @param string $name * @return bool */ public function hasMacro($name) { return isset($this->localMacros[$name]); } /** * Get the given global macro by name. * * @param string $name * @return \Closure */ public static function getGlobalMacro($name) { return Arr::get(static::$macros, $name); } /** * Checks if a global macro is registered. * * @param string $name * @return bool */ public static function hasGlobalMacro($name) { return isset(static::$macros[$name]); } /** * Dynamically access builder proxies. * * @param string $key * @return mixed * * @throws \Exception */ public function __get($key) { if ($key === 'orWhere') { return new HigherOrderBuilderProxy($this, $key); } throw new Exception("Property [{$key}] does not exist on the Eloquent builder instance."); } /** * Dynamically handle calls into the query instance. * * @param string $method * @param array $parameters * @return mixed */ public function __call($method, $parameters) { if ($method === 'macro') { $this->localMacros[$parameters[0]] = $parameters[1]; return; } if ($this->hasMacro($method)) { array_unshift($parameters, $this); return $this->localMacros[$method](...$parameters); } if (static::hasGlobalMacro($method)) { if (static::$macros[$method] instanceof Closure) { return call_user_func_array(static::$macros[$method]->bindTo($this, static::class), $parameters); } return call_user_func_array(static::$macros[$method], $parameters); } if ($this->hasNamedScope($method)) { return $this->callNamedScope($method, $parameters); } if (in_array($method, $this->passthru)) { return $this->toBase()->{$method}(...$parameters); } $this->forwardCallTo($this->query, $method, $parameters); return $this; } /** * Dynamically handle calls into the query instance. * * @param string $method * @param array $parameters * @return mixed * * @throws \BadMethodCallException */ public static function __callStatic($method, $parameters) { if ($method === 'macro') { static::$macros[$parameters[0]] = $parameters[1]; return; } if ($method === 'mixin') { return static::registerMixin($parameters[0], $parameters[1] ?? true); } if (! static::hasGlobalMacro($method)) { static::throwBadMethodCallException($method); } if (static::$macros[$method] instanceof Closure) { return call_user_func_array(Closure::bind(static::$macros[$method], null, static::class), $parameters); } return call_user_func_array(static::$macros[$method], $parameters); } /** * Register the given mixin with the builder. * * @param string $mixin * @param bool $replace * @return void */ protected static function registerMixin($mixin, $replace) { $methods = (new ReflectionClass($mixin))->getMethods( ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED ); foreach ($methods as $method) { if ($replace || ! static::hasGlobalMacro($method->name)) { $method->setAccessible(true); static::macro($method->name, $method->invoke($mixin)); } } } /** * Force a clone of the underlying query builder when cloning. * * @return void */ public function __clone() { $this->query = clone $this->query; } } database/ConnectionResolverInterface.php 0000644 00000001077 14736103231 0014470 0 ustar 00 <?php namespace Illuminate\Database; interface ConnectionResolverInterface { /** * Get a database connection instance. * * @param string|null $name * @return \Illuminate\Database\ConnectionInterface */ public function connection($name = null); /** * Get the default connection name. * * @return string */ public function getDefaultConnection(); /** * Set the default connection name. * * @param string $name * @return void */ public function setDefaultConnection($name); } database/DetectsConcurrencyErrors.php 0000644 00000002075 14736103231 0014030 0 ustar 00 <?php namespace Illuminate\Database; use Illuminate\Support\Str; use PDOException; use Throwable; trait DetectsConcurrencyErrors { /** * Determine if the given exception was caused by a concurrency error such as a deadlock or serialization failure. * * @param \Throwable $e * @return bool */ protected function causedByConcurrencyError(Throwable $e) { if ($e instanceof PDOException && $e->getCode() === '40001') { return true; } $message = $e->getMessage(); return Str::contains($message, [ 'Deadlock found when trying to get lock', 'deadlock detected', 'The database file is locked', 'database is locked', 'database table is locked', 'A table in the database is locked', 'has been chosen as the deadlock victim', 'Lock wait timeout exceeded; try restarting transaction', 'WSREP detected deadlock/conflict and aborted the transaction. Try restarting the transaction', ]); } } database/ConfigurationUrlParser.php 0000644 00000000300 14736103231 0013461 0 ustar 00 <?php namespace Illuminate\Database; use Illuminate\Support\ConfigurationUrlParser as BaseConfigurationUrlParser; class ConfigurationUrlParser extends BaseConfigurationUrlParser { // } database/ConnectionResolver.php 0000644 00000003571 14736103231 0012650 0 ustar 00 <?php namespace Illuminate\Database; class ConnectionResolver implements ConnectionResolverInterface { /** * All of the registered connections. * * @var array */ protected $connections = []; /** * The default connection name. * * @var string */ protected $default; /** * Create a new connection resolver instance. * * @param array $connections * @return void */ public function __construct(array $connections = []) { foreach ($connections as $name => $connection) { $this->addConnection($name, $connection); } } /** * Get a database connection instance. * * @param string|null $name * @return \Illuminate\Database\ConnectionInterface */ public function connection($name = null) { if (is_null($name)) { $name = $this->getDefaultConnection(); } return $this->connections[$name]; } /** * Add a connection to the resolver. * * @param string $name * @param \Illuminate\Database\ConnectionInterface $connection * @return void */ public function addConnection($name, ConnectionInterface $connection) { $this->connections[$name] = $connection; } /** * Check if a connection has been registered. * * @param string $name * @return bool */ public function hasConnection($name) { return isset($this->connections[$name]); } /** * Get the default connection name. * * @return string */ public function getDefaultConnection() { return $this->default; } /** * Set the default connection name. * * @param string $name * @return void */ public function setDefaultConnection($name) { $this->default = $name; } } database/Migrations/MigrationRepositoryInterface.php 0000644 00000002746 14736103231 0017020 0 ustar 00 <?php namespace Illuminate\Database\Migrations; interface MigrationRepositoryInterface { /** * Get the completed migrations. * * @return array */ public function getRan(); /** * Get list of migrations. * * @param int $steps * @return array */ public function getMigrations($steps); /** * Get the last migration batch. * * @return array */ public function getLast(); /** * Get the completed migrations with their batch numbers. * * @return array */ public function getMigrationBatches(); /** * Log that a migration was run. * * @param string $file * @param int $batch * @return void */ public function log($file, $batch); /** * Remove a migration from the log. * * @param object $migration * @return void */ public function delete($migration); /** * Get the next migration batch number. * * @return int */ public function getNextBatchNumber(); /** * Create the migration repository data store. * * @return void */ public function createRepository(); /** * Determine if the migration repository exists. * * @return bool */ public function repositoryExists(); /** * Set the information source to gather data. * * @param string $name * @return void */ public function setSource($name); } database/Migrations/stubs/blank.stub 0000644 00000000572 14736103231 0013556 0 ustar 00 <?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class DummyClass extends Migration { /** * Run the migrations. * * @return void */ public function up() { // } /** * Reverse the migrations. * * @return void */ public function down() { // } } database/Migrations/stubs/migration.create.stub 0000644 00000001105 14736103231 0015713 0 ustar 00 <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class {{ class }} extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('{{ table }}', function (Blueprint $table) { $table->id(); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('{{ table }}'); } } database/Migrations/stubs/migration.stub 0000644 00000000642 14736103231 0014456 0 ustar 00 <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class {{ class }} extends Migration { /** * Run the migrations. * * @return void */ public function up() { // } /** * Reverse the migrations. * * @return void */ public function down() { // } } database/Migrations/stubs/update.stub 0000644 00000001036 14736103231 0013745 0 ustar 00 <?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class DummyClass extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::table('DummyTable', function (Blueprint $table) { // }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('DummyTable', function (Blueprint $table) { // }); } } database/Migrations/stubs/create.stub 0000644 00000001037 14736103231 0013727 0 ustar 00 <?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class DummyClass extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('DummyTable', function (Blueprint $table) { $table->increments('id'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('DummyTable'); } } database/Migrations/stubs/migration.update.stub 0000644 00000001110 14736103231 0015726 0 ustar 00 <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class {{ class }} extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::table('{{ table }}', function (Blueprint $table) { // }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('{{ table }}', function (Blueprint $table) { // }); } } database/Migrations/Migrator.php 0000644 00000045116 14736103231 0012730 0 ustar 00 <?php namespace Illuminate\Database\Migrations; use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Database\ConnectionResolverInterface as Resolver; use Illuminate\Database\Events\MigrationEnded; use Illuminate\Database\Events\MigrationsEnded; use Illuminate\Database\Events\MigrationsStarted; use Illuminate\Database\Events\MigrationStarted; use Illuminate\Database\Events\NoPendingMigrations; use Illuminate\Filesystem\Filesystem; use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\Str; use Symfony\Component\Console\Output\OutputInterface; class Migrator { /** * The event dispatcher instance. * * @var \Illuminate\Contracts\Events\Dispatcher */ protected $events; /** * The migration repository implementation. * * @var \Illuminate\Database\Migrations\MigrationRepositoryInterface */ protected $repository; /** * The filesystem instance. * * @var \Illuminate\Filesystem\Filesystem */ protected $files; /** * The connection resolver instance. * * @var \Illuminate\Database\ConnectionResolverInterface */ protected $resolver; /** * The name of the default connection. * * @var string */ protected $connection; /** * The paths to all of the migration files. * * @var array */ protected $paths = []; /** * The output interface implementation. * * @var \Symfony\Component\Console\Output\OutputInterface */ protected $output; /** * Create a new migrator instance. * * @param \Illuminate\Database\Migrations\MigrationRepositoryInterface $repository * @param \Illuminate\Database\ConnectionResolverInterface $resolver * @param \Illuminate\Filesystem\Filesystem $files * @param \Illuminate\Contracts\Events\Dispatcher|null $dispatcher * @return void */ public function __construct(MigrationRepositoryInterface $repository, Resolver $resolver, Filesystem $files, Dispatcher $dispatcher = null) { $this->files = $files; $this->events = $dispatcher; $this->resolver = $resolver; $this->repository = $repository; } /** * Run the pending migrations at a given path. * * @param array|string $paths * @param array $options * @return array */ public function run($paths = [], array $options = []) { // Once we grab all of the migration files for the path, we will compare them // against the migrations that have already been run for this package then // run each of the outstanding migrations against a database connection. $files = $this->getMigrationFiles($paths); $this->requireFiles($migrations = $this->pendingMigrations( $files, $this->repository->getRan() )); // Once we have all these migrations that are outstanding we are ready to run // we will go ahead and run them "up". This will execute each migration as // an operation against a database. Then we'll return this list of them. $this->runPending($migrations, $options); return $migrations; } /** * Get the migration files that have not yet run. * * @param array $files * @param array $ran * @return array */ protected function pendingMigrations($files, $ran) { return Collection::make($files) ->reject(function ($file) use ($ran) { return in_array($this->getMigrationName($file), $ran); })->values()->all(); } /** * Run an array of migrations. * * @param array $migrations * @param array $options * @return void */ public function runPending(array $migrations, array $options = []) { // First we will just make sure that there are any migrations to run. If there // aren't, we will just make a note of it to the developer so they're aware // that all of the migrations have been run against this database system. if (count($migrations) === 0) { $this->fireMigrationEvent(new NoPendingMigrations('up')); $this->note('<info>Nothing to migrate.</info>'); return; } // Next, we will get the next batch number for the migrations so we can insert // correct batch number in the database migrations repository when we store // each migration's execution. We will also extract a few of the options. $batch = $this->repository->getNextBatchNumber(); $pretend = $options['pretend'] ?? false; $step = $options['step'] ?? false; $this->fireMigrationEvent(new MigrationsStarted); // Once we have the array of migrations, we will spin through them and run the // migrations "up" so the changes are made to the databases. We'll then log // that the migration was run so we don't repeat it next time we execute. foreach ($migrations as $file) { $this->runUp($file, $batch, $pretend); if ($step) { $batch++; } } $this->fireMigrationEvent(new MigrationsEnded); } /** * Run "up" a migration instance. * * @param string $file * @param int $batch * @param bool $pretend * @return void */ protected function runUp($file, $batch, $pretend) { // First we will resolve a "real" instance of the migration class from this // migration file name. Once we have the instances we can run the actual // command such as "up" or "down", or we can just simulate the action. $migration = $this->resolve( $name = $this->getMigrationName($file) ); if ($pretend) { return $this->pretendToRun($migration, 'up'); } $this->note("<comment>Migrating:</comment> {$name}"); $startTime = microtime(true); $this->runMigration($migration, 'up'); $runTime = round(microtime(true) - $startTime, 2); // Once we have run a migrations class, we will log that it was run in this // repository so that we don't try to run it next time we do a migration // in the application. A migration repository keeps the migrate order. $this->repository->log($name, $batch); $this->note("<info>Migrated:</info> {$name} ({$runTime} seconds)"); } /** * Rollback the last migration operation. * * @param array|string $paths * @param array $options * @return array */ public function rollback($paths = [], array $options = []) { // We want to pull in the last batch of migrations that ran on the previous // migration operation. We'll then reverse those migrations and run each // of them "down" to reverse the last migration "operation" which ran. $migrations = $this->getMigrationsForRollback($options); if (count($migrations) === 0) { $this->fireMigrationEvent(new NoPendingMigrations('down')); $this->note('<info>Nothing to rollback.</info>'); return []; } return $this->rollbackMigrations($migrations, $paths, $options); } /** * Get the migrations for a rollback operation. * * @param array $options * @return array */ protected function getMigrationsForRollback(array $options) { if (($steps = $options['step'] ?? 0) > 0) { return $this->repository->getMigrations($steps); } return $this->repository->getLast(); } /** * Rollback the given migrations. * * @param array $migrations * @param array|string $paths * @param array $options * @return array */ protected function rollbackMigrations(array $migrations, $paths, array $options) { $rolledBack = []; $this->requireFiles($files = $this->getMigrationFiles($paths)); $this->fireMigrationEvent(new MigrationsStarted); // Next we will run through all of the migrations and call the "down" method // which will reverse each migration in order. This getLast method on the // repository already returns these migration's names in reverse order. foreach ($migrations as $migration) { $migration = (object) $migration; if (! $file = Arr::get($files, $migration->migration)) { $this->note("<fg=red>Migration not found:</> {$migration->migration}"); continue; } $rolledBack[] = $file; $this->runDown( $file, $migration, $options['pretend'] ?? false ); } $this->fireMigrationEvent(new MigrationsEnded); return $rolledBack; } /** * Rolls all of the currently applied migrations back. * * @param array|string $paths * @param bool $pretend * @return array */ public function reset($paths = [], $pretend = false) { // Next, we will reverse the migration list so we can run them back in the // correct order for resetting this database. This will allow us to get // the database back into its "empty" state ready for the migrations. $migrations = array_reverse($this->repository->getRan()); if (count($migrations) === 0) { $this->note('<info>Nothing to rollback.</info>'); return []; } return $this->resetMigrations($migrations, $paths, $pretend); } /** * Reset the given migrations. * * @param array $migrations * @param array $paths * @param bool $pretend * @return array */ protected function resetMigrations(array $migrations, array $paths, $pretend = false) { // Since the getRan method that retrieves the migration name just gives us the // migration name, we will format the names into objects with the name as a // property on the objects so that we can pass it to the rollback method. $migrations = collect($migrations)->map(function ($m) { return (object) ['migration' => $m]; })->all(); return $this->rollbackMigrations( $migrations, $paths, compact('pretend') ); } /** * Run "down" a migration instance. * * @param string $file * @param object $migration * @param bool $pretend * @return void */ protected function runDown($file, $migration, $pretend) { // First we will get the file name of the migration so we can resolve out an // instance of the migration. Once we get an instance we can either run a // pretend execution of the migration or we can run the real migration. $instance = $this->resolve( $name = $this->getMigrationName($file) ); $this->note("<comment>Rolling back:</comment> {$name}"); if ($pretend) { return $this->pretendToRun($instance, 'down'); } $startTime = microtime(true); $this->runMigration($instance, 'down'); $runTime = round(microtime(true) - $startTime, 2); // Once we have successfully run the migration "down" we will remove it from // the migration repository so it will be considered to have not been run // by the application then will be able to fire by any later operation. $this->repository->delete($migration); $this->note("<info>Rolled back:</info> {$name} ({$runTime} seconds)"); } /** * Run a migration inside a transaction if the database supports it. * * @param object $migration * @param string $method * @return void */ protected function runMigration($migration, $method) { $connection = $this->resolveConnection( $migration->getConnection() ); $callback = function () use ($migration, $method) { if (method_exists($migration, $method)) { $this->fireMigrationEvent(new MigrationStarted($migration, $method)); $migration->{$method}(); $this->fireMigrationEvent(new MigrationEnded($migration, $method)); } }; $this->getSchemaGrammar($connection)->supportsSchemaTransactions() && $migration->withinTransaction ? $connection->transaction($callback) : $callback(); } /** * Pretend to run the migrations. * * @param object $migration * @param string $method * @return void */ protected function pretendToRun($migration, $method) { foreach ($this->getQueries($migration, $method) as $query) { $name = get_class($migration); $this->note("<info>{$name}:</info> {$query['query']}"); } } /** * Get all of the queries that would be run for a migration. * * @param object $migration * @param string $method * @return array */ protected function getQueries($migration, $method) { // Now that we have the connections we can resolve it and pretend to run the // queries against the database returning the array of raw SQL statements // that would get fired against the database system for this migration. $db = $this->resolveConnection( $migration->getConnection() ); return $db->pretend(function () use ($migration, $method) { if (method_exists($migration, $method)) { $migration->{$method}(); } }); } /** * Resolve a migration instance from a file. * * @param string $file * @return object */ public function resolve($file) { $class = Str::studly(implode('_', array_slice(explode('_', $file), 4))); return new $class; } /** * Get all of the migration files in a given path. * * @param string|array $paths * @return array */ public function getMigrationFiles($paths) { return Collection::make($paths)->flatMap(function ($path) { return Str::endsWith($path, '.php') ? [$path] : $this->files->glob($path.'/*_*.php'); })->filter()->values()->keyBy(function ($file) { return $this->getMigrationName($file); })->sortBy(function ($file, $key) { return $key; })->all(); } /** * Require in all the migration files in a given path. * * @param array $files * @return void */ public function requireFiles(array $files) { foreach ($files as $file) { $this->files->requireOnce($file); } } /** * Get the name of the migration. * * @param string $path * @return string */ public function getMigrationName($path) { return str_replace('.php', '', basename($path)); } /** * Register a custom migration path. * * @param string $path * @return void */ public function path($path) { $this->paths = array_unique(array_merge($this->paths, [$path])); } /** * Get all of the custom migration paths. * * @return array */ public function paths() { return $this->paths; } /** * Get the default connection name. * * @return string */ public function getConnection() { return $this->connection; } /** * Execute the given callback using the given connection as the default connection. * * @param string $name * @param callable $callback * @return mixed */ public function usingConnection($name, callable $callback) { $previousConnection = $this->resolver->getDefaultConnection(); $this->setConnection($name); return tap($callback(), function () use ($previousConnection) { $this->setConnection($previousConnection); }); } /** * Set the default connection name. * * @param string $name * @return void */ public function setConnection($name) { if (! is_null($name)) { $this->resolver->setDefaultConnection($name); } $this->repository->setSource($name); $this->connection = $name; } /** * Resolve the database connection instance. * * @param string $connection * @return \Illuminate\Database\Connection */ public function resolveConnection($connection) { return $this->resolver->connection($connection ?: $this->connection); } /** * Get the schema grammar out of a migration connection. * * @param \Illuminate\Database\Connection $connection * @return \Illuminate\Database\Schema\Grammars\Grammar */ protected function getSchemaGrammar($connection) { if (is_null($grammar = $connection->getSchemaGrammar())) { $connection->useDefaultSchemaGrammar(); $grammar = $connection->getSchemaGrammar(); } return $grammar; } /** * Get the migration repository instance. * * @return \Illuminate\Database\Migrations\MigrationRepositoryInterface */ public function getRepository() { return $this->repository; } /** * Determine if the migration repository exists. * * @return bool */ public function repositoryExists() { return $this->repository->repositoryExists(); } /** * Get the file system instance. * * @return \Illuminate\Filesystem\Filesystem */ public function getFilesystem() { return $this->files; } /** * Set the output implementation that should be used by the console. * * @param \Symfony\Component\Console\Output\OutputInterface $output * @return $this */ public function setOutput(OutputInterface $output) { $this->output = $output; return $this; } /** * Write a note to the console's output. * * @param string $message * @return void */ protected function note($message) { if ($this->output) { $this->output->writeln($message); } } /** * Fire the given event for the migration. * * @param \Illuminate\Contracts\Database\Events\MigrationEvent $event * @return void */ public function fireMigrationEvent($event) { if ($this->events) { $this->events->dispatch($event); } } } database/Migrations/DatabaseMigrationRepository.php 0000644 00000011445 14736103231 0016620 0 ustar 00 <?php namespace Illuminate\Database\Migrations; use Illuminate\Database\ConnectionResolverInterface as Resolver; class DatabaseMigrationRepository implements MigrationRepositoryInterface { /** * The database connection resolver instance. * * @var \Illuminate\Database\ConnectionResolverInterface */ protected $resolver; /** * The name of the migration table. * * @var string */ protected $table; /** * The name of the database connection to use. * * @var string */ protected $connection; /** * Create a new database migration repository instance. * * @param \Illuminate\Database\ConnectionResolverInterface $resolver * @param string $table * @return void */ public function __construct(Resolver $resolver, $table) { $this->table = $table; $this->resolver = $resolver; } /** * Get the completed migrations. * * @return array */ public function getRan() { return $this->table() ->orderBy('batch', 'asc') ->orderBy('migration', 'asc') ->pluck('migration')->all(); } /** * Get list of migrations. * * @param int $steps * @return array */ public function getMigrations($steps) { $query = $this->table()->where('batch', '>=', '1'); return $query->orderBy('batch', 'desc') ->orderBy('migration', 'desc') ->take($steps)->get()->all(); } /** * Get the last migration batch. * * @return array */ public function getLast() { $query = $this->table()->where('batch', $this->getLastBatchNumber()); return $query->orderBy('migration', 'desc')->get()->all(); } /** * Get the completed migrations with their batch numbers. * * @return array */ public function getMigrationBatches() { return $this->table() ->orderBy('batch', 'asc') ->orderBy('migration', 'asc') ->pluck('batch', 'migration')->all(); } /** * Log that a migration was run. * * @param string $file * @param int $batch * @return void */ public function log($file, $batch) { $record = ['migration' => $file, 'batch' => $batch]; $this->table()->insert($record); } /** * Remove a migration from the log. * * @param object $migration * @return void */ public function delete($migration) { $this->table()->where('migration', $migration->migration)->delete(); } /** * Get the next migration batch number. * * @return int */ public function getNextBatchNumber() { return $this->getLastBatchNumber() + 1; } /** * Get the last migration batch number. * * @return int */ public function getLastBatchNumber() { return $this->table()->max('batch'); } /** * Create the migration repository data store. * * @return void */ public function createRepository() { $schema = $this->getConnection()->getSchemaBuilder(); $schema->create($this->table, function ($table) { // The migrations table is responsible for keeping track of which of the // migrations have actually run for the application. We'll create the // table to hold the migration file's path as well as the batch ID. $table->increments('id'); $table->string('migration'); $table->integer('batch'); }); } /** * Determine if the migration repository exists. * * @return bool */ public function repositoryExists() { $schema = $this->getConnection()->getSchemaBuilder(); return $schema->hasTable($this->table); } /** * Get a query builder for the migration table. * * @return \Illuminate\Database\Query\Builder */ protected function table() { return $this->getConnection()->table($this->table)->useWritePdo(); } /** * Get the connection resolver instance. * * @return \Illuminate\Database\ConnectionResolverInterface */ public function getConnectionResolver() { return $this->resolver; } /** * Resolve the database connection instance. * * @return \Illuminate\Database\Connection */ public function getConnection() { return $this->resolver->connection($this->connection); } /** * Set the information source to gather data. * * @param string $name * @return void */ public function setSource($name) { $this->connection = $name; } } database/Migrations/MigrationCreator.php 0000644 00000014003 14736103231 0014404 0 ustar 00 <?php namespace Illuminate\Database\Migrations; use Closure; use Illuminate\Filesystem\Filesystem; use Illuminate\Support\Str; use InvalidArgumentException; class MigrationCreator { /** * The filesystem instance. * * @var \Illuminate\Filesystem\Filesystem */ protected $files; /** * The custom app stubs directory. * * @var string */ protected $customStubPath; /** * The registered post create hooks. * * @var array */ protected $postCreate = []; /** * Create a new migration creator instance. * * @param \Illuminate\Filesystem\Filesystem $files * @param string $customStubPath * @return void */ public function __construct(Filesystem $files, $customStubPath) { $this->files = $files; $this->customStubPath = $customStubPath; } /** * Create a new migration at the given path. * * @param string $name * @param string $path * @param string|null $table * @param bool $create * @return string * * @throws \Exception */ public function create($name, $path, $table = null, $create = false) { $this->ensureMigrationDoesntAlreadyExist($name, $path); // First we will get the stub file for the migration, which serves as a type // of template for the migration. Once we have those we will populate the // various place-holders, save the file, and run the post create event. $stub = $this->getStub($table, $create); $this->files->put( $path = $this->getPath($name, $path), $this->populateStub($name, $stub, $table) ); // Next, we will fire any hooks that are supposed to fire after a migration is // created. Once that is done we'll be ready to return the full path to the // migration file so it can be used however it's needed by the developer. $this->firePostCreateHooks($table); return $path; } /** * Ensure that a migration with the given name doesn't already exist. * * @param string $name * @param string $migrationPath * @return void * * @throws \InvalidArgumentException */ protected function ensureMigrationDoesntAlreadyExist($name, $migrationPath = null) { if (! empty($migrationPath)) { $migrationFiles = $this->files->glob($migrationPath.'/*.php'); foreach ($migrationFiles as $migrationFile) { $this->files->requireOnce($migrationFile); } } if (class_exists($className = $this->getClassName($name))) { throw new InvalidArgumentException("A {$className} class already exists."); } } /** * Get the migration stub file. * * @param string|null $table * @param bool $create * @return string */ protected function getStub($table, $create) { if (is_null($table)) { $stub = $this->files->exists($customPath = $this->customStubPath.'/migration.stub') ? $customPath : $this->stubPath().'/migration.stub'; } elseif ($create) { $stub = $this->files->exists($customPath = $this->customStubPath.'/migration.create.stub') ? $customPath : $this->stubPath().'/migration.create.stub'; } else { $stub = $this->files->exists($customPath = $this->customStubPath.'/migration.update.stub') ? $customPath : $this->stubPath().'/migration.update.stub'; } return $this->files->get($stub); } /** * Populate the place-holders in the migration stub. * * @param string $name * @param string $stub * @param string|null $table * @return string */ protected function populateStub($name, $stub, $table) { $stub = str_replace( ['DummyClass', '{{ class }}', '{{class}}'], $this->getClassName($name), $stub ); // Here we will replace the table place-holders with the table specified by // the developer, which is useful for quickly creating a tables creation // or update migration from the console instead of typing it manually. if (! is_null($table)) { $stub = str_replace( ['DummyTable', '{{ table }}', '{{table}}'], $table, $stub ); } return $stub; } /** * Get the class name of a migration name. * * @param string $name * @return string */ protected function getClassName($name) { return Str::studly($name); } /** * Get the full path to the migration. * * @param string $name * @param string $path * @return string */ protected function getPath($name, $path) { return $path.'/'.$this->getDatePrefix().'_'.$name.'.php'; } /** * Fire the registered post create hooks. * * @param string|null $table * @return void */ protected function firePostCreateHooks($table) { foreach ($this->postCreate as $callback) { $callback($table); } } /** * Register a post migration create hook. * * @param \Closure $callback * @return void */ public function afterCreate(Closure $callback) { $this->postCreate[] = $callback; } /** * Get the date prefix for the migration. * * @return string */ protected function getDatePrefix() { return date('Y_m_d_His'); } /** * Get the path to the stubs. * * @return string */ public function stubPath() { return __DIR__.'/stubs'; } /** * Get the filesystem instance. * * @return \Illuminate\Filesystem\Filesystem */ public function getFilesystem() { return $this->files; } } database/Migrations/Migration.php 0000644 00000001025 14736103231 0013064 0 ustar 00 <?php namespace Illuminate\Database\Migrations; abstract class Migration { /** * The name of the database connection to use. * * @var string|null */ protected $connection; /** * Enables, if supported, wrapping the migration within a transaction. * * @var bool */ public $withinTransaction = true; /** * Get the migration connection name. * * @return string|null */ public function getConnection() { return $this->connection; } } database/Connection.php 0000644 00000077022 14736103231 0011130 0 ustar 00 <?php namespace Illuminate\Database; use Closure; use DateTimeInterface; use Doctrine\DBAL\Connection as DoctrineConnection; use Exception; use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Database\Events\QueryExecuted; use Illuminate\Database\Events\StatementPrepared; use Illuminate\Database\Events\TransactionBeginning; use Illuminate\Database\Events\TransactionCommitted; use Illuminate\Database\Events\TransactionRolledBack; use Illuminate\Database\Query\Builder as QueryBuilder; use Illuminate\Database\Query\Expression; use Illuminate\Database\Query\Grammars\Grammar as QueryGrammar; use Illuminate\Database\Query\Processors\Processor; use Illuminate\Database\Schema\Builder as SchemaBuilder; use Illuminate\Support\Arr; use LogicException; use PDO; use PDOStatement; class Connection implements ConnectionInterface { use DetectsConcurrencyErrors, DetectsLostConnections, Concerns\ManagesTransactions; /** * The active PDO connection. * * @var \PDO|\Closure */ protected $pdo; /** * The active PDO connection used for reads. * * @var \PDO|\Closure */ protected $readPdo; /** * The name of the connected database. * * @var string */ protected $database; /** * The table prefix for the connection. * * @var string */ protected $tablePrefix = ''; /** * The database connection configuration options. * * @var array */ protected $config = []; /** * The reconnector instance for the connection. * * @var callable */ protected $reconnector; /** * The query grammar implementation. * * @var \Illuminate\Database\Query\Grammars\Grammar */ protected $queryGrammar; /** * The schema grammar implementation. * * @var \Illuminate\Database\Schema\Grammars\Grammar */ protected $schemaGrammar; /** * The query post processor implementation. * * @var \Illuminate\Database\Query\Processors\Processor */ protected $postProcessor; /** * The event dispatcher instance. * * @var \Illuminate\Contracts\Events\Dispatcher */ protected $events; /** * The default fetch mode of the connection. * * @var int */ protected $fetchMode = PDO::FETCH_OBJ; /** * The number of active transactions. * * @var int */ protected $transactions = 0; /** * Indicates if changes have been made to the database. * * @var int */ protected $recordsModified = false; /** * All of the queries run against the connection. * * @var array */ protected $queryLog = []; /** * Indicates whether queries are being logged. * * @var bool */ protected $loggingQueries = false; /** * Indicates if the connection is in a "dry run". * * @var bool */ protected $pretending = false; /** * The instance of Doctrine connection. * * @var \Doctrine\DBAL\Connection */ protected $doctrineConnection; /** * The connection resolvers. * * @var array */ protected static $resolvers = []; /** * Create a new database connection instance. * * @param \PDO|\Closure $pdo * @param string $database * @param string $tablePrefix * @param array $config * @return void */ public function __construct($pdo, $database = '', $tablePrefix = '', array $config = []) { $this->pdo = $pdo; // First we will setup the default properties. We keep track of the DB // name we are connected to since it is needed when some reflective // type commands are run such as checking whether a table exists. $this->database = $database; $this->tablePrefix = $tablePrefix; $this->config = $config; // We need to initialize a query grammar and the query post processors // which are both very important parts of the database abstractions // so we initialize these to their default values while starting. $this->useDefaultQueryGrammar(); $this->useDefaultPostProcessor(); } /** * Set the query grammar to the default implementation. * * @return void */ public function useDefaultQueryGrammar() { $this->queryGrammar = $this->getDefaultQueryGrammar(); } /** * Get the default query grammar instance. * * @return \Illuminate\Database\Query\Grammars\Grammar */ protected function getDefaultQueryGrammar() { return new QueryGrammar; } /** * Set the schema grammar to the default implementation. * * @return void */ public function useDefaultSchemaGrammar() { $this->schemaGrammar = $this->getDefaultSchemaGrammar(); } /** * Get the default schema grammar instance. * * @return \Illuminate\Database\Schema\Grammars\Grammar */ protected function getDefaultSchemaGrammar() { // } /** * Set the query post processor to the default implementation. * * @return void */ public function useDefaultPostProcessor() { $this->postProcessor = $this->getDefaultPostProcessor(); } /** * Get the default post processor instance. * * @return \Illuminate\Database\Query\Processors\Processor */ protected function getDefaultPostProcessor() { return new Processor; } /** * Get a schema builder instance for the connection. * * @return \Illuminate\Database\Schema\Builder */ public function getSchemaBuilder() { if (is_null($this->schemaGrammar)) { $this->useDefaultSchemaGrammar(); } return new SchemaBuilder($this); } /** * Begin a fluent query against a database table. * * @param \Closure|\Illuminate\Database\Query\Builder|string $table * @param string|null $as * @return \Illuminate\Database\Query\Builder */ public function table($table, $as = null) { return $this->query()->from($table, $as); } /** * Get a new query builder instance. * * @return \Illuminate\Database\Query\Builder */ public function query() { return new QueryBuilder( $this, $this->getQueryGrammar(), $this->getPostProcessor() ); } /** * Run a select statement and return a single result. * * @param string $query * @param array $bindings * @param bool $useReadPdo * @return mixed */ public function selectOne($query, $bindings = [], $useReadPdo = true) { $records = $this->select($query, $bindings, $useReadPdo); return array_shift($records); } /** * Run a select statement against the database. * * @param string $query * @param array $bindings * @return array */ public function selectFromWriteConnection($query, $bindings = []) { return $this->select($query, $bindings, false); } /** * Run a select statement against the database. * * @param string $query * @param array $bindings * @param bool $useReadPdo * @return array */ public function select($query, $bindings = [], $useReadPdo = true) { return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) { if ($this->pretending()) { return []; } // For select statements, we'll simply execute the query and return an array // of the database result set. Each element in the array will be a single // row from the database table, and will either be an array or objects. $statement = $this->prepared( $this->getPdoForSelect($useReadPdo)->prepare($query) ); $this->bindValues($statement, $this->prepareBindings($bindings)); $statement->execute(); return $statement->fetchAll(); }); } /** * Run a select statement against the database and returns a generator. * * @param string $query * @param array $bindings * @param bool $useReadPdo * @return \Generator */ public function cursor($query, $bindings = [], $useReadPdo = true) { $statement = $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) { if ($this->pretending()) { return []; } // First we will create a statement for the query. Then, we will set the fetch // mode and prepare the bindings for the query. Once that's done we will be // ready to execute the query against the database and return the cursor. $statement = $this->prepared($this->getPdoForSelect($useReadPdo) ->prepare($query)); $this->bindValues( $statement, $this->prepareBindings($bindings) ); // Next, we'll execute the query against the database and return the statement // so we can return the cursor. The cursor will use a PHP generator to give // back one row at a time without using a bunch of memory to render them. $statement->execute(); return $statement; }); while ($record = $statement->fetch()) { yield $record; } } /** * Configure the PDO prepared statement. * * @param \PDOStatement $statement * @return \PDOStatement */ protected function prepared(PDOStatement $statement) { $statement->setFetchMode($this->fetchMode); $this->event(new StatementPrepared( $this, $statement )); return $statement; } /** * Get the PDO connection to use for a select query. * * @param bool $useReadPdo * @return \PDO */ protected function getPdoForSelect($useReadPdo = true) { return $useReadPdo ? $this->getReadPdo() : $this->getPdo(); } /** * Run an insert statement against the database. * * @param string $query * @param array $bindings * @return bool */ public function insert($query, $bindings = []) { return $this->statement($query, $bindings); } /** * Run an update statement against the database. * * @param string $query * @param array $bindings * @return int */ public function update($query, $bindings = []) { return $this->affectingStatement($query, $bindings); } /** * Run a delete statement against the database. * * @param string $query * @param array $bindings * @return int */ public function delete($query, $bindings = []) { return $this->affectingStatement($query, $bindings); } /** * Execute an SQL statement and return the boolean result. * * @param string $query * @param array $bindings * @return bool */ public function statement($query, $bindings = []) { return $this->run($query, $bindings, function ($query, $bindings) { if ($this->pretending()) { return true; } $statement = $this->getPdo()->prepare($query); $this->bindValues($statement, $this->prepareBindings($bindings)); $this->recordsHaveBeenModified(); return $statement->execute(); }); } /** * Run an SQL statement and get the number of rows affected. * * @param string $query * @param array $bindings * @return int */ public function affectingStatement($query, $bindings = []) { return $this->run($query, $bindings, function ($query, $bindings) { if ($this->pretending()) { return 0; } // For update or delete statements, we want to get the number of rows affected // by the statement and return that back to the developer. We'll first need // to execute the statement and then we'll use PDO to fetch the affected. $statement = $this->getPdo()->prepare($query); $this->bindValues($statement, $this->prepareBindings($bindings)); $statement->execute(); $this->recordsHaveBeenModified( ($count = $statement->rowCount()) > 0 ); return $count; }); } /** * Run a raw, unprepared query against the PDO connection. * * @param string $query * @return bool */ public function unprepared($query) { return $this->run($query, [], function ($query) { if ($this->pretending()) { return true; } $this->recordsHaveBeenModified( $change = $this->getPdo()->exec($query) !== false ); return $change; }); } /** * Execute the given callback in "dry run" mode. * * @param \Closure $callback * @return array */ public function pretend(Closure $callback) { return $this->withFreshQueryLog(function () use ($callback) { $this->pretending = true; // Basically to make the database connection "pretend", we will just return // the default values for all the query methods, then we will return an // array of queries that were "executed" within the Closure callback. $callback($this); $this->pretending = false; return $this->queryLog; }); } /** * Execute the given callback in "dry run" mode. * * @param \Closure $callback * @return array */ protected function withFreshQueryLog($callback) { $loggingQueries = $this->loggingQueries; // First we will back up the value of the logging queries property and then // we'll be ready to run callbacks. This query log will also get cleared // so we will have a new log of all the queries that are executed now. $this->enableQueryLog(); $this->queryLog = []; // Now we'll execute this callback and capture the result. Once it has been // executed we will restore the value of query logging and give back the // value of the callback so the original callers can have the results. $result = $callback(); $this->loggingQueries = $loggingQueries; return $result; } /** * Bind values to their parameters in the given statement. * * @param \PDOStatement $statement * @param array $bindings * @return void */ public function bindValues($statement, $bindings) { foreach ($bindings as $key => $value) { $statement->bindValue( is_string($key) ? $key : $key + 1, $value, is_int($value) ? PDO::PARAM_INT : PDO::PARAM_STR ); } } /** * Prepare the query bindings for execution. * * @param array $bindings * @return array */ public function prepareBindings(array $bindings) { $grammar = $this->getQueryGrammar(); foreach ($bindings as $key => $value) { // We need to transform all instances of DateTimeInterface into the actual // date string. Each query grammar maintains its own date string format // so we'll just ask the grammar for the format to get from the date. if ($value instanceof DateTimeInterface) { $bindings[$key] = $value->format($grammar->getDateFormat()); } elseif (is_bool($value)) { $bindings[$key] = (int) $value; } } return $bindings; } /** * Run a SQL statement and log its execution context. * * @param string $query * @param array $bindings * @param \Closure $callback * @return mixed * * @throws \Illuminate\Database\QueryException */ protected function run($query, $bindings, Closure $callback) { $this->reconnectIfMissingConnection(); $start = microtime(true); // Here we will run this query. If an exception occurs we'll determine if it was // caused by a connection that has been lost. If that is the cause, we'll try // to re-establish connection and re-run the query with a fresh connection. try { $result = $this->runQueryCallback($query, $bindings, $callback); } catch (QueryException $e) { $result = $this->handleQueryException( $e, $query, $bindings, $callback ); } // Once we have run the query we will calculate the time that it took to run and // then log the query, bindings, and execution time so we will report them on // the event that the developer needs them. We'll log time in milliseconds. $this->logQuery( $query, $bindings, $this->getElapsedTime($start) ); return $result; } /** * Run a SQL statement. * * @param string $query * @param array $bindings * @param \Closure $callback * @return mixed * * @throws \Illuminate\Database\QueryException */ protected function runQueryCallback($query, $bindings, Closure $callback) { // To execute the statement, we'll simply call the callback, which will actually // run the SQL against the PDO connection. Then we can calculate the time it // took to execute and log the query SQL, bindings and time in our memory. try { $result = $callback($query, $bindings); } // If an exception occurs when attempting to run a query, we'll format the error // message to include the bindings with SQL, which will make this exception a // lot more helpful to the developer instead of just the database's errors. catch (Exception $e) { throw new QueryException( $query, $this->prepareBindings($bindings), $e ); } return $result; } /** * Log a query in the connection's query log. * * @param string $query * @param array $bindings * @param float|null $time * @return void */ public function logQuery($query, $bindings, $time = null) { $this->event(new QueryExecuted($query, $bindings, $time, $this)); if ($this->loggingQueries) { $this->queryLog[] = compact('query', 'bindings', 'time'); } } /** * Get the elapsed time since a given starting point. * * @param int $start * @return float */ protected function getElapsedTime($start) { return round((microtime(true) - $start) * 1000, 2); } /** * Handle a query exception. * * @param \Illuminate\Database\QueryException $e * @param string $query * @param array $bindings * @param \Closure $callback * @return mixed * * @throws \Illuminate\Database\QueryException */ protected function handleQueryException(QueryException $e, $query, $bindings, Closure $callback) { if ($this->transactions >= 1) { throw $e; } return $this->tryAgainIfCausedByLostConnection( $e, $query, $bindings, $callback ); } /** * Handle a query exception that occurred during query execution. * * @param \Illuminate\Database\QueryException $e * @param string $query * @param array $bindings * @param \Closure $callback * @return mixed * * @throws \Illuminate\Database\QueryException */ protected function tryAgainIfCausedByLostConnection(QueryException $e, $query, $bindings, Closure $callback) { if ($this->causedByLostConnection($e->getPrevious())) { $this->reconnect(); return $this->runQueryCallback($query, $bindings, $callback); } throw $e; } /** * Reconnect to the database. * * @return void * * @throws \LogicException */ public function reconnect() { if (is_callable($this->reconnector)) { $this->doctrineConnection = null; return call_user_func($this->reconnector, $this); } throw new LogicException('Lost connection and no reconnector available.'); } /** * Reconnect to the database if a PDO connection is missing. * * @return void */ protected function reconnectIfMissingConnection() { if (is_null($this->pdo)) { $this->reconnect(); } } /** * Disconnect from the underlying PDO connection. * * @return void */ public function disconnect() { $this->setPdo(null)->setReadPdo(null); } /** * Register a database query listener with the connection. * * @param \Closure $callback * @return void */ public function listen(Closure $callback) { if (isset($this->events)) { $this->events->listen(Events\QueryExecuted::class, $callback); } } /** * Fire an event for this connection. * * @param string $event * @return array|null */ protected function fireConnectionEvent($event) { if (! isset($this->events)) { return; } switch ($event) { case 'beganTransaction': return $this->events->dispatch(new TransactionBeginning($this)); case 'committed': return $this->events->dispatch(new TransactionCommitted($this)); case 'rollingBack': return $this->events->dispatch(new TransactionRolledBack($this)); } } /** * Fire the given event if possible. * * @param mixed $event * @return void */ protected function event($event) { if (isset($this->events)) { $this->events->dispatch($event); } } /** * Get a new raw query expression. * * @param mixed $value * @return \Illuminate\Database\Query\Expression */ public function raw($value) { return new Expression($value); } /** * Indicate if any records have been modified. * * @param bool $value * @return void */ public function recordsHaveBeenModified($value = true) { if (! $this->recordsModified) { $this->recordsModified = $value; } } /** * Is Doctrine available? * * @return bool */ public function isDoctrineAvailable() { return class_exists('Doctrine\DBAL\Connection'); } /** * Get a Doctrine Schema Column instance. * * @param string $table * @param string $column * @return \Doctrine\DBAL\Schema\Column */ public function getDoctrineColumn($table, $column) { $schema = $this->getDoctrineSchemaManager(); return $schema->listTableDetails($table)->getColumn($column); } /** * Get the Doctrine DBAL schema manager for the connection. * * @return \Doctrine\DBAL\Schema\AbstractSchemaManager */ public function getDoctrineSchemaManager() { return $this->getDoctrineDriver()->getSchemaManager($this->getDoctrineConnection()); } /** * Get the Doctrine DBAL database connection instance. * * @return \Doctrine\DBAL\Connection */ public function getDoctrineConnection() { if (is_null($this->doctrineConnection)) { $driver = $this->getDoctrineDriver(); $this->doctrineConnection = new DoctrineConnection(array_filter([ 'pdo' => $this->getPdo(), 'dbname' => $this->getDatabaseName(), 'driver' => $driver->getName(), 'serverVersion' => $this->getConfig('server_version'), ]), $driver); } return $this->doctrineConnection; } /** * Get the current PDO connection. * * @return \PDO */ public function getPdo() { if ($this->pdo instanceof Closure) { return $this->pdo = call_user_func($this->pdo); } return $this->pdo; } /** * Get the current PDO connection parameter without executing any reconnect logic. * * @return \PDO|\Closure|null */ public function getRawPdo() { return $this->pdo; } /** * Get the current PDO connection used for reading. * * @return \PDO */ public function getReadPdo() { if ($this->transactions > 0) { return $this->getPdo(); } if ($this->recordsModified && $this->getConfig('sticky')) { return $this->getPdo(); } if ($this->readPdo instanceof Closure) { return $this->readPdo = call_user_func($this->readPdo); } return $this->readPdo ?: $this->getPdo(); } /** * Get the current read PDO connection parameter without executing any reconnect logic. * * @return \PDO|\Closure|null */ public function getRawReadPdo() { return $this->readPdo; } /** * Set the PDO connection. * * @param \PDO|\Closure|null $pdo * @return $this */ public function setPdo($pdo) { $this->transactions = 0; $this->pdo = $pdo; return $this; } /** * Set the PDO connection used for reading. * * @param \PDO|\Closure|null $pdo * @return $this */ public function setReadPdo($pdo) { $this->readPdo = $pdo; return $this; } /** * Set the reconnect instance on the connection. * * @param callable $reconnector * @return $this */ public function setReconnector(callable $reconnector) { $this->reconnector = $reconnector; return $this; } /** * Get the database connection name. * * @return string|null */ public function getName() { return $this->getConfig('name'); } /** * Get an option from the configuration options. * * @param string|null $option * @return mixed */ public function getConfig($option = null) { return Arr::get($this->config, $option); } /** * Get the PDO driver name. * * @return string */ public function getDriverName() { return $this->getConfig('driver'); } /** * Get the query grammar used by the connection. * * @return \Illuminate\Database\Query\Grammars\Grammar */ public function getQueryGrammar() { return $this->queryGrammar; } /** * Set the query grammar used by the connection. * * @param \Illuminate\Database\Query\Grammars\Grammar $grammar * @return $this */ public function setQueryGrammar(Query\Grammars\Grammar $grammar) { $this->queryGrammar = $grammar; return $this; } /** * Get the schema grammar used by the connection. * * @return \Illuminate\Database\Schema\Grammars\Grammar */ public function getSchemaGrammar() { return $this->schemaGrammar; } /** * Set the schema grammar used by the connection. * * @param \Illuminate\Database\Schema\Grammars\Grammar $grammar * @return $this */ public function setSchemaGrammar(Schema\Grammars\Grammar $grammar) { $this->schemaGrammar = $grammar; return $this; } /** * Get the query post processor used by the connection. * * @return \Illuminate\Database\Query\Processors\Processor */ public function getPostProcessor() { return $this->postProcessor; } /** * Set the query post processor used by the connection. * * @param \Illuminate\Database\Query\Processors\Processor $processor * @return $this */ public function setPostProcessor(Processor $processor) { $this->postProcessor = $processor; return $this; } /** * Get the event dispatcher used by the connection. * * @return \Illuminate\Contracts\Events\Dispatcher */ public function getEventDispatcher() { return $this->events; } /** * Set the event dispatcher instance on the connection. * * @param \Illuminate\Contracts\Events\Dispatcher $events * @return $this */ public function setEventDispatcher(Dispatcher $events) { $this->events = $events; return $this; } /** * Unset the event dispatcher for this connection. * * @return void */ public function unsetEventDispatcher() { $this->events = null; } /** * Determine if the connection is in a "dry run". * * @return bool */ public function pretending() { return $this->pretending === true; } /** * Get the connection query log. * * @return array */ public function getQueryLog() { return $this->queryLog; } /** * Clear the query log. * * @return void */ public function flushQueryLog() { $this->queryLog = []; } /** * Enable the query log on the connection. * * @return void */ public function enableQueryLog() { $this->loggingQueries = true; } /** * Disable the query log on the connection. * * @return void */ public function disableQueryLog() { $this->loggingQueries = false; } /** * Determine whether we're logging queries. * * @return bool */ public function logging() { return $this->loggingQueries; } /** * Get the name of the connected database. * * @return string */ public function getDatabaseName() { return $this->database; } /** * Set the name of the connected database. * * @param string $database * @return $this */ public function setDatabaseName($database) { $this->database = $database; return $this; } /** * Get the table prefix for the connection. * * @return string */ public function getTablePrefix() { return $this->tablePrefix; } /** * Set the table prefix in use by the connection. * * @param string $prefix * @return $this */ public function setTablePrefix($prefix) { $this->tablePrefix = $prefix; $this->getQueryGrammar()->setTablePrefix($prefix); return $this; } /** * Set the table prefix and return the grammar. * * @param \Illuminate\Database\Grammar $grammar * @return \Illuminate\Database\Grammar */ public function withTablePrefix(Grammar $grammar) { $grammar->setTablePrefix($this->tablePrefix); return $grammar; } /** * Register a connection resolver. * * @param string $driver * @param \Closure $callback * @return void */ public static function resolverFor($driver, Closure $callback) { static::$resolvers[$driver] = $callback; } /** * Get the connection resolver for the given driver. * * @param string $driver * @return mixed */ public static function getResolver($driver) { return static::$resolvers[$driver] ?? null; } } database/SqlServerConnection.php 0000644 00000005671 14736103231 0013000 0 ustar 00 <?php namespace Illuminate\Database; use Closure; use Doctrine\DBAL\Driver\PDOSqlsrv\Driver as DoctrineDriver; use Illuminate\Database\Query\Grammars\SqlServerGrammar as QueryGrammar; use Illuminate\Database\Query\Processors\SqlServerProcessor; use Illuminate\Database\Schema\Grammars\SqlServerGrammar as SchemaGrammar; use Illuminate\Database\Schema\SqlServerBuilder; use Throwable; class SqlServerConnection extends Connection { /** * Execute a Closure within a transaction. * * @param \Closure $callback * @param int $attempts * @return mixed * * @throws \Throwable */ public function transaction(Closure $callback, $attempts = 1) { for ($a = 1; $a <= $attempts; $a++) { if ($this->getDriverName() === 'sqlsrv') { return parent::transaction($callback); } $this->getPdo()->exec('BEGIN TRAN'); // We'll simply execute the given callback within a try / catch block // and if we catch any exception we can rollback the transaction // so that none of the changes are persisted to the database. try { $result = $callback($this); $this->getPdo()->exec('COMMIT TRAN'); } // If we catch an exception, we will roll back so nothing gets messed // up in the database. Then we'll re-throw the exception so it can // be handled how the developer sees fit for their applications. catch (Throwable $e) { $this->getPdo()->exec('ROLLBACK TRAN'); throw $e; } return $result; } } /** * Get the default query grammar instance. * * @return \Illuminate\Database\Query\Grammars\SqlServerGrammar */ protected function getDefaultQueryGrammar() { return $this->withTablePrefix(new QueryGrammar); } /** * Get a schema builder instance for the connection. * * @return \Illuminate\Database\Schema\SqlServerBuilder */ public function getSchemaBuilder() { if (is_null($this->schemaGrammar)) { $this->useDefaultSchemaGrammar(); } return new SqlServerBuilder($this); } /** * Get the default schema grammar instance. * * @return \Illuminate\Database\Schema\Grammars\SqlServerGrammar */ protected function getDefaultSchemaGrammar() { return $this->withTablePrefix(new SchemaGrammar); } /** * Get the default post processor instance. * * @return \Illuminate\Database\Query\Processors\SqlServerProcessor */ protected function getDefaultPostProcessor() { return new SqlServerProcessor; } /** * Get the Doctrine DBAL driver. * * @return \Doctrine\DBAL\Driver\PDOSqlsrv\Driver */ protected function getDoctrineDriver() { return new DoctrineDriver; } } translation/Translator.php 0000644 00000026651 14736103231 0011756 0 ustar 00 <?php namespace Illuminate\Translation; use Countable; use Illuminate\Contracts\Translation\Loader; use Illuminate\Contracts\Translation\Translator as TranslatorContract; use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\NamespacedItemResolver; use Illuminate\Support\Str; use Illuminate\Support\Traits\Macroable; use InvalidArgumentException; class Translator extends NamespacedItemResolver implements TranslatorContract { use Macroable; /** * The loader implementation. * * @var \Illuminate\Contracts\Translation\Loader */ protected $loader; /** * The default locale being used by the translator. * * @var string */ protected $locale; /** * The fallback locale used by the translator. * * @var string */ protected $fallback; /** * The array of loaded translation groups. * * @var array */ protected $loaded = []; /** * The message selector. * * @var \Illuminate\Translation\MessageSelector */ protected $selector; /** * Create a new translator instance. * * @param \Illuminate\Contracts\Translation\Loader $loader * @param string $locale * @return void */ public function __construct(Loader $loader, $locale) { $this->loader = $loader; $this->setLocale($locale); } /** * Determine if a translation exists for a given locale. * * @param string $key * @param string|null $locale * @return bool */ public function hasForLocale($key, $locale = null) { return $this->has($key, $locale, false); } /** * Determine if a translation exists. * * @param string $key * @param string|null $locale * @param bool $fallback * @return bool */ public function has($key, $locale = null, $fallback = true) { return $this->get($key, [], $locale, $fallback) !== $key; } /** * Get the translation for the given key. * * @param string $key * @param array $replace * @param string|null $locale * @param bool $fallback * @return string|array */ public function get($key, array $replace = [], $locale = null, $fallback = true) { $locale = $locale ?: $this->locale; // For JSON translations, there is only one file per locale, so we will simply load // that file and then we will be ready to check the array for the key. These are // only one level deep so we do not need to do any fancy searching through it. $this->load('*', '*', $locale); $line = $this->loaded['*']['*'][$locale][$key] ?? null; // If we can't find a translation for the JSON key, we will attempt to translate it // using the typical translation file. This way developers can always just use a // helper such as __ instead of having to pick between trans or __ with views. if (! isset($line)) { [$namespace, $group, $item] = $this->parseKey($key); // Here we will get the locale that should be used for the language line. If one // was not passed, we will use the default locales which was given to us when // the translator was instantiated. Then, we can load the lines and return. $locales = $fallback ? $this->localeArray($locale) : [$locale]; foreach ($locales as $locale) { if (! is_null($line = $this->getLine( $namespace, $group, $locale, $item, $replace ))) { return $line ?? $key; } } } // If the line doesn't exist, we will return back the key which was requested as // that will be quick to spot in the UI if language keys are wrong or missing // from the application's language files. Otherwise we can return the line. return $this->makeReplacements($line ?: $key, $replace); } /** * Get a translation according to an integer value. * * @param string $key * @param \Countable|int|array $number * @param array $replace * @param string|null $locale * @return string */ public function choice($key, $number, array $replace = [], $locale = null) { $line = $this->get( $key, $replace, $locale = $this->localeForChoice($locale) ); // If the given "number" is actually an array or countable we will simply count the // number of elements in an instance. This allows developers to pass an array of // items without having to count it on their end first which gives bad syntax. if (is_array($number) || $number instanceof Countable) { $number = count($number); } $replace['count'] = $number; return $this->makeReplacements( $this->getSelector()->choose($line, $number, $locale), $replace ); } /** * Get the proper locale for a choice operation. * * @param string|null $locale * @return string */ protected function localeForChoice($locale) { return $locale ?: $this->locale ?: $this->fallback; } /** * Retrieve a language line out the loaded array. * * @param string $namespace * @param string $group * @param string $locale * @param string $item * @param array $replace * @return string|array|null */ protected function getLine($namespace, $group, $locale, $item, array $replace) { $this->load($namespace, $group, $locale); $line = Arr::get($this->loaded[$namespace][$group][$locale], $item); if (is_string($line)) { return $this->makeReplacements($line, $replace); } elseif (is_array($line) && count($line) > 0) { foreach ($line as $key => $value) { $line[$key] = $this->makeReplacements($value, $replace); } return $line; } } /** * Make the place-holder replacements on a line. * * @param string $line * @param array $replace * @return string */ protected function makeReplacements($line, array $replace) { if (empty($replace)) { return $line; } $replace = $this->sortReplacements($replace); foreach ($replace as $key => $value) { $line = str_replace( [':'.$key, ':'.Str::upper($key), ':'.Str::ucfirst($key)], [$value, Str::upper($value), Str::ucfirst($value)], $line ); } return $line; } /** * Sort the replacements array. * * @param array $replace * @return array */ protected function sortReplacements(array $replace) { return (new Collection($replace))->sortBy(function ($value, $key) { return mb_strlen($key) * -1; })->all(); } /** * Add translation lines to the given locale. * * @param array $lines * @param string $locale * @param string $namespace * @return void */ public function addLines(array $lines, $locale, $namespace = '*') { foreach ($lines as $key => $value) { [$group, $item] = explode('.', $key, 2); Arr::set($this->loaded, "$namespace.$group.$locale.$item", $value); } } /** * Load the specified language group. * * @param string $namespace * @param string $group * @param string $locale * @return void */ public function load($namespace, $group, $locale) { if ($this->isLoaded($namespace, $group, $locale)) { return; } // The loader is responsible for returning the array of language lines for the // given namespace, group, and locale. We'll set the lines in this array of // lines that have already been loaded so that we can easily access them. $lines = $this->loader->load($locale, $group, $namespace); $this->loaded[$namespace][$group][$locale] = $lines; } /** * Determine if the given group has been loaded. * * @param string $namespace * @param string $group * @param string $locale * @return bool */ protected function isLoaded($namespace, $group, $locale) { return isset($this->loaded[$namespace][$group][$locale]); } /** * Add a new namespace to the loader. * * @param string $namespace * @param string $hint * @return void */ public function addNamespace($namespace, $hint) { $this->loader->addNamespace($namespace, $hint); } /** * Add a new JSON path to the loader. * * @param string $path * @return void */ public function addJsonPath($path) { $this->loader->addJsonPath($path); } /** * Parse a key into namespace, group, and item. * * @param string $key * @return array */ public function parseKey($key) { $segments = parent::parseKey($key); if (is_null($segments[0])) { $segments[0] = '*'; } return $segments; } /** * Get the array of locales to be checked. * * @param string|null $locale * @return array */ protected function localeArray($locale) { return array_filter([$locale ?: $this->locale, $this->fallback]); } /** * Get the message selector instance. * * @return \Illuminate\Translation\MessageSelector */ public function getSelector() { if (! isset($this->selector)) { $this->selector = new MessageSelector; } return $this->selector; } /** * Set the message selector instance. * * @param \Illuminate\Translation\MessageSelector $selector * @return void */ public function setSelector(MessageSelector $selector) { $this->selector = $selector; } /** * Get the language line loader implementation. * * @return \Illuminate\Contracts\Translation\Loader */ public function getLoader() { return $this->loader; } /** * Get the default locale being used. * * @return string */ public function locale() { return $this->getLocale(); } /** * Get the default locale being used. * * @return string */ public function getLocale() { return $this->locale; } /** * Set the default locale. * * @param string $locale * @return void */ public function setLocale($locale) { if (Str::contains($locale, ['/', '\\'])) { throw new InvalidArgumentException('Invalid characters present in locale.'); } $this->locale = $locale; } /** * Get the fallback locale being used. * * @return string */ public function getFallback() { return $this->fallback; } /** * Set the fallback locale being used. * * @param string $fallback * @return void */ public function setFallback($fallback) { $this->fallback = $fallback; } /** * Set the loaded translation groups. * * @param array $loaded * @return void */ public function setLoaded(array $loaded) { $this->loaded = $loaded; } } translation/TranslationServiceProvider.php 0000644 00000002662 14736103231 0015153 0 ustar 00 <?php namespace Illuminate\Translation; use Illuminate\Contracts\Support\DeferrableProvider; use Illuminate\Support\ServiceProvider; class TranslationServiceProvider extends ServiceProvider implements DeferrableProvider { /** * Register the service provider. * * @return void */ public function register() { $this->registerLoader(); $this->app->singleton('translator', function ($app) { $loader = $app['translation.loader']; // When registering the translator component, we'll need to set the default // locale as well as the fallback locale. So, we'll grab the application // configuration so we can easily get both of these values from there. $locale = $app['config']['app.locale']; $trans = new Translator($loader, $locale); $trans->setFallback($app['config']['app.fallback_locale']); return $trans; }); } /** * Register the translation line loader. * * @return void */ protected function registerLoader() { $this->app->singleton('translation.loader', function ($app) { return new FileLoader($app['files'], $app['path.lang']); }); } /** * Get the services provided by the provider. * * @return array */ public function provides() { return ['translator', 'translation.loader']; } } translation/ArrayLoader.php 0000644 00000003117 14736103231 0012022 0 ustar 00 <?php namespace Illuminate\Translation; use Illuminate\Contracts\Translation\Loader; class ArrayLoader implements Loader { /** * All of the translation messages. * * @var array */ protected $messages = []; /** * Load the messages for the given locale. * * @param string $locale * @param string $group * @param string|null $namespace * @return array */ public function load($locale, $group, $namespace = null) { $namespace = $namespace ?: '*'; return $this->messages[$namespace][$locale][$group] ?? []; } /** * Add a new namespace to the loader. * * @param string $namespace * @param string $hint * @return void */ public function addNamespace($namespace, $hint) { // } /** * Add a new JSON path to the loader. * * @param string $path * @return void */ public function addJsonPath($path) { // } /** * Add messages to the loader. * * @param string $locale * @param string $group * @param array $messages * @param string|null $namespace * @return $this */ public function addMessages($locale, $group, array $messages, $namespace = null) { $namespace = $namespace ?: '*'; $this->messages[$namespace][$locale][$group] = $messages; return $this; } /** * Get an array of all the registered namespaces. * * @return array */ public function namespaces() { return []; } } translation/MessageSelector.php 0000644 00000026671 14736103231 0012714 0 ustar 00 <?php namespace Illuminate\Translation; use Illuminate\Support\Str; class MessageSelector { /** * Select a proper translation string based on the given number. * * @param string $line * @param int $number * @param string $locale * @return mixed */ public function choose($line, $number, $locale) { $segments = explode('|', $line); if (($value = $this->extract($segments, $number)) !== null) { return trim($value); } $segments = $this->stripConditions($segments); $pluralIndex = $this->getPluralIndex($locale, $number); if (count($segments) === 1 || ! isset($segments[$pluralIndex])) { return $segments[0]; } return $segments[$pluralIndex]; } /** * Extract a translation string using inline conditions. * * @param array $segments * @param int $number * @return mixed */ private function extract($segments, $number) { foreach ($segments as $part) { if (! is_null($line = $this->extractFromString($part, $number))) { return $line; } } } /** * Get the translation string if the condition matches. * * @param string $part * @param int $number * @return mixed */ private function extractFromString($part, $number) { preg_match('/^[\{\[]([^\[\]\{\}]*)[\}\]](.*)/s', $part, $matches); if (count($matches) !== 3) { return; } $condition = $matches[1]; $value = $matches[2]; if (Str::contains($condition, ',')) { [$from, $to] = explode(',', $condition, 2); if ($to === '*' && $number >= $from) { return $value; } elseif ($from === '*' && $number <= $to) { return $value; } elseif ($number >= $from && $number <= $to) { return $value; } } return $condition == $number ? $value : null; } /** * Strip the inline conditions from each segment, just leaving the text. * * @param array $segments * @return array */ private function stripConditions($segments) { return collect($segments)->map(function ($part) { return preg_replace('/^[\{\[]([^\[\]\{\}]*)[\}\]]/', '', $part); })->all(); } /** * Get the index to use for pluralization. * * The plural rules are derived from code of the Zend Framework (2010-09-25), which * is subject to the new BSD license (https://framework.zend.com/license) * Copyright (c) 2005-2010 - Zend Technologies USA Inc. (http://www.zend.com) * * @param string $locale * @param int $number * @return int */ public function getPluralIndex($locale, $number) { switch ($locale) { case 'az': case 'az_AZ': case 'bo': case 'bo_CN': case 'bo_IN': case 'dz': case 'dz_BT': case 'id': case 'id_ID': case 'ja': case 'ja_JP': case 'jv': case 'ka': case 'ka_GE': case 'km': case 'km_KH': case 'kn': case 'kn_IN': case 'ko': case 'ko_KR': case 'ms': case 'ms_MY': case 'th': case 'th_TH': case 'tr': case 'tr_CY': case 'tr_TR': case 'vi': case 'vi_VN': case 'zh': case 'zh_CN': case 'zh_HK': case 'zh_SG': case 'zh_TW': return 0; case 'af': case 'af_ZA': case 'bn': case 'bn_BD': case 'bn_IN': case 'bg': case 'bg_BG': case 'ca': case 'ca_AD': case 'ca_ES': case 'ca_FR': case 'ca_IT': case 'da': case 'da_DK': case 'de': case 'de_AT': case 'de_BE': case 'de_CH': case 'de_DE': case 'de_LI': case 'de_LU': case 'el': case 'el_CY': case 'el_GR': case 'en': case 'en_AG': case 'en_AU': case 'en_BW': case 'en_CA': case 'en_DK': case 'en_GB': case 'en_HK': case 'en_IE': case 'en_IN': case 'en_NG': case 'en_NZ': case 'en_PH': case 'en_SG': case 'en_US': case 'en_ZA': case 'en_ZM': case 'en_ZW': case 'eo': case 'eo_US': case 'es': case 'es_AR': case 'es_BO': case 'es_CL': case 'es_CO': case 'es_CR': case 'es_CU': case 'es_DO': case 'es_EC': case 'es_ES': case 'es_GT': case 'es_HN': case 'es_MX': case 'es_NI': case 'es_PA': case 'es_PE': case 'es_PR': case 'es_PY': case 'es_SV': case 'es_US': case 'es_UY': case 'es_VE': case 'et': case 'et_EE': case 'eu': case 'eu_ES': case 'eu_FR': case 'fa': case 'fa_IR': case 'fi': case 'fi_FI': case 'fo': case 'fo_FO': case 'fur': case 'fur_IT': case 'fy': case 'fy_DE': case 'fy_NL': case 'gl': case 'gl_ES': case 'gu': case 'gu_IN': case 'ha': case 'ha_NG': case 'he': case 'he_IL': case 'hu': case 'hu_HU': case 'is': case 'is_IS': case 'it': case 'it_CH': case 'it_IT': case 'ku': case 'ku_TR': case 'lb': case 'lb_LU': case 'ml': case 'ml_IN': case 'mn': case 'mn_MN': case 'mr': case 'mr_IN': case 'nah': case 'nb': case 'nb_NO': case 'ne': case 'ne_NP': case 'nl': case 'nl_AW': case 'nl_BE': case 'nl_NL': case 'nn': case 'nn_NO': case 'no': case 'om': case 'om_ET': case 'om_KE': case 'or': case 'or_IN': case 'pa': case 'pa_IN': case 'pa_PK': case 'pap': case 'pap_AN': case 'pap_AW': case 'pap_CW': case 'ps': case 'ps_AF': case 'pt': case 'pt_BR': case 'pt_PT': case 'so': case 'so_DJ': case 'so_ET': case 'so_KE': case 'so_SO': case 'sq': case 'sq_AL': case 'sq_MK': case 'sv': case 'sv_FI': case 'sv_SE': case 'sw': case 'sw_KE': case 'sw_TZ': case 'ta': case 'ta_IN': case 'ta_LK': case 'te': case 'te_IN': case 'tk': case 'tk_TM': case 'ur': case 'ur_IN': case 'ur_PK': case 'zu': case 'zu_ZA': return ($number == 1) ? 0 : 1; case 'am': case 'am_ET': case 'bh': case 'fil': case 'fil_PH': case 'fr': case 'fr_BE': case 'fr_CA': case 'fr_CH': case 'fr_FR': case 'fr_LU': case 'gun': case 'hi': case 'hi_IN': case 'hy': case 'hy_AM': case 'ln': case 'ln_CD': case 'mg': case 'mg_MG': case 'nso': case 'nso_ZA': case 'ti': case 'ti_ER': case 'ti_ET': case 'wa': case 'wa_BE': case 'xbr': return (($number == 0) || ($number == 1)) ? 0 : 1; case 'be': case 'be_BY': case 'bs': case 'bs_BA': case 'hr': case 'hr_HR': case 'ru': case 'ru_RU': case 'ru_UA': case 'sr': case 'sr_ME': case 'sr_RS': case 'uk': case 'uk_UA': return (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2); case 'cs': case 'cs_CZ': case 'sk': case 'sk_SK': return ($number == 1) ? 0 : ((($number >= 2) && ($number <= 4)) ? 1 : 2); case 'ga': case 'ga_IE': return ($number == 1) ? 0 : (($number == 2) ? 1 : 2); case 'lt': case 'lt_LT': return (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2); case 'sl': case 'sl_SI': return ($number % 100 == 1) ? 0 : (($number % 100 == 2) ? 1 : ((($number % 100 == 3) || ($number % 100 == 4)) ? 2 : 3)); case 'mk': case 'mk_MK': return ($number % 10 == 1) ? 0 : 1; case 'mt': case 'mt_MT': return ($number == 1) ? 0 : ((($number == 0) || (($number % 100 > 1) && ($number % 100 < 11))) ? 1 : ((($number % 100 > 10) && ($number % 100 < 20)) ? 2 : 3)); case 'lv': case 'lv_LV': return ($number == 0) ? 0 : ((($number % 10 == 1) && ($number % 100 != 11)) ? 1 : 2); case 'pl': case 'pl_PL': return ($number == 1) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 12) || ($number % 100 > 14))) ? 1 : 2); case 'cy': case 'cy_GB': return ($number == 1) ? 0 : (($number == 2) ? 1 : ((($number == 8) || ($number == 11)) ? 2 : 3)); case 'ro': case 'ro_RO': return ($number == 1) ? 0 : ((($number == 0) || (($number % 100 > 0) && ($number % 100 < 20))) ? 1 : 2); case 'ar': case 'ar_AE': case 'ar_BH': case 'ar_DZ': case 'ar_EG': case 'ar_IN': case 'ar_IQ': case 'ar_JO': case 'ar_KW': case 'ar_LB': case 'ar_LY': case 'ar_MA': case 'ar_OM': case 'ar_QA': case 'ar_SA': case 'ar_SD': case 'ar_SS': case 'ar_SY': case 'ar_TN': case 'ar_YE': return ($number == 0) ? 0 : (($number == 1) ? 1 : (($number == 2) ? 2 : ((($number % 100 >= 3) && ($number % 100 <= 10)) ? 3 : ((($number % 100 >= 11) && ($number % 100 <= 99)) ? 4 : 5)))); default: return 0; } } } translation/LICENSE.md 0000644 00000002063 14736103231 0010507 0 ustar 00 The MIT License (MIT) Copyright (c) Taylor Otwell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. translation/FileLoader.php 0000644 00000010652 14736103231 0011625 0 ustar 00 <?php namespace Illuminate\Translation; use Illuminate\Contracts\Translation\Loader; use Illuminate\Filesystem\Filesystem; use RuntimeException; class FileLoader implements Loader { /** * The filesystem instance. * * @var \Illuminate\Filesystem\Filesystem */ protected $files; /** * The default path for the loader. * * @var string */ protected $path; /** * All of the registered paths to JSON translation files. * * @var array */ protected $jsonPaths = []; /** * All of the namespace hints. * * @var array */ protected $hints = []; /** * Create a new file loader instance. * * @param \Illuminate\Filesystem\Filesystem $files * @param string $path * @return void */ public function __construct(Filesystem $files, $path) { $this->path = $path; $this->files = $files; } /** * Load the messages for the given locale. * * @param string $locale * @param string $group * @param string|null $namespace * @return array */ public function load($locale, $group, $namespace = null) { if ($group === '*' && $namespace === '*') { return $this->loadJsonPaths($locale); } if (is_null($namespace) || $namespace === '*') { return $this->loadPath($this->path, $locale, $group); } return $this->loadNamespaced($locale, $group, $namespace); } /** * Load a namespaced translation group. * * @param string $locale * @param string $group * @param string $namespace * @return array */ protected function loadNamespaced($locale, $group, $namespace) { if (isset($this->hints[$namespace])) { $lines = $this->loadPath($this->hints[$namespace], $locale, $group); return $this->loadNamespaceOverrides($lines, $locale, $group, $namespace); } return []; } /** * Load a local namespaced translation group for overrides. * * @param array $lines * @param string $locale * @param string $group * @param string $namespace * @return array */ protected function loadNamespaceOverrides(array $lines, $locale, $group, $namespace) { $file = "{$this->path}/vendor/{$namespace}/{$locale}/{$group}.php"; if ($this->files->exists($file)) { return array_replace_recursive($lines, $this->files->getRequire($file)); } return $lines; } /** * Load a locale from a given path. * * @param string $path * @param string $locale * @param string $group * @return array */ protected function loadPath($path, $locale, $group) { if ($this->files->exists($full = "{$path}/{$locale}/{$group}.php")) { return $this->files->getRequire($full); } return []; } /** * Load a locale from the given JSON file path. * * @param string $locale * @return array * * @throws \RuntimeException */ protected function loadJsonPaths($locale) { return collect(array_merge($this->jsonPaths, [$this->path])) ->reduce(function ($output, $path) use ($locale) { if ($this->files->exists($full = "{$path}/{$locale}.json")) { $decoded = json_decode($this->files->get($full), true); if (is_null($decoded) || json_last_error() !== JSON_ERROR_NONE) { throw new RuntimeException("Translation file [{$full}] contains an invalid JSON structure."); } $output = array_merge($output, $decoded); } return $output; }, []); } /** * Add a new namespace to the loader. * * @param string $namespace * @param string $hint * @return void */ public function addNamespace($namespace, $hint) { $this->hints[$namespace] = $hint; } /** * Add a new JSON path to the loader. * * @param string $path * @return void */ public function addJsonPath($path) { $this->jsonPaths[] = $path; } /** * Get an array of all the registered namespaces. * * @return array */ public function namespaces() { return $this->hints; } } validation/Validator.php 0000644 00000102127 14736103231 0011337 0 ustar 00 <?php namespace Illuminate\Validation; use BadMethodCallException; use Illuminate\Contracts\Container\Container; use Illuminate\Contracts\Translation\Translator; use Illuminate\Contracts\Validation\ImplicitRule; use Illuminate\Contracts\Validation\Rule as RuleContract; use Illuminate\Contracts\Validation\Validator as ValidatorContract; use Illuminate\Support\Arr; use Illuminate\Support\Fluent; use Illuminate\Support\MessageBag; use Illuminate\Support\Str; use RuntimeException; use Symfony\Component\HttpFoundation\File\UploadedFile; class Validator implements ValidatorContract { use Concerns\FormatsMessages, Concerns\ValidatesAttributes; /** * The Translator implementation. * * @var \Illuminate\Contracts\Translation\Translator */ protected $translator; /** * The container instance. * * @var \Illuminate\Contracts\Container\Container */ protected $container; /** * The Presence Verifier implementation. * * @var \Illuminate\Validation\PresenceVerifierInterface */ protected $presenceVerifier; /** * The failed validation rules. * * @var array */ protected $failedRules = []; /** * Attributes that should be excluded from the validated data. * * @var array */ protected $excludeAttributes = []; /** * The message bag instance. * * @var \Illuminate\Support\MessageBag */ protected $messages; /** * The data under validation. * * @var array */ protected $data; /** * The initial rules provided. * * @var array */ protected $initialRules; /** * The rules to be applied to the data. * * @var array */ protected $rules; /** * The current rule that is validating. * * @var string */ protected $currentRule; /** * The array of wildcard attributes with their asterisks expanded. * * @var array */ protected $implicitAttributes = []; /** * The callback that should be used to format the attribute. * * @var callable|null */ protected $implicitAttributesFormatter; /** * The cached data for the "distinct" rule. * * @var array */ protected $distinctValues = []; /** * All of the registered "after" callbacks. * * @var array */ protected $after = []; /** * The array of custom error messages. * * @var array */ public $customMessages = []; /** * The array of fallback error messages. * * @var array */ public $fallbackMessages = []; /** * The array of custom attribute names. * * @var array */ public $customAttributes = []; /** * The array of custom displayable values. * * @var array */ public $customValues = []; /** * All of the custom validator extensions. * * @var array */ public $extensions = []; /** * All of the custom replacer extensions. * * @var array */ public $replacers = []; /** * The validation rules that may be applied to files. * * @var array */ protected $fileRules = [ 'Between', 'Dimensions', 'File', 'Image', 'Max', 'Mimes', 'Mimetypes', 'Min', 'Size', ]; /** * The validation rules that imply the field is required. * * @var array */ protected $implicitRules = [ 'Accepted', 'Filled', 'Present', 'Required', 'RequiredIf', 'RequiredUnless', 'RequiredWith', 'RequiredWithAll', 'RequiredWithout', 'RequiredWithoutAll', ]; /** * The validation rules which depend on other fields as parameters. * * @var array */ protected $dependentRules = [ 'After', 'AfterOrEqual', 'Before', 'BeforeOrEqual', 'Confirmed', 'Different', 'ExcludeIf', 'ExcludeUnless', 'ExcludeWithout', 'Gt', 'Gte', 'Lt', 'Lte', 'RequiredIf', 'RequiredUnless', 'RequiredWith', 'RequiredWithAll', 'RequiredWithout', 'RequiredWithoutAll', 'Same', 'Unique', ]; /** * The validation rules that can exclude an attribute. * * @var array */ protected $excludeRules = ['ExcludeIf', 'ExcludeUnless', 'ExcludeWithout']; /** * The size related validation rules. * * @var array */ protected $sizeRules = ['Size', 'Between', 'Min', 'Max', 'Gt', 'Lt', 'Gte', 'Lte']; /** * The numeric related validation rules. * * @var array */ protected $numericRules = ['Numeric', 'Integer']; /** * The current placeholder for dots in rule keys. * * @var string */ protected $dotPlaceholder; /** * Create a new Validator instance. * * @param \Illuminate\Contracts\Translation\Translator $translator * @param array $data * @param array $rules * @param array $messages * @param array $customAttributes * @return void */ public function __construct(Translator $translator, array $data, array $rules, array $messages = [], array $customAttributes = []) { $this->dotPlaceholder = Str::random(); $this->initialRules = $rules; $this->translator = $translator; $this->customMessages = $messages; $this->data = $this->parseData($data); $this->customAttributes = $customAttributes; $this->setRules($rules); } /** * Parse the data array, converting dots to ->. * * @param array $data * @return array */ public function parseData(array $data) { $newData = []; foreach ($data as $key => $value) { if (is_array($value)) { $value = $this->parseData($value); } $key = str_replace( ['.', '*'], [$this->dotPlaceholder, '__asterisk__'], $key ); $newData[$key] = $value; } return $newData; } /** * Add an after validation callback. * * @param callable|string $callback * @return $this */ public function after($callback) { $this->after[] = function () use ($callback) { return call_user_func_array($callback, [$this]); }; return $this; } /** * Determine if the data passes the validation rules. * * @return bool */ public function passes() { $this->messages = new MessageBag; [$this->distinctValues, $this->failedRules] = [[], []]; // We'll spin through each rule, validating the attributes attached to that // rule. Any error messages will be added to the containers with each of // the other error messages, returning true if we don't have messages. foreach ($this->rules as $attribute => $rules) { if ($this->shouldBeExcluded($attribute)) { $this->removeAttribute($attribute); continue; } foreach ($rules as $rule) { $this->validateAttribute($attribute, $rule); if ($this->shouldBeExcluded($attribute)) { $this->removeAttribute($attribute); break; } if ($this->shouldStopValidating($attribute)) { break; } } } // Here we will spin through all of the "after" hooks on this validator and // fire them off. This gives the callbacks a chance to perform all kinds // of other validation that needs to get wrapped up in this operation. foreach ($this->after as $after) { $after(); } return $this->messages->isEmpty(); } /** * Determine if the data fails the validation rules. * * @return bool */ public function fails() { return ! $this->passes(); } /** * Determine if the attribute should be excluded. * * @param string $attribute * @return bool */ protected function shouldBeExcluded($attribute) { foreach ($this->excludeAttributes as $excludeAttribute) { if ($attribute === $excludeAttribute || Str::startsWith($attribute, $excludeAttribute.'.')) { return true; } } return false; } /** * Remove the given attribute. * * @param string $attribute * * @return void */ protected function removeAttribute($attribute) { unset($this->data[$attribute], $this->rules[$attribute]); } /** * Run the validator's rules against its data. * * @return array * * @throws \Illuminate\Validation\ValidationException */ public function validate() { if ($this->fails()) { throw new ValidationException($this); } return $this->validated(); } /** * Run the validator's rules against its data. * * @param string $errorBag * @return array * * @throws \Illuminate\Validation\ValidationException */ public function validateWithBag(string $errorBag) { try { return $this->validate(); } catch (ValidationException $e) { $e->errorBag = $errorBag; throw $e; } } /** * Get the attributes and values that were validated. * * @return array * * @throws \Illuminate\Validation\ValidationException */ public function validated() { if ($this->invalid()) { throw new ValidationException($this); } $results = []; $missingValue = Str::random(10); foreach (array_keys($this->getRules()) as $key) { $value = data_get($this->getData(), $key, $missingValue); if ($value !== $missingValue) { Arr::set($results, $key, $value); } } return $results; } /** * Validate a given attribute against a rule. * * @param string $attribute * @param string $rule * @return void */ protected function validateAttribute($attribute, $rule) { $this->currentRule = $rule; [$rule, $parameters] = ValidationRuleParser::parse($rule); if ($rule == '') { return; } // First we will get the correct keys for the given attribute in case the field is nested in // an array. Then we determine if the given rule accepts other field names as parameters. // If so, we will replace any asterisks found in the parameters with the correct keys. if (($keys = $this->getExplicitKeys($attribute)) && $this->dependsOnOtherFields($rule)) { $parameters = $this->replaceAsterisksInParameters($parameters, $keys); } $value = $this->getValue($attribute); // If the attribute is a file, we will verify that the file upload was actually successful // and if it wasn't we will add a failure for the attribute. Files may not successfully // upload if they are too large based on PHP's settings so we will bail in this case. if ($value instanceof UploadedFile && ! $value->isValid() && $this->hasRule($attribute, array_merge($this->fileRules, $this->implicitRules)) ) { return $this->addFailure($attribute, 'uploaded', []); } // If we have made it this far we will make sure the attribute is validatable and if it is // we will call the validation method with the attribute. If a method returns false the // attribute is invalid and we will add a failure message for this failing attribute. $validatable = $this->isValidatable($rule, $attribute, $value); if ($rule instanceof RuleContract) { return $validatable ? $this->validateUsingCustomRule($attribute, $value, $rule) : null; } $method = "validate{$rule}"; if ($validatable && ! $this->$method($attribute, $value, $parameters, $this)) { $this->addFailure($attribute, $rule, $parameters); } } /** * Determine if the given rule depends on other fields. * * @param string $rule * @return bool */ protected function dependsOnOtherFields($rule) { return in_array($rule, $this->dependentRules); } /** * Get the explicit keys from an attribute flattened with dot notation. * * E.g. 'foo.1.bar.spark.baz' -> [1, 'spark'] for 'foo.*.bar.*.baz' * * @param string $attribute * @return array */ protected function getExplicitKeys($attribute) { $pattern = str_replace('\*', '([^\.]+)', preg_quote($this->getPrimaryAttribute($attribute), '/')); if (preg_match('/^'.$pattern.'/', $attribute, $keys)) { array_shift($keys); return $keys; } return []; } /** * Get the primary attribute name. * * For example, if "name.0" is given, "name.*" will be returned. * * @param string $attribute * @return string */ protected function getPrimaryAttribute($attribute) { foreach ($this->implicitAttributes as $unparsed => $parsed) { if (in_array($attribute, $parsed, true)) { return $unparsed; } } return $attribute; } /** * Replace each field parameter which has asterisks with the given keys. * * @param array $parameters * @param array $keys * @return array */ protected function replaceAsterisksInParameters(array $parameters, array $keys) { return array_map(function ($field) use ($keys) { return vsprintf(str_replace('*', '%s', $field), $keys); }, $parameters); } /** * Determine if the attribute is validatable. * * @param object|string $rule * @param string $attribute * @param mixed $value * @return bool */ protected function isValidatable($rule, $attribute, $value) { if (in_array($rule, $this->excludeRules)) { return true; } return $this->presentOrRuleIsImplicit($rule, $attribute, $value) && $this->passesOptionalCheck($attribute) && $this->isNotNullIfMarkedAsNullable($rule, $attribute) && $this->hasNotFailedPreviousRuleIfPresenceRule($rule, $attribute); } /** * Determine if the field is present, or the rule implies required. * * @param object|string $rule * @param string $attribute * @param mixed $value * @return bool */ protected function presentOrRuleIsImplicit($rule, $attribute, $value) { if (is_string($value) && trim($value) === '') { return $this->isImplicit($rule); } return $this->validatePresent($attribute, $value) || $this->isImplicit($rule); } /** * Determine if a given rule implies the attribute is required. * * @param object|string $rule * @return bool */ protected function isImplicit($rule) { return $rule instanceof ImplicitRule || in_array($rule, $this->implicitRules); } /** * Determine if the attribute passes any optional check. * * @param string $attribute * @return bool */ protected function passesOptionalCheck($attribute) { if (! $this->hasRule($attribute, ['Sometimes'])) { return true; } $data = ValidationData::initializeAndGatherData($attribute, $this->data); return array_key_exists($attribute, $data) || array_key_exists($attribute, $this->data); } /** * Determine if the attribute fails the nullable check. * * @param string $rule * @param string $attribute * @return bool */ protected function isNotNullIfMarkedAsNullable($rule, $attribute) { if ($this->isImplicit($rule) || ! $this->hasRule($attribute, ['Nullable'])) { return true; } return ! is_null(Arr::get($this->data, $attribute, 0)); } /** * Determine if it's a necessary presence validation. * * This is to avoid possible database type comparison errors. * * @param string $rule * @param string $attribute * @return bool */ protected function hasNotFailedPreviousRuleIfPresenceRule($rule, $attribute) { return in_array($rule, ['Unique', 'Exists']) ? ! $this->messages->has($attribute) : true; } /** * Validate an attribute using a custom rule object. * * @param string $attribute * @param mixed $value * @param \Illuminate\Contracts\Validation\Rule $rule * @return void */ protected function validateUsingCustomRule($attribute, $value, $rule) { if (! $rule->passes($attribute, $value)) { $this->failedRules[$attribute][get_class($rule)] = []; $messages = $rule->message() ? (array) $rule->message() : [get_class($rule)]; foreach ($messages as $message) { $this->messages->add($attribute, $this->makeReplacements( $message, $attribute, get_class($rule), [] )); } } } /** * Check if we should stop further validations on a given attribute. * * @param string $attribute * @return bool */ protected function shouldStopValidating($attribute) { if ($this->hasRule($attribute, ['Bail'])) { return $this->messages->has($attribute); } if (isset($this->failedRules[$attribute]) && array_key_exists('uploaded', $this->failedRules[$attribute])) { return true; } // In case the attribute has any rule that indicates that the field is required // and that rule already failed then we should stop validation at this point // as now there is no point in calling other rules with this field empty. return $this->hasRule($attribute, $this->implicitRules) && isset($this->failedRules[$attribute]) && array_intersect(array_keys($this->failedRules[$attribute]), $this->implicitRules); } /** * Add a failed rule and error message to the collection. * * @param string $attribute * @param string $rule * @param array $parameters * @return void */ public function addFailure($attribute, $rule, $parameters = []) { if (! $this->messages) { $this->passes(); } $attribute = str_replace('__asterisk__', '*', $attribute); if (in_array($rule, $this->excludeRules)) { return $this->excludeAttribute($attribute); } $this->messages->add($attribute, $this->makeReplacements( $this->getMessage($attribute, $rule), $attribute, $rule, $parameters )); $this->failedRules[$attribute][$rule] = $parameters; } /** * Add the given attribute to the list of excluded attributes. * * @param string $attribute * @return void */ protected function excludeAttribute(string $attribute) { $this->excludeAttributes[] = $attribute; $this->excludeAttributes = array_unique($this->excludeAttributes); } /** * Returns the data which was valid. * * @return array */ public function valid() { if (! $this->messages) { $this->passes(); } return array_diff_key( $this->data, $this->attributesThatHaveMessages() ); } /** * Returns the data which was invalid. * * @return array */ public function invalid() { if (! $this->messages) { $this->passes(); } $invalid = array_intersect_key( $this->data, $this->attributesThatHaveMessages() ); $result = []; $failed = Arr::only(Arr::dot($invalid), array_keys($this->failed())); foreach ($failed as $key => $failure) { Arr::set($result, $key, $failure); } return $result; } /** * Generate an array of all attributes that have messages. * * @return array */ protected function attributesThatHaveMessages() { return collect($this->messages()->toArray())->map(function ($message, $key) { return explode('.', $key)[0]; })->unique()->flip()->all(); } /** * Get the failed validation rules. * * @return array */ public function failed() { return $this->failedRules; } /** * Get the message container for the validator. * * @return \Illuminate\Support\MessageBag */ public function messages() { if (! $this->messages) { $this->passes(); } return $this->messages; } /** * An alternative more semantic shortcut to the message container. * * @return \Illuminate\Support\MessageBag */ public function errors() { return $this->messages(); } /** * Get the messages for the instance. * * @return \Illuminate\Support\MessageBag */ public function getMessageBag() { return $this->messages(); } /** * Determine if the given attribute has a rule in the given set. * * @param string $attribute * @param string|array $rules * @return bool */ public function hasRule($attribute, $rules) { return ! is_null($this->getRule($attribute, $rules)); } /** * Get a rule and its parameters for a given attribute. * * @param string $attribute * @param string|array $rules * @return array|null */ protected function getRule($attribute, $rules) { if (! array_key_exists($attribute, $this->rules)) { return; } $rules = (array) $rules; foreach ($this->rules[$attribute] as $rule) { [$rule, $parameters] = ValidationRuleParser::parse($rule); if (in_array($rule, $rules)) { return [$rule, $parameters]; } } } /** * Get the data under validation. * * @return array */ public function attributes() { return $this->getData(); } /** * Get the data under validation. * * @return array */ public function getData() { return $this->data; } /** * Set the data under validation. * * @param array $data * @return $this */ public function setData(array $data) { $this->data = $this->parseData($data); $this->setRules($this->initialRules); return $this; } /** * Get the value of a given attribute. * * @param string $attribute * @return mixed */ protected function getValue($attribute) { return Arr::get($this->data, $attribute); } /** * Get the validation rules. * * @return array */ public function getRules() { return $this->rules; } /** * Set the validation rules. * * @param array $rules * @return $this */ public function setRules(array $rules) { $rules = collect($rules)->mapWithKeys(function ($value, $key) { return [str_replace('\.', $this->dotPlaceholder, $key) => $value]; })->toArray(); $this->initialRules = $rules; $this->rules = []; $this->addRules($rules); return $this; } /** * Parse the given rules and merge them into current rules. * * @param array $rules * @return void */ public function addRules($rules) { // The primary purpose of this parser is to expand any "*" rules to the all // of the explicit rules needed for the given data. For example the rule // names.* would get expanded to names.0, names.1, etc. for this data. $response = (new ValidationRuleParser($this->data)) ->explode($rules); $this->rules = array_merge_recursive( $this->rules, $response->rules ); $this->implicitAttributes = array_merge( $this->implicitAttributes, $response->implicitAttributes ); } /** * Add conditions to a given field based on a Closure. * * @param string|array $attribute * @param string|array $rules * @param callable $callback * @return $this */ public function sometimes($attribute, $rules, callable $callback) { $payload = new Fluent($this->getData()); if ($callback($payload)) { foreach ((array) $attribute as $key) { $this->addRules([$key => $rules]); } } return $this; } /** * Register an array of custom validator extensions. * * @param array $extensions * @return void */ public function addExtensions(array $extensions) { if ($extensions) { $keys = array_map([Str::class, 'snake'], array_keys($extensions)); $extensions = array_combine($keys, array_values($extensions)); } $this->extensions = array_merge($this->extensions, $extensions); } /** * Register an array of custom implicit validator extensions. * * @param array $extensions * @return void */ public function addImplicitExtensions(array $extensions) { $this->addExtensions($extensions); foreach ($extensions as $rule => $extension) { $this->implicitRules[] = Str::studly($rule); } } /** * Register an array of custom dependent validator extensions. * * @param array $extensions * @return void */ public function addDependentExtensions(array $extensions) { $this->addExtensions($extensions); foreach ($extensions as $rule => $extension) { $this->dependentRules[] = Str::studly($rule); } } /** * Register a custom validator extension. * * @param string $rule * @param \Closure|string $extension * @return void */ public function addExtension($rule, $extension) { $this->extensions[Str::snake($rule)] = $extension; } /** * Register a custom implicit validator extension. * * @param string $rule * @param \Closure|string $extension * @return void */ public function addImplicitExtension($rule, $extension) { $this->addExtension($rule, $extension); $this->implicitRules[] = Str::studly($rule); } /** * Register a custom dependent validator extension. * * @param string $rule * @param \Closure|string $extension * @return void */ public function addDependentExtension($rule, $extension) { $this->addExtension($rule, $extension); $this->dependentRules[] = Str::studly($rule); } /** * Register an array of custom validator message replacers. * * @param array $replacers * @return void */ public function addReplacers(array $replacers) { if ($replacers) { $keys = array_map([Str::class, 'snake'], array_keys($replacers)); $replacers = array_combine($keys, array_values($replacers)); } $this->replacers = array_merge($this->replacers, $replacers); } /** * Register a custom validator message replacer. * * @param string $rule * @param \Closure|string $replacer * @return void */ public function addReplacer($rule, $replacer) { $this->replacers[Str::snake($rule)] = $replacer; } /** * Set the custom messages for the validator. * * @param array $messages * @return $this */ public function setCustomMessages(array $messages) { $this->customMessages = array_merge($this->customMessages, $messages); return $this; } /** * Set the custom attributes on the validator. * * @param array $attributes * @return $this */ public function setAttributeNames(array $attributes) { $this->customAttributes = $attributes; return $this; } /** * Add custom attributes to the validator. * * @param array $customAttributes * @return $this */ public function addCustomAttributes(array $customAttributes) { $this->customAttributes = array_merge($this->customAttributes, $customAttributes); return $this; } /** * Set the callback that used to format an implicit attribute.. * * @param callable|null $formatter * @return $this */ public function setImplicitAttributesFormatter(callable $formatter = null) { $this->implicitAttributesFormatter = $formatter; return $this; } /** * Set the custom values on the validator. * * @param array $values * @return $this */ public function setValueNames(array $values) { $this->customValues = $values; return $this; } /** * Add the custom values for the validator. * * @param array $customValues * @return $this */ public function addCustomValues(array $customValues) { $this->customValues = array_merge($this->customValues, $customValues); return $this; } /** * Set the fallback messages for the validator. * * @param array $messages * @return void */ public function setFallbackMessages(array $messages) { $this->fallbackMessages = $messages; } /** * Get the Presence Verifier implementation. * * @param string|null $connection * @return \Illuminate\Validation\PresenceVerifierInterface * * @throws \RuntimeException */ public function getPresenceVerifier($connection = null) { if (! isset($this->presenceVerifier)) { throw new RuntimeException('Presence verifier has not been set.'); } if ($this->presenceVerifier instanceof DatabasePresenceVerifierInterface) { $this->presenceVerifier->setConnection($connection); } return $this->presenceVerifier; } /** * Set the Presence Verifier implementation. * * @param \Illuminate\Validation\PresenceVerifierInterface $presenceVerifier * @return void */ public function setPresenceVerifier(PresenceVerifierInterface $presenceVerifier) { $this->presenceVerifier = $presenceVerifier; } /** * Get the Translator implementation. * * @return \Illuminate\Contracts\Translation\Translator */ public function getTranslator() { return $this->translator; } /** * Set the Translator implementation. * * @param \Illuminate\Contracts\Translation\Translator $translator * @return void */ public function setTranslator(Translator $translator) { $this->translator = $translator; } /** * Set the IoC container instance. * * @param \Illuminate\Contracts\Container\Container $container * @return void */ public function setContainer(Container $container) { $this->container = $container; } /** * Call a custom validator extension. * * @param string $rule * @param array $parameters * @return bool|null */ protected function callExtension($rule, $parameters) { $callback = $this->extensions[$rule]; if (is_callable($callback)) { return call_user_func_array($callback, $parameters); } elseif (is_string($callback)) { return $this->callClassBasedExtension($callback, $parameters); } } /** * Call a class based validator extension. * * @param string $callback * @param array $parameters * @return bool */ protected function callClassBasedExtension($callback, $parameters) { [$class, $method] = Str::parseCallback($callback, 'validate'); return call_user_func_array([$this->container->make($class), $method], $parameters); } /** * Handle dynamic calls to class methods. * * @param string $method * @param array $parameters * @return mixed * * @throws \BadMethodCallException */ public function __call($method, $parameters) { $rule = Str::snake(substr($method, 8)); if (isset($this->extensions[$rule])) { return $this->callExtension($rule, $parameters); } throw new BadMethodCallException(sprintf( 'Method %s::%s does not exist.', static::class, $method )); } } validation/ValidationData.php 0000644 00000005600 14736103231 0012274 0 ustar 00 <?php namespace Illuminate\Validation; use Illuminate\Support\Arr; use Illuminate\Support\Str; class ValidationData { /** * Initialize and gather data for given attribute. * * @param string $attribute * @param array $masterData * @return array */ public static function initializeAndGatherData($attribute, $masterData) { $data = Arr::dot(static::initializeAttributeOnData($attribute, $masterData)); return array_merge($data, static::extractValuesForWildcards( $masterData, $data, $attribute )); } /** * Gather a copy of the attribute data filled with any missing attributes. * * @param string $attribute * @param array $masterData * @return array */ protected static function initializeAttributeOnData($attribute, $masterData) { $explicitPath = static::getLeadingExplicitAttributePath($attribute); $data = static::extractDataFromPath($explicitPath, $masterData); if (! Str::contains($attribute, '*') || Str::endsWith($attribute, '*')) { return $data; } return data_set($data, $attribute, null, true); } /** * Get all of the exact attribute values for a given wildcard attribute. * * @param array $masterData * @param array $data * @param string $attribute * @return array */ protected static function extractValuesForWildcards($masterData, $data, $attribute) { $keys = []; $pattern = str_replace('\*', '[^\.]+', preg_quote($attribute)); foreach ($data as $key => $value) { if ((bool) preg_match('/^'.$pattern.'/', $key, $matches)) { $keys[] = $matches[0]; } } $keys = array_unique($keys); $data = []; foreach ($keys as $key) { $data[$key] = Arr::get($masterData, $key); } return $data; } /** * Extract data based on the given dot-notated path. * * Used to extract a sub-section of the data for faster iteration. * * @param string $attribute * @param array $masterData * @return array */ public static function extractDataFromPath($attribute, $masterData) { $results = []; $value = Arr::get($masterData, $attribute, '__missing__'); if ($value !== '__missing__') { Arr::set($results, $attribute, $value); } return $results; } /** * Get the explicit part of the attribute name. * * E.g. 'foo.bar.*.baz' -> 'foo.bar' * * Allows us to not spin through all of the flattened data for some operations. * * @param string $attribute * @return string */ public static function getLeadingExplicitAttributePath($attribute) { return rtrim(explode('*', $attribute)[0], '.') ?: null; } } validation/Rule.php 0000644 00000004545 14736103231 0010326 0 ustar 00 <?php namespace Illuminate\Validation; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Support\Traits\Macroable; use Illuminate\Validation\Rules\Dimensions; use Illuminate\Validation\Rules\Exists; use Illuminate\Validation\Rules\In; use Illuminate\Validation\Rules\NotIn; use Illuminate\Validation\Rules\RequiredIf; use Illuminate\Validation\Rules\Unique; class Rule { use Macroable; /** * Get a dimensions constraint builder instance. * * @param array $constraints * @return \Illuminate\Validation\Rules\Dimensions */ public static function dimensions(array $constraints = []) { return new Dimensions($constraints); } /** * Get a exists constraint builder instance. * * @param string $table * @param string $column * @return \Illuminate\Validation\Rules\Exists */ public static function exists($table, $column = 'NULL') { return new Exists($table, $column); } /** * Get an in constraint builder instance. * * @param \Illuminate\Contracts\Support\Arrayable|array|string $values * @return \Illuminate\Validation\Rules\In */ public static function in($values) { if ($values instanceof Arrayable) { $values = $values->toArray(); } return new In(is_array($values) ? $values : func_get_args()); } /** * Get a not_in constraint builder instance. * * @param \Illuminate\Contracts\Support\Arrayable|array|string $values * @return \Illuminate\Validation\Rules\NotIn */ public static function notIn($values) { if ($values instanceof Arrayable) { $values = $values->toArray(); } return new NotIn(is_array($values) ? $values : func_get_args()); } /** * Get a required_if constraint builder instance. * * @param callable|bool $callback * @return \Illuminate\Validation\Rules\RequiredIf */ public static function requiredIf($callback) { return new RequiredIf($callback); } /** * Get a unique constraint builder instance. * * @param string $table * @param string $column * @return \Illuminate\Validation\Rules\Unique */ public static function unique($table, $column = 'NULL') { return new Unique($table, $column); } } validation/ClosureValidationRule.php 0000644 00000002452 14736103231 0013671 0 ustar 00 <?php namespace Illuminate\Validation; use Illuminate\Contracts\Validation\Rule as RuleContract; class ClosureValidationRule implements RuleContract { /** * The callback that validates the attribute. * * @var \Closure */ public $callback; /** * Indicates if the validation callback failed. * * @var bool */ public $failed = false; /** * The validation error message. * * @var string|null */ public $message; /** * Create a new Closure based validation rule. * * @param \Closure $callback * @return void */ public function __construct($callback) { $this->callback = $callback; } /** * Determine if the validation rule passes. * * @param string $attribute * @param mixed $value * @return bool */ public function passes($attribute, $value) { $this->failed = false; $this->callback->__invoke($attribute, $value, function ($message) { $this->failed = true; $this->message = $message; }); return ! $this->failed; } /** * Get the validation error message. * * @return string */ public function message() { return $this->message; } } validation/ValidationException.php 0000644 00000005665 14736103231 0013374 0 ustar 00 <?php namespace Illuminate\Validation; use Exception; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Validator as ValidatorFacade; class ValidationException extends Exception { /** * The validator instance. * * @var \Illuminate\Contracts\Validation\Validator */ public $validator; /** * The recommended response to send to the client. * * @var \Symfony\Component\HttpFoundation\Response|null */ public $response; /** * The status code to use for the response. * * @var int */ public $status = 422; /** * The name of the error bag. * * @var string */ public $errorBag; /** * The path the client should be redirected to. * * @var string */ public $redirectTo; /** * Create a new exception instance. * * @param \Illuminate\Contracts\Validation\Validator $validator * @param \Symfony\Component\HttpFoundation\Response|null $response * @param string $errorBag * @return void */ public function __construct($validator, $response = null, $errorBag = 'default') { parent::__construct('The given data was invalid.'); $this->response = $response; $this->errorBag = $errorBag; $this->validator = $validator; } /** * Create a new validation exception from a plain array of messages. * * @param array $messages * @return static */ public static function withMessages(array $messages) { return new static(tap(ValidatorFacade::make([], []), function ($validator) use ($messages) { foreach ($messages as $key => $value) { foreach (Arr::wrap($value) as $message) { $validator->errors()->add($key, $message); } } })); } /** * Get all of the validation error messages. * * @return array */ public function errors() { return $this->validator->errors()->messages(); } /** * Set the HTTP status code to be used for the response. * * @param int $status * @return $this */ public function status($status) { $this->status = $status; return $this; } /** * Set the error bag on the exception. * * @param string $errorBag * @return $this */ public function errorBag($errorBag) { $this->errorBag = $errorBag; return $this; } /** * Set the URL to redirect to on a validation error. * * @param string $url * @return $this */ public function redirectTo($url) { $this->redirectTo = $url; return $this; } /** * Get the underlying response instance. * * @return \Symfony\Component\HttpFoundation\Response|null */ public function getResponse() { return $this->response; } } validation/DatabasePresenceVerifier.php 0000644 00000007200 14736103231 0014273 0 ustar 00 <?php namespace Illuminate\Validation; use Closure; use Illuminate\Database\ConnectionResolverInterface; use Illuminate\Support\Str; class DatabasePresenceVerifier implements DatabasePresenceVerifierInterface { /** * The database connection instance. * * @var \Illuminate\Database\ConnectionResolverInterface */ protected $db; /** * The database connection to use. * * @var string */ protected $connection; /** * Create a new database presence verifier. * * @param \Illuminate\Database\ConnectionResolverInterface $db * @return void */ public function __construct(ConnectionResolverInterface $db) { $this->db = $db; } /** * Count the number of objects in a collection having the given value. * * @param string $collection * @param string $column * @param string $value * @param int|null $excludeId * @param string|null $idColumn * @param array $extra * @return int */ public function getCount($collection, $column, $value, $excludeId = null, $idColumn = null, array $extra = []) { $query = $this->table($collection)->where($column, '=', $value); if (! is_null($excludeId) && $excludeId !== 'NULL') { $query->where($idColumn ?: 'id', '<>', $excludeId); } return $this->addConditions($query, $extra)->count(); } /** * Count the number of objects in a collection with the given values. * * @param string $collection * @param string $column * @param array $values * @param array $extra * @return int */ public function getMultiCount($collection, $column, array $values, array $extra = []) { $query = $this->table($collection)->whereIn($column, $values); return $this->addConditions($query, $extra)->distinct()->count($column); } /** * Add the given conditions to the query. * * @param \Illuminate\Database\Query\Builder $query * @param array $conditions * @return \Illuminate\Database\Query\Builder */ protected function addConditions($query, $conditions) { foreach ($conditions as $key => $value) { if ($value instanceof Closure) { $query->where(function ($query) use ($value) { $value($query); }); } else { $this->addWhere($query, $key, $value); } } return $query; } /** * Add a "where" clause to the given query. * * @param \Illuminate\Database\Query\Builder $query * @param string $key * @param string $extraValue * @return void */ protected function addWhere($query, $key, $extraValue) { if ($extraValue === 'NULL') { $query->whereNull($key); } elseif ($extraValue === 'NOT_NULL') { $query->whereNotNull($key); } elseif (Str::startsWith($extraValue, '!')) { $query->where($key, '!=', mb_substr($extraValue, 1)); } else { $query->where($key, $extraValue); } } /** * Get a query builder for the given table. * * @param string $table * @return \Illuminate\Database\Query\Builder */ protected function table($table) { return $this->db->connection($this->connection)->table($table)->useWritePdo(); } /** * Set the connection to be used. * * @param string $connection * @return void */ public function setConnection($connection) { $this->connection = $connection; } } validation/Rules/Unique.php 0000644 00000003031 14736103231 0011744 0 ustar 00 <?php namespace Illuminate\Validation\Rules; use Illuminate\Database\Eloquent\Model; class Unique { use DatabaseRule; /** * The ID that should be ignored. * * @var mixed */ protected $ignore; /** * The name of the ID column. * * @var string */ protected $idColumn = 'id'; /** * Ignore the given ID during the unique check. * * @param mixed $id * @param string|null $idColumn * @return $this */ public function ignore($id, $idColumn = null) { if ($id instanceof Model) { return $this->ignoreModel($id, $idColumn); } $this->ignore = $id; $this->idColumn = $idColumn ?? 'id'; return $this; } /** * Ignore the given model during the unique check. * * @param \Illuminate\Database\Eloquent\Model $model * @param string|null $idColumn * @return $this */ public function ignoreModel($model, $idColumn = null) { $this->idColumn = $idColumn ?? $model->getKeyName(); $this->ignore = $model->{$this->idColumn}; return $this; } /** * Convert the rule to a validation string. * * @return string */ public function __toString() { return rtrim(sprintf('unique:%s,%s,%s,%s,%s', $this->table, $this->column, $this->ignore ? '"'.addslashes($this->ignore).'"' : 'NULL', $this->idColumn, $this->formatWheres() ), ','); } } validation/Rules/RequiredIf.php 0000644 00000001363 14736103231 0012543 0 ustar 00 <?php namespace Illuminate\Validation\Rules; class RequiredIf { /** * The condition that validates the attribute. * * @var callable|bool */ public $condition; /** * Create a new required validation rule based on a condition. * * @param callable|bool $condition * @return void */ public function __construct($condition) { $this->condition = $condition; } /** * Convert the rule to a validation string. * * @return string */ public function __toString() { if (is_callable($this->condition)) { return call_user_func($this->condition) ? 'required' : ''; } return $this->condition ? 'required' : ''; } } validation/Rules/DatabaseRule.php 0000644 00000010103 14736103231 0013030 0 ustar 00 <?php namespace Illuminate\Validation\Rules; use Closure; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Str; trait DatabaseRule { /** * The table to run the query against. * * @var string */ protected $table; /** * The column to check on. * * @var string */ protected $column; /** * The extra where clauses for the query. * * @var array */ protected $wheres = []; /** * The array of custom query callbacks. * * @var array */ protected $using = []; /** * Create a new rule instance. * * @param string $table * @param string $column * @return void */ public function __construct($table, $column = 'NULL') { $this->column = $column; $this->table = $this->resolveTableName($table); } /** * Resolves the name of the table from the given string. * * @param string $table * @return string */ public function resolveTableName($table) { if (! Str::contains($table, '\\') || ! class_exists($table)) { return $table; } $model = new $table; return $model instanceof Model ? $model->getTable() : $table; } /** * Set a "where" constraint on the query. * * @param \Closure|string $column * @param array|string|null $value * @return $this */ public function where($column, $value = null) { if (is_array($value)) { return $this->whereIn($column, $value); } if ($column instanceof Closure) { return $this->using($column); } if (is_null($value)) { return $this->whereNull($column); } $this->wheres[] = compact('column', 'value'); return $this; } /** * Set a "where not" constraint on the query. * * @param string $column * @param array|string $value * @return $this */ public function whereNot($column, $value) { if (is_array($value)) { return $this->whereNotIn($column, $value); } return $this->where($column, '!'.$value); } /** * Set a "where null" constraint on the query. * * @param string $column * @return $this */ public function whereNull($column) { return $this->where($column, 'NULL'); } /** * Set a "where not null" constraint on the query. * * @param string $column * @return $this */ public function whereNotNull($column) { return $this->where($column, 'NOT_NULL'); } /** * Set a "where in" constraint on the query. * * @param string $column * @param array $values * @return $this */ public function whereIn($column, array $values) { return $this->where(function ($query) use ($column, $values) { $query->whereIn($column, $values); }); } /** * Set a "where not in" constraint on the query. * * @param string $column * @param array $values * @return $this */ public function whereNotIn($column, array $values) { return $this->where(function ($query) use ($column, $values) { $query->whereNotIn($column, $values); }); } /** * Register a custom query callback. * * @param \Closure $callback * @return $this */ public function using(Closure $callback) { $this->using[] = $callback; return $this; } /** * Get the custom query callbacks for the rule. * * @return array */ public function queryCallbacks() { return $this->using; } /** * Format the where clauses. * * @return string */ protected function formatWheres() { return collect($this->wheres)->map(function ($where) { return $where['column'].','.'"'.str_replace('"', '""', $where['value']).'"'; })->implode(','); } } validation/Rules/NotIn.php 0000644 00000001403 14736103231 0011526 0 ustar 00 <?php namespace Illuminate\Validation\Rules; class NotIn { /** * The name of the rule. */ protected $rule = 'not_in'; /** * The accepted values. * * @var array */ protected $values; /** * Create a new "not in" rule instance. * * @param array $values * @return void */ public function __construct(array $values) { $this->values = $values; } /** * Convert the rule to a validation string. * * @return string */ public function __toString() { $values = array_map(function ($value) { return '"'.str_replace('"', '""', $value).'"'; }, $this->values); return $this->rule.':'.implode(',', $values); } } validation/Rules/In.php 0000644 00000001506 14736103231 0011051 0 ustar 00 <?php namespace Illuminate\Validation\Rules; class In { /** * The name of the rule. */ protected $rule = 'in'; /** * The accepted values. * * @var array */ protected $values; /** * Create a new in rule instance. * * @param array $values * @return void */ public function __construct(array $values) { $this->values = $values; } /** * Convert the rule to a validation string. * * @return string * * @see \Illuminate\Validation\ValidationRuleParser::parseParameters */ public function __toString() { $values = array_map(function ($value) { return '"'.str_replace('"', '""', $value).'"'; }, $this->values); return $this->rule.':'.implode(',', $values); } } validation/Rules/Exists.php 0000644 00000000571 14736103231 0011763 0 ustar 00 <?php namespace Illuminate\Validation\Rules; class Exists { use DatabaseRule; /** * Convert the rule to a validation string. * * @return string */ public function __toString() { return rtrim(sprintf('exists:%s,%s,%s', $this->table, $this->column, $this->formatWheres() ), ','); } } validation/Rules/Dimensions.php 0000644 00000004467 14736103231 0012624 0 ustar 00 <?php namespace Illuminate\Validation\Rules; class Dimensions { /** * The constraints for the dimensions rule. * * @var array */ protected $constraints = []; /** * Create a new dimensions rule instance. * * @param array $constraints; * @return void */ public function __construct(array $constraints = []) { $this->constraints = $constraints; } /** * Set the "width" constraint. * * @param int $value * @return $this */ public function width($value) { $this->constraints['width'] = $value; return $this; } /** * Set the "height" constraint. * * @param int $value * @return $this */ public function height($value) { $this->constraints['height'] = $value; return $this; } /** * Set the "min width" constraint. * * @param int $value * @return $this */ public function minWidth($value) { $this->constraints['min_width'] = $value; return $this; } /** * Set the "min height" constraint. * * @param int $value * @return $this */ public function minHeight($value) { $this->constraints['min_height'] = $value; return $this; } /** * Set the "max width" constraint. * * @param int $value * @return $this */ public function maxWidth($value) { $this->constraints['max_width'] = $value; return $this; } /** * Set the "max height" constraint. * * @param int $value * @return $this */ public function maxHeight($value) { $this->constraints['max_height'] = $value; return $this; } /** * Set the "ratio" constraint. * * @param float $value * @return $this */ public function ratio($value) { $this->constraints['ratio'] = $value; return $this; } /** * Convert the rule to a validation string. * * @return string */ public function __toString() { $result = ''; foreach ($this->constraints as $key => $value) { $result .= "$key=$value,"; } return 'dimensions:'.substr($result, 0, -1); } } validation/ValidationServiceProvider.php 0000644 00000003250 14736103231 0014535 0 ustar 00 <?php namespace Illuminate\Validation; use Illuminate\Contracts\Support\DeferrableProvider; use Illuminate\Support\ServiceProvider; class ValidationServiceProvider extends ServiceProvider implements DeferrableProvider { /** * Register the service provider. * * @return void */ public function register() { $this->registerPresenceVerifier(); $this->registerValidationFactory(); } /** * Register the validation factory. * * @return void */ protected function registerValidationFactory() { $this->app->singleton('validator', function ($app) { $validator = new Factory($app['translator'], $app); // The validation presence verifier is responsible for determining the existence of // values in a given data collection which is typically a relational database or // other persistent data stores. It is used to check for "uniqueness" as well. if (isset($app['db'], $app['validation.presence'])) { $validator->setPresenceVerifier($app['validation.presence']); } return $validator; }); } /** * Register the database presence verifier. * * @return void */ protected function registerPresenceVerifier() { $this->app->singleton('validation.presence', function ($app) { return new DatabasePresenceVerifier($app['db']); }); } /** * Get the services provided by the provider. * * @return array */ public function provides() { return [ 'validator', 'validation.presence', ]; } } validation/ValidationRuleParser.php 0000644 00000015443 14736103231 0013515 0 ustar 00 <?php namespace Illuminate\Validation; use Closure; use Illuminate\Contracts\Validation\Rule as RuleContract; use Illuminate\Support\Arr; use Illuminate\Support\Str; use Illuminate\Validation\Rules\Exists; use Illuminate\Validation\Rules\Unique; class ValidationRuleParser { /** * The data being validated. * * @var array */ public $data; /** * The implicit attributes. * * @var array */ public $implicitAttributes = []; /** * Create a new validation rule parser. * * @param array $data * @return void */ public function __construct(array $data) { $this->data = $data; } /** * Parse the human-friendly rules into a full rules array for the validator. * * @param array $rules * @return \stdClass */ public function explode($rules) { $this->implicitAttributes = []; $rules = $this->explodeRules($rules); return (object) [ 'rules' => $rules, 'implicitAttributes' => $this->implicitAttributes, ]; } /** * Explode the rules into an array of explicit rules. * * @param array $rules * @return array */ protected function explodeRules($rules) { foreach ($rules as $key => $rule) { if (Str::contains($key, '*')) { $rules = $this->explodeWildcardRules($rules, $key, [$rule]); unset($rules[$key]); } else { $rules[$key] = $this->explodeExplicitRule($rule); } } return $rules; } /** * Explode the explicit rule into an array if necessary. * * @param mixed $rule * @return array */ protected function explodeExplicitRule($rule) { if (is_string($rule)) { return explode('|', $rule); } elseif (is_object($rule)) { return [$this->prepareRule($rule)]; } return array_map([$this, 'prepareRule'], $rule); } /** * Prepare the given rule for the Validator. * * @param mixed $rule * @return mixed */ protected function prepareRule($rule) { if ($rule instanceof Closure) { $rule = new ClosureValidationRule($rule); } if (! is_object($rule) || $rule instanceof RuleContract || ($rule instanceof Exists && $rule->queryCallbacks()) || ($rule instanceof Unique && $rule->queryCallbacks())) { return $rule; } return (string) $rule; } /** * Define a set of rules that apply to each element in an array attribute. * * @param array $results * @param string $attribute * @param string|array $rules * @return array */ protected function explodeWildcardRules($results, $attribute, $rules) { $pattern = str_replace('\*', '[^\.]*', preg_quote($attribute)); $data = ValidationData::initializeAndGatherData($attribute, $this->data); foreach ($data as $key => $value) { if (Str::startsWith($key, $attribute) || (bool) preg_match('/^'.$pattern.'\z/', $key)) { foreach ((array) $rules as $rule) { $this->implicitAttributes[$attribute][] = $key; $results = $this->mergeRules($results, $key, $rule); } } } return $results; } /** * Merge additional rules into a given attribute(s). * * @param array $results * @param string|array $attribute * @param string|array $rules * @return array */ public function mergeRules($results, $attribute, $rules = []) { if (is_array($attribute)) { foreach ((array) $attribute as $innerAttribute => $innerRules) { $results = $this->mergeRulesForAttribute($results, $innerAttribute, $innerRules); } return $results; } return $this->mergeRulesForAttribute( $results, $attribute, $rules ); } /** * Merge additional rules into a given attribute. * * @param array $results * @param string $attribute * @param string|array $rules * @return array */ protected function mergeRulesForAttribute($results, $attribute, $rules) { $merge = head($this->explodeRules([$rules])); $results[$attribute] = array_merge( isset($results[$attribute]) ? $this->explodeExplicitRule($results[$attribute]) : [], $merge ); return $results; } /** * Extract the rule name and parameters from a rule. * * @param array|string $rules * @return array */ public static function parse($rules) { if ($rules instanceof RuleContract) { return [$rules, []]; } if (is_array($rules)) { $rules = static::parseArrayRule($rules); } else { $rules = static::parseStringRule($rules); } $rules[0] = static::normalizeRule($rules[0]); return $rules; } /** * Parse an array based rule. * * @param array $rules * @return array */ protected static function parseArrayRule(array $rules) { return [Str::studly(trim(Arr::get($rules, 0))), array_slice($rules, 1)]; } /** * Parse a string based rule. * * @param string $rules * @return array */ protected static function parseStringRule($rules) { $parameters = []; // The format for specifying validation rules and parameters follows an // easy {rule}:{parameters} formatting convention. For instance the // rule "Max:3" states that the value may only be three letters. if (strpos($rules, ':') !== false) { [$rules, $parameter] = explode(':', $rules, 2); $parameters = static::parseParameters($rules, $parameter); } return [Str::studly(trim($rules)), $parameters]; } /** * Parse a parameter list. * * @param string $rule * @param string $parameter * @return array */ protected static function parseParameters($rule, $parameter) { $rule = strtolower($rule); if (in_array($rule, ['regex', 'not_regex', 'notregex'], true)) { return [$parameter]; } return str_getcsv($parameter); } /** * Normalizes a rule so that we can accept short types. * * @param string $rule * @return string */ protected static function normalizeRule($rule) { switch ($rule) { case 'Int': return 'Integer'; case 'Bool': return 'Boolean'; default: return $rule; } } } validation/Concerns/ValidatesAttributes.php 0000644 00000161601 14736103231 0015151 0 ustar 00 <?php namespace Illuminate\Validation\Concerns; use Countable; use DateTime; use DateTimeInterface; use Egulias\EmailValidator\EmailValidator; use Egulias\EmailValidator\Validation\DNSCheckValidation; use Egulias\EmailValidator\Validation\MultipleValidationWithAnd; use Egulias\EmailValidator\Validation\NoRFCWarningsValidation; use Egulias\EmailValidator\Validation\RFCValidation; use Egulias\EmailValidator\Validation\SpoofCheckValidation; use Exception; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Date; use Illuminate\Support\Str; use Illuminate\Validation\Rules\Exists; use Illuminate\Validation\Rules\Unique; use Illuminate\Validation\ValidationData; use InvalidArgumentException; use Symfony\Component\HttpFoundation\File\File; use Symfony\Component\HttpFoundation\File\UploadedFile; trait ValidatesAttributes { /** * Validate that an attribute was "accepted". * * This validation rule implies the attribute is "required". * * @param string $attribute * @param mixed $value * @return bool */ public function validateAccepted($attribute, $value) { $acceptable = ['yes', 'on', '1', 1, true, 'true']; return $this->validateRequired($attribute, $value) && in_array($value, $acceptable, true); } /** * Validate that an attribute is an active URL. * * @param string $attribute * @param mixed $value * @return bool */ public function validateActiveUrl($attribute, $value) { if (! is_string($value)) { return false; } if ($url = parse_url($value, PHP_URL_HOST)) { try { return count(dns_get_record($url, DNS_A | DNS_AAAA)) > 0; } catch (Exception $e) { return false; } } return false; } /** * "Break" on first validation fail. * * Always returns true, just lets us put "bail" in rules. * * @return bool */ public function validateBail() { return true; } /** * Validate the date is before a given date. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateBefore($attribute, $value, $parameters) { $this->requireParameterCount(1, $parameters, 'before'); return $this->compareDates($attribute, $value, $parameters, '<'); } /** * Validate the date is before or equal a given date. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateBeforeOrEqual($attribute, $value, $parameters) { $this->requireParameterCount(1, $parameters, 'before_or_equal'); return $this->compareDates($attribute, $value, $parameters, '<='); } /** * Validate the date is after a given date. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateAfter($attribute, $value, $parameters) { $this->requireParameterCount(1, $parameters, 'after'); return $this->compareDates($attribute, $value, $parameters, '>'); } /** * Validate the date is equal or after a given date. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateAfterOrEqual($attribute, $value, $parameters) { $this->requireParameterCount(1, $parameters, 'after_or_equal'); return $this->compareDates($attribute, $value, $parameters, '>='); } /** * Compare a given date against another using an operator. * * @param string $attribute * @param mixed $value * @param array $parameters * @param string $operator * @return bool */ protected function compareDates($attribute, $value, $parameters, $operator) { if (! is_string($value) && ! is_numeric($value) && ! $value instanceof DateTimeInterface) { return false; } if ($format = $this->getDateFormat($attribute)) { return $this->checkDateTimeOrder($format, $value, $parameters[0], $operator); } if (! $date = $this->getDateTimestamp($parameters[0])) { $date = $this->getDateTimestamp($this->getValue($parameters[0])); } return $this->compare($this->getDateTimestamp($value), $date, $operator); } /** * Get the date format for an attribute if it has one. * * @param string $attribute * @return string|null */ protected function getDateFormat($attribute) { if ($result = $this->getRule($attribute, 'DateFormat')) { return $result[1][0]; } } /** * Get the date timestamp. * * @param mixed $value * @return int */ protected function getDateTimestamp($value) { if ($value instanceof DateTimeInterface) { return $value->getTimestamp(); } if ($this->isTestingRelativeDateTime($value)) { $date = $this->getDateTime($value); if (! is_null($date)) { return $date->getTimestamp(); } } return strtotime($value); } /** * Given two date/time strings, check that one is after the other. * * @param string $format * @param string $first * @param string $second * @param string $operator * @return bool */ protected function checkDateTimeOrder($format, $first, $second, $operator) { $firstDate = $this->getDateTimeWithOptionalFormat($format, $first); if (! $secondDate = $this->getDateTimeWithOptionalFormat($format, $second)) { $secondDate = $this->getDateTimeWithOptionalFormat($format, $this->getValue($second)); } return ($firstDate && $secondDate) && ($this->compare($firstDate, $secondDate, $operator)); } /** * Get a DateTime instance from a string. * * @param string $format * @param string $value * @return \DateTime|null */ protected function getDateTimeWithOptionalFormat($format, $value) { if ($date = DateTime::createFromFormat('!'.$format, $value)) { return $date; } return $this->getDateTime($value); } /** * Get a DateTime instance from a string with no format. * * @param string $value * @return \DateTime|null */ protected function getDateTime($value) { try { if ($this->isTestingRelativeDateTime($value)) { return Date::parse($value); } return date_create($value) ?: null; } catch (Exception $e) { // } } /** * Check if the given value should be adjusted to Carbon::getTestNow(). * * @param mixed $value * @return bool */ protected function isTestingRelativeDateTime($value) { return Carbon::hasTestNow() && is_string($value) && ( $value === 'now' || Carbon::hasRelativeKeywords($value) ); } /** * Validate that an attribute contains only alphabetic characters. * * @param string $attribute * @param mixed $value * @return bool */ public function validateAlpha($attribute, $value) { return is_string($value) && preg_match('/^[\pL\pM]+$/u', $value); } /** * Validate that an attribute contains only alpha-numeric characters, dashes, and underscores. * * @param string $attribute * @param mixed $value * @return bool */ public function validateAlphaDash($attribute, $value) { if (! is_string($value) && ! is_numeric($value)) { return false; } return preg_match('/^[\pL\pM\pN_-]+$/u', $value) > 0; } /** * Validate that an attribute contains only alpha-numeric characters. * * @param string $attribute * @param mixed $value * @return bool */ public function validateAlphaNum($attribute, $value) { if (! is_string($value) && ! is_numeric($value)) { return false; } return preg_match('/^[\pL\pM\pN]+$/u', $value) > 0; } /** * Validate that an attribute is an array. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateArray($attribute, $value, $parameters = []) { if (! is_array($value)) { return false; } if (empty($parameters)) { return true; } return empty(array_diff_key($value, array_fill_keys($parameters, ''))); } /** * Validate the size of an attribute is between a set of values. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateBetween($attribute, $value, $parameters) { $this->requireParameterCount(2, $parameters, 'between'); $size = $this->getSize($attribute, $value); return $size >= $parameters[0] && $size <= $parameters[1]; } /** * Validate that an attribute is a boolean. * * @param string $attribute * @param mixed $value * @return bool */ public function validateBoolean($attribute, $value) { $acceptable = [true, false, 0, 1, '0', '1']; return in_array($value, $acceptable, true); } /** * Validate that an attribute has a matching confirmation. * * @param string $attribute * @param mixed $value * @return bool */ public function validateConfirmed($attribute, $value) { return $this->validateSame($attribute, $value, [$attribute.'_confirmation']); } /** * Validate that an attribute is a valid date. * * @param string $attribute * @param mixed $value * @return bool */ public function validateDate($attribute, $value) { if ($value instanceof DateTimeInterface) { return true; } if ((! is_string($value) && ! is_numeric($value)) || strtotime($value) === false) { return false; } $date = date_parse($value); return checkdate($date['month'], $date['day'], $date['year']); } /** * Validate that an attribute matches a date format. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateDateFormat($attribute, $value, $parameters) { $this->requireParameterCount(1, $parameters, 'date_format'); if (! is_string($value) && ! is_numeric($value)) { return false; } $format = $parameters[0]; $date = DateTime::createFromFormat('!'.$format, $value); return $date && $date->format($format) == $value; } /** * Validate that an attribute is equal to another date. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateDateEquals($attribute, $value, $parameters) { $this->requireParameterCount(1, $parameters, 'date_equals'); return $this->compareDates($attribute, $value, $parameters, '='); } /** * Validate that an attribute is different from another attribute. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateDifferent($attribute, $value, $parameters) { $this->requireParameterCount(1, $parameters, 'different'); foreach ($parameters as $parameter) { if (Arr::has($this->data, $parameter)) { $other = Arr::get($this->data, $parameter); if ($value === $other) { return false; } } } return true; } /** * Validate that an attribute has a given number of digits. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateDigits($attribute, $value, $parameters) { $this->requireParameterCount(1, $parameters, 'digits'); return ! preg_match('/[^0-9]/', $value) && strlen((string) $value) == $parameters[0]; } /** * Validate that an attribute is between a given number of digits. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateDigitsBetween($attribute, $value, $parameters) { $this->requireParameterCount(2, $parameters, 'digits_between'); $length = strlen((string) $value); return ! preg_match('/[^0-9]/', $value) && $length >= $parameters[0] && $length <= $parameters[1]; } /** * Validate the dimensions of an image matches the given values. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateDimensions($attribute, $value, $parameters) { if ($this->isValidFileInstance($value) && in_array($value->getMimeType(), ['image/svg+xml', 'image/svg'])) { return true; } if (! $this->isValidFileInstance($value) || ! $sizeDetails = @getimagesize($value->getRealPath())) { return false; } $this->requireParameterCount(1, $parameters, 'dimensions'); [$width, $height] = $sizeDetails; $parameters = $this->parseNamedParameters($parameters); if ($this->failsBasicDimensionChecks($parameters, $width, $height) || $this->failsRatioCheck($parameters, $width, $height)) { return false; } return true; } /** * Test if the given width and height fail any conditions. * * @param array $parameters * @param int $width * @param int $height * @return bool */ protected function failsBasicDimensionChecks($parameters, $width, $height) { return (isset($parameters['width']) && $parameters['width'] != $width) || (isset($parameters['min_width']) && $parameters['min_width'] > $width) || (isset($parameters['max_width']) && $parameters['max_width'] < $width) || (isset($parameters['height']) && $parameters['height'] != $height) || (isset($parameters['min_height']) && $parameters['min_height'] > $height) || (isset($parameters['max_height']) && $parameters['max_height'] < $height); } /** * Determine if the given parameters fail a dimension ratio check. * * @param array $parameters * @param int $width * @param int $height * @return bool */ protected function failsRatioCheck($parameters, $width, $height) { if (! isset($parameters['ratio'])) { return false; } [$numerator, $denominator] = array_replace( [1, 1], array_filter(sscanf($parameters['ratio'], '%f/%d')) ); $precision = 1 / max($width, $height); return abs($numerator / $denominator - $width / $height) > $precision; } /** * Validate an attribute is unique among other values. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateDistinct($attribute, $value, $parameters) { $data = Arr::except($this->getDistinctValues($attribute), $attribute); if (in_array('ignore_case', $parameters)) { return empty(preg_grep('/^'.preg_quote($value, '/').'$/iu', $data)); } return ! in_array($value, array_values($data)); } /** * Get the values to distinct between. * * @param string $attribute * @return array */ protected function getDistinctValues($attribute) { $attributeName = $this->getPrimaryAttribute($attribute); if (! property_exists($this, 'distinctValues')) { return $this->extractDistinctValues($attributeName); } if (! array_key_exists($attributeName, $this->distinctValues)) { $this->distinctValues[$attributeName] = $this->extractDistinctValues($attributeName); } return $this->distinctValues[$attributeName]; } /** * Extract the distinct values from the data. * * @param string $attribute * @return array */ protected function extractDistinctValues($attribute) { $attributeData = ValidationData::extractDataFromPath( ValidationData::getLeadingExplicitAttributePath($attribute), $this->data ); $pattern = str_replace('\*', '[^.]+', preg_quote($attribute, '#')); return Arr::where(Arr::dot($attributeData), function ($value, $key) use ($pattern) { return (bool) preg_match('#^'.$pattern.'\z#u', $key); }); } /** * Validate that an attribute is a valid e-mail address. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateEmail($attribute, $value, $parameters) { if (! is_string($value) && ! (is_object($value) && method_exists($value, '__toString'))) { return false; } $validations = collect($parameters) ->unique() ->map(function ($validation) { if ($validation === 'rfc') { return new RFCValidation(); } elseif ($validation === 'strict') { return new NoRFCWarningsValidation(); } elseif ($validation === 'dns') { return new DNSCheckValidation(); } elseif ($validation === 'spoof') { return new SpoofCheckValidation(); } elseif ($validation === 'filter') { return new FilterEmailValidation(); } elseif ($validation === 'filter_unicode') { return FilterEmailValidation::unicode(); } }) ->values() ->all() ?: [new RFCValidation()]; return (new EmailValidator)->isValid($value, new MultipleValidationWithAnd($validations)); } /** * Validate the existence of an attribute value in a database table. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateExists($attribute, $value, $parameters) { $this->requireParameterCount(1, $parameters, 'exists'); [$connection, $table] = $this->parseTable($parameters[0]); // The second parameter position holds the name of the column that should be // verified as existing. If this parameter is not specified we will guess // that the columns being "verified" shares the given attribute's name. $column = $this->getQueryColumn($parameters, $attribute); $expected = is_array($value) ? count(array_unique($value)) : 1; return $this->getExistCount( $connection, $table, $column, $value, $parameters ) >= $expected; } /** * Get the number of records that exist in storage. * * @param mixed $connection * @param string $table * @param string $column * @param mixed $value * @param array $parameters * @return int */ protected function getExistCount($connection, $table, $column, $value, $parameters) { $verifier = $this->getPresenceVerifier($connection); $extra = $this->getExtraConditions( array_values(array_slice($parameters, 2)) ); if ($this->currentRule instanceof Exists) { $extra = array_merge($extra, $this->currentRule->queryCallbacks()); } return is_array($value) ? $verifier->getMultiCount($table, $column, $value, $extra) : $verifier->getCount($table, $column, $value, null, null, $extra); } /** * Validate the uniqueness of an attribute value on a given database table. * * If a database column is not specified, the attribute will be used. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateUnique($attribute, $value, $parameters) { $this->requireParameterCount(1, $parameters, 'unique'); [$connection, $table] = $this->parseTable($parameters[0]); // The second parameter position holds the name of the column that needs to // be verified as unique. If this parameter isn't specified we will just // assume that this column to be verified shares the attribute's name. $column = $this->getQueryColumn($parameters, $attribute); [$idColumn, $id] = [null, null]; if (isset($parameters[2])) { [$idColumn, $id] = $this->getUniqueIds($parameters); if (! is_null($id)) { $id = stripslashes($id); } } // The presence verifier is responsible for counting rows within this store // mechanism which might be a relational database or any other permanent // data store like Redis, etc. We will use it to determine uniqueness. $verifier = $this->getPresenceVerifier($connection); $extra = $this->getUniqueExtra($parameters); if ($this->currentRule instanceof Unique) { $extra = array_merge($extra, $this->currentRule->queryCallbacks()); } return $verifier->getCount( $table, $column, $value, $id, $idColumn, $extra ) == 0; } /** * Get the excluded ID column and value for the unique rule. * * @param array $parameters * @return array */ protected function getUniqueIds($parameters) { $idColumn = $parameters[3] ?? 'id'; return [$idColumn, $this->prepareUniqueId($parameters[2])]; } /** * Prepare the given ID for querying. * * @param mixed $id * @return int */ protected function prepareUniqueId($id) { if (preg_match('/\[(.*)\]/', $id, $matches)) { $id = $this->getValue($matches[1]); } if (strtolower($id) === 'null') { $id = null; } if (filter_var($id, FILTER_VALIDATE_INT) !== false) { $id = (int) $id; } return $id; } /** * Get the extra conditions for a unique rule. * * @param array $parameters * @return array */ protected function getUniqueExtra($parameters) { if (isset($parameters[4])) { return $this->getExtraConditions(array_slice($parameters, 4)); } return []; } /** * Parse the connection / table for the unique / exists rules. * * @param string $table * @return array */ public function parseTable($table) { [$connection, $table] = Str::contains($table, '.') ? explode('.', $table, 2) : [null, $table]; if (Str::contains($table, '\\') && class_exists($table) && is_a($table, Model::class, true)) { $model = new $table; $table = $model->getTable(); $connection = $connection ?? $model->getConnectionName(); } return [$connection, $table]; } /** * Get the column name for an exists / unique query. * * @param array $parameters * @param string $attribute * @return bool */ public function getQueryColumn($parameters, $attribute) { return isset($parameters[1]) && $parameters[1] !== 'NULL' ? $parameters[1] : $this->guessColumnForQuery($attribute); } /** * Guess the database column from the given attribute name. * * @param string $attribute * @return string */ public function guessColumnForQuery($attribute) { if (in_array($attribute, Arr::collapse($this->implicitAttributes)) && ! is_numeric($last = last(explode('.', $attribute)))) { return $last; } return $attribute; } /** * Get the extra conditions for a unique / exists rule. * * @param array $segments * @return array */ protected function getExtraConditions(array $segments) { $extra = []; $count = count($segments); for ($i = 0; $i < $count; $i += 2) { $extra[$segments[$i]] = $segments[$i + 1]; } return $extra; } /** * Validate the given value is a valid file. * * @param string $attribute * @param mixed $value * @return bool */ public function validateFile($attribute, $value) { return $this->isValidFileInstance($value); } /** * Validate the given attribute is filled if it is present. * * @param string $attribute * @param mixed $value * @return bool */ public function validateFilled($attribute, $value) { if (Arr::has($this->data, $attribute)) { return $this->validateRequired($attribute, $value); } return true; } /** * Validate that an attribute is greater than another attribute. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateGt($attribute, $value, $parameters) { $this->requireParameterCount(1, $parameters, 'gt'); $comparedToValue = $this->getValue($parameters[0]); $this->shouldBeNumeric($attribute, 'Gt'); if (is_null($comparedToValue) && (is_numeric($value) && is_numeric($parameters[0]))) { return $this->getSize($attribute, $value) > $parameters[0]; } if ($this->hasRule($attribute, $this->numericRules) && is_numeric($value) && is_numeric($comparedToValue)) { return $value > $comparedToValue; } if (! $this->isSameType($value, $comparedToValue)) { return false; } return $this->getSize($attribute, $value) > $this->getSize($attribute, $comparedToValue); } /** * Validate that an attribute is less than another attribute. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateLt($attribute, $value, $parameters) { $this->requireParameterCount(1, $parameters, 'lt'); $comparedToValue = $this->getValue($parameters[0]); $this->shouldBeNumeric($attribute, 'Lt'); if (is_null($comparedToValue) && (is_numeric($value) && is_numeric($parameters[0]))) { return $this->getSize($attribute, $value) < $parameters[0]; } if ($this->hasRule($attribute, $this->numericRules) && is_numeric($value) && is_numeric($comparedToValue)) { return $value < $comparedToValue; } if (! $this->isSameType($value, $comparedToValue)) { return false; } return $this->getSize($attribute, $value) < $this->getSize($attribute, $comparedToValue); } /** * Validate that an attribute is greater than or equal another attribute. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateGte($attribute, $value, $parameters) { $this->requireParameterCount(1, $parameters, 'gte'); $comparedToValue = $this->getValue($parameters[0]); $this->shouldBeNumeric($attribute, 'Gte'); if (is_null($comparedToValue) && (is_numeric($value) && is_numeric($parameters[0]))) { return $this->getSize($attribute, $value) >= $parameters[0]; } if ($this->hasRule($attribute, $this->numericRules) && is_numeric($value) && is_numeric($comparedToValue)) { return $value >= $comparedToValue; } if (! $this->isSameType($value, $comparedToValue)) { return false; } return $this->getSize($attribute, $value) >= $this->getSize($attribute, $comparedToValue); } /** * Validate that an attribute is less than or equal another attribute. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateLte($attribute, $value, $parameters) { $this->requireParameterCount(1, $parameters, 'lte'); $comparedToValue = $this->getValue($parameters[0]); $this->shouldBeNumeric($attribute, 'Lte'); if (is_null($comparedToValue) && (is_numeric($value) && is_numeric($parameters[0]))) { return $this->getSize($attribute, $value) <= $parameters[0]; } if ($this->hasRule($attribute, $this->numericRules) && is_numeric($value) && is_numeric($comparedToValue)) { return $value <= $comparedToValue; } if (! $this->isSameType($value, $comparedToValue)) { return false; } return $this->getSize($attribute, $value) <= $this->getSize($attribute, $comparedToValue); } /** * Validate the MIME type of a file is an image MIME type. * * @param string $attribute * @param mixed $value * @return bool */ public function validateImage($attribute, $value) { return $this->validateMimes($attribute, $value, ['jpeg', 'png', 'gif', 'bmp', 'svg', 'webp']); } /** * Validate an attribute is contained within a list of values. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateIn($attribute, $value, $parameters) { if (is_array($value) && $this->hasRule($attribute, 'Array')) { foreach ($value as $element) { if (is_array($element)) { return false; } } return count(array_diff($value, $parameters)) === 0; } return ! is_array($value) && in_array((string) $value, $parameters); } /** * Validate that the values of an attribute is in another attribute. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateInArray($attribute, $value, $parameters) { $this->requireParameterCount(1, $parameters, 'in_array'); $explicitPath = ValidationData::getLeadingExplicitAttributePath($parameters[0]); $attributeData = ValidationData::extractDataFromPath($explicitPath, $this->data); $otherValues = Arr::where(Arr::dot($attributeData), function ($value, $key) use ($parameters) { return Str::is($parameters[0], $key); }); return in_array($value, $otherValues); } /** * Validate that an attribute is an integer. * * @param string $attribute * @param mixed $value * @return bool */ public function validateInteger($attribute, $value) { return filter_var($value, FILTER_VALIDATE_INT) !== false; } /** * Validate that an attribute is a valid IP. * * @param string $attribute * @param mixed $value * @return bool */ public function validateIp($attribute, $value) { return filter_var($value, FILTER_VALIDATE_IP) !== false; } /** * Validate that an attribute is a valid IPv4. * * @param string $attribute * @param mixed $value * @return bool */ public function validateIpv4($attribute, $value) { return filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false; } /** * Validate that an attribute is a valid IPv6. * * @param string $attribute * @param mixed $value * @return bool */ public function validateIpv6($attribute, $value) { return filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false; } /** * Validate the attribute is a valid JSON string. * * @param string $attribute * @param mixed $value * @return bool */ public function validateJson($attribute, $value) { if (! is_scalar($value) && ! method_exists($value, '__toString')) { return false; } json_decode($value); return json_last_error() === JSON_ERROR_NONE; } /** * Validate the size of an attribute is less than a maximum value. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateMax($attribute, $value, $parameters) { $this->requireParameterCount(1, $parameters, 'max'); if ($value instanceof UploadedFile && ! $value->isValid()) { return false; } return $this->getSize($attribute, $value) <= $parameters[0]; } /** * Validate the guessed extension of a file upload is in a set of file extensions. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateMimes($attribute, $value, $parameters) { if (! $this->isValidFileInstance($value)) { return false; } if ($this->shouldBlockPhpUpload($value, $parameters)) { return false; } return $value->getPath() !== '' && in_array($value->guessExtension(), $parameters); } /** * Validate the MIME type of a file upload attribute is in a set of MIME types. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateMimetypes($attribute, $value, $parameters) { if (! $this->isValidFileInstance($value)) { return false; } if ($this->shouldBlockPhpUpload($value, $parameters)) { return false; } return $value->getPath() !== '' && (in_array($value->getMimeType(), $parameters) || in_array(explode('/', $value->getMimeType())[0].'/*', $parameters)); } /** * Check if PHP uploads are explicitly allowed. * * @param mixed $value * @param array $parameters * @return bool */ protected function shouldBlockPhpUpload($value, $parameters) { if (in_array('php', $parameters)) { return false; } $phpExtensions = [ 'php', 'php3', 'php4', 'php5', 'phtml', ]; return ($value instanceof UploadedFile) ? in_array(trim(strtolower($value->getClientOriginalExtension())), $phpExtensions) : in_array(trim(strtolower($value->getExtension())), $phpExtensions); } /** * Validate the size of an attribute is greater than a minimum value. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateMin($attribute, $value, $parameters) { $this->requireParameterCount(1, $parameters, 'min'); return $this->getSize($attribute, $value) >= $parameters[0]; } /** * "Indicate" validation should pass if value is null. * * Always returns true, just lets us put "nullable" in rules. * * @return bool */ public function validateNullable() { return true; } /** * Validate an attribute is not contained within a list of values. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateNotIn($attribute, $value, $parameters) { return ! $this->validateIn($attribute, $value, $parameters); } /** * Validate that an attribute is numeric. * * @param string $attribute * @param mixed $value * @return bool */ public function validateNumeric($attribute, $value) { return is_numeric($value); } /** * Validate that the current logged in user's password matches the given value. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ protected function validatePassword($attribute, $value, $parameters) { $auth = $this->container->make('auth'); $hasher = $this->container->make('hash'); $guard = $auth->guard(Arr::first($parameters)); if ($guard->guest()) { return false; } return $hasher->check($value, $guard->user()->getAuthPassword()); } /** * Validate that an attribute exists even if not filled. * * @param string $attribute * @param mixed $value * @return bool */ public function validatePresent($attribute, $value) { return Arr::has($this->data, $attribute); } /** * Validate that an attribute passes a regular expression check. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateRegex($attribute, $value, $parameters) { if (! is_string($value) && ! is_numeric($value)) { return false; } $this->requireParameterCount(1, $parameters, 'regex'); return preg_match($parameters[0], $value) > 0; } /** * Validate that an attribute does not pass a regular expression check. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateNotRegex($attribute, $value, $parameters) { if (! is_string($value) && ! is_numeric($value)) { return false; } $this->requireParameterCount(1, $parameters, 'not_regex'); return preg_match($parameters[0], $value) < 1; } /** * Validate that a required attribute exists. * * @param string $attribute * @param mixed $value * @return bool */ public function validateRequired($attribute, $value) { if (is_null($value)) { return false; } elseif (is_string($value) && trim($value) === '') { return false; } elseif ((is_array($value) || $value instanceof Countable) && count($value) < 1) { return false; } elseif ($value instanceof File) { return (string) $value->getPath() !== ''; } return true; } /** * Validate that an attribute exists when another attribute has a given value. * * @param string $attribute * @param mixed $value * @param mixed $parameters * @return bool */ public function validateRequiredIf($attribute, $value, $parameters) { $this->requireParameterCount(2, $parameters, 'required_if'); [$values, $other] = $this->prepareValuesAndOther($parameters); if (in_array($other, $values)) { return $this->validateRequired($attribute, $value); } return true; } /** * Indicate that an attribute should be excluded when another attribute has a given value. * * @param string $attribute * @param mixed $value * @param mixed $parameters * @return bool */ public function validateExcludeIf($attribute, $value, $parameters) { $this->requireParameterCount(2, $parameters, 'exclude_if'); [$values, $other] = $this->prepareValuesAndOther($parameters); return ! in_array($other, $values); } /** * Indicate that an attribute should be excluded when another attribute does not have a given value. * * @param string $attribute * @param mixed $value * @param mixed $parameters * @return bool */ public function validateExcludeUnless($attribute, $value, $parameters) { $this->requireParameterCount(2, $parameters, 'exclude_unless'); [$values, $other] = $this->prepareValuesAndOther($parameters); return in_array($other, $values); } /** * Indicate that an attribute should be excluded when another attribute is missing. * * @param string $attribute * @param mixed $value * @param mixed $parameters * @return bool */ public function validateExcludeWithout($attribute, $value, $parameters) { $this->requireParameterCount(1, $parameters, 'exclude_without'); if ($this->anyFailingRequired($parameters)) { return false; } return true; } /** * Prepare the values and the other value for validation. * * @param array $parameters * @return array */ protected function prepareValuesAndOther($parameters) { $other = Arr::get($this->data, $parameters[0]); $values = array_slice($parameters, 1); if (is_bool($other)) { $values = $this->convertValuesToBoolean($values); } return [$values, $other]; } /** * Convert the given values to boolean if they are string "true" / "false". * * @param array $values * @return array */ protected function convertValuesToBoolean($values) { return array_map(function ($value) { if ($value === 'true') { return true; } elseif ($value === 'false') { return false; } return $value; }, $values); } /** * Validate that an attribute exists when another attribute does not have a given value. * * @param string $attribute * @param mixed $value * @param mixed $parameters * @return bool */ public function validateRequiredUnless($attribute, $value, $parameters) { $this->requireParameterCount(2, $parameters, 'required_unless'); $data = Arr::get($this->data, $parameters[0]); $values = array_slice($parameters, 1); if (! in_array($data, $values)) { return $this->validateRequired($attribute, $value); } return true; } /** * Validate that an attribute exists when any other attribute exists. * * @param string $attribute * @param mixed $value * @param mixed $parameters * @return bool */ public function validateRequiredWith($attribute, $value, $parameters) { if (! $this->allFailingRequired($parameters)) { return $this->validateRequired($attribute, $value); } return true; } /** * Validate that an attribute exists when all other attributes exists. * * @param string $attribute * @param mixed $value * @param mixed $parameters * @return bool */ public function validateRequiredWithAll($attribute, $value, $parameters) { if (! $this->anyFailingRequired($parameters)) { return $this->validateRequired($attribute, $value); } return true; } /** * Validate that an attribute exists when another attribute does not. * * @param string $attribute * @param mixed $value * @param mixed $parameters * @return bool */ public function validateRequiredWithout($attribute, $value, $parameters) { if ($this->anyFailingRequired($parameters)) { return $this->validateRequired($attribute, $value); } return true; } /** * Validate that an attribute exists when all other attributes do not. * * @param string $attribute * @param mixed $value * @param mixed $parameters * @return bool */ public function validateRequiredWithoutAll($attribute, $value, $parameters) { if ($this->allFailingRequired($parameters)) { return $this->validateRequired($attribute, $value); } return true; } /** * Determine if any of the given attributes fail the required test. * * @param array $attributes * @return bool */ protected function anyFailingRequired(array $attributes) { foreach ($attributes as $key) { if (! $this->validateRequired($key, $this->getValue($key))) { return true; } } return false; } /** * Determine if all of the given attributes fail the required test. * * @param array $attributes * @return bool */ protected function allFailingRequired(array $attributes) { foreach ($attributes as $key) { if ($this->validateRequired($key, $this->getValue($key))) { return false; } } return true; } /** * Validate that two attributes match. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateSame($attribute, $value, $parameters) { $this->requireParameterCount(1, $parameters, 'same'); $other = Arr::get($this->data, $parameters[0]); return $value === $other; } /** * Validate the size of an attribute. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateSize($attribute, $value, $parameters) { $this->requireParameterCount(1, $parameters, 'size'); return $this->getSize($attribute, $value) == $parameters[0]; } /** * "Validate" optional attributes. * * Always returns true, just lets us put sometimes in rules. * * @return bool */ public function validateSometimes() { return true; } /** * Validate the attribute starts with a given substring. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateStartsWith($attribute, $value, $parameters) { return Str::startsWith($value, $parameters); } /** * Validate the attribute ends with a given substring. * * @param string $attribute * @param mixed $value * @param array $parameters * @return bool */ public function validateEndsWith($attribute, $value, $parameters) { return Str::endsWith($value, $parameters); } /** * Validate that an attribute is a string. * * @param string $attribute * @param mixed $value * @return bool */ public function validateString($attribute, $value) { return is_string($value); } /** * Validate that an attribute is a valid timezone. * * @param string $attribute * @param mixed $value * @return bool */ public function validateTimezone($attribute, $value) { return in_array($value, timezone_identifiers_list(), true); } /** * Validate that an attribute is a valid URL. * * @param string $attribute * @param mixed $value * @return bool */ public function validateUrl($attribute, $value) { if (! is_string($value)) { return false; } /* * This pattern is derived from Symfony\Component\Validator\Constraints\UrlValidator (5.0.7). * * (c) Fabien Potencier <fabien@symfony.com> http://symfony.com */ $pattern = '~^ (aaa|aaas|about|acap|acct|acd|acr|adiumxtra|adt|afp|afs|aim|amss|android|appdata|apt|ark|attachment|aw|barion|beshare|bitcoin|bitcoincash|blob|bolo|browserext|calculator|callto|cap|cast|casts|chrome|chrome-extension|cid|coap|coap\+tcp|coap\+ws|coaps|coaps\+tcp|coaps\+ws|com-eventbrite-attendee|content|conti|crid|cvs|dab|data|dav|diaspora|dict|did|dis|dlna-playcontainer|dlna-playsingle|dns|dntp|dpp|drm|drop|dtn|dvb|ed2k|elsi|example|facetime|fax|feed|feedready|file|filesystem|finger|first-run-pen-experience|fish|fm|ftp|fuchsia-pkg|geo|gg|git|gizmoproject|go|gopher|graph|gtalk|h323|ham|hcap|hcp|http|https|hxxp|hxxps|hydrazone|iax|icap|icon|im|imap|info|iotdisco|ipn|ipp|ipps|irc|irc6|ircs|iris|iris\.beep|iris\.lwz|iris\.xpc|iris\.xpcs|isostore|itms|jabber|jar|jms|keyparc|lastfm|ldap|ldaps|leaptofrogans|lorawan|lvlt|magnet|mailserver|mailto|maps|market|message|mid|mms|modem|mongodb|moz|ms-access|ms-browser-extension|ms-calculator|ms-drive-to|ms-enrollment|ms-excel|ms-eyecontrolspeech|ms-gamebarservices|ms-gamingoverlay|ms-getoffice|ms-help|ms-infopath|ms-inputapp|ms-lockscreencomponent-config|ms-media-stream-id|ms-mixedrealitycapture|ms-mobileplans|ms-officeapp|ms-people|ms-project|ms-powerpoint|ms-publisher|ms-restoretabcompanion|ms-screenclip|ms-screensketch|ms-search|ms-search-repair|ms-secondary-screen-controller|ms-secondary-screen-setup|ms-settings|ms-settings-airplanemode|ms-settings-bluetooth|ms-settings-camera|ms-settings-cellular|ms-settings-cloudstorage|ms-settings-connectabledevices|ms-settings-displays-topology|ms-settings-emailandaccounts|ms-settings-language|ms-settings-location|ms-settings-lock|ms-settings-nfctransactions|ms-settings-notifications|ms-settings-power|ms-settings-privacy|ms-settings-proximity|ms-settings-screenrotation|ms-settings-wifi|ms-settings-workplace|ms-spd|ms-sttoverlay|ms-transit-to|ms-useractivityset|ms-virtualtouchpad|ms-visio|ms-walk-to|ms-whiteboard|ms-whiteboard-cmd|ms-word|msnim|msrp|msrps|mss|mtqp|mumble|mupdate|mvn|news|nfs|ni|nih|nntp|notes|ocf|oid|onenote|onenote-cmd|opaquelocktoken|openpgp4fpr|pack|palm|paparazzi|payto|pkcs11|platform|pop|pres|prospero|proxy|pwid|psyc|pttp|qb|query|redis|rediss|reload|res|resource|rmi|rsync|rtmfp|rtmp|rtsp|rtsps|rtspu|s3|secondlife|service|session|sftp|sgn|shttp|sieve|simpleledger|sip|sips|skype|smb|sms|smtp|snews|snmp|soap\.beep|soap\.beeps|soldat|spiffe|spotify|ssh|steam|stun|stuns|submit|svn|tag|teamspeak|tel|teliaeid|telnet|tftp|things|thismessage|tip|tn3270|tool|turn|turns|tv|udp|unreal|urn|ut2004|v-event|vemmi|ventrilo|videotex|vnc|view-source|wais|webcal|wpid|ws|wss|wtai|wyciwyg|xcon|xcon-userid|xfire|xmlrpc\.beep|xmlrpc\.beeps|xmpp|xri|ymsgr|z39\.50|z39\.50r|z39\.50s):// # protocol (((?:[\_\.\pL\pN-]|%[0-9A-Fa-f]{2})+:)?((?:[\_\.\pL\pN-]|%[0-9A-Fa-f]{2})+)@)? # basic auth ( ([\pL\pN\pS\-\_\.])+(\.?([\pL\pN]|xn\-\-[\pL\pN-]+)+\.?) # a domain name | # or \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} # an IP address | # or \[ (?:(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){6})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:::(?:(?:(?:[0-9a-f]{1,4})):){5})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){4})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,1}(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){3})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,2}(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){2})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,3}(?:(?:[0-9a-f]{1,4})))?::(?:(?:[0-9a-f]{1,4})):)(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,4}(?:(?:[0-9a-f]{1,4})))?::)(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,5}(?:(?:[0-9a-f]{1,4})))?::)(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,6}(?:(?:[0-9a-f]{1,4})))?::)))) \] # an IPv6 address ) (:[0-9]+)? # a port (optional) (?:/ (?:[\pL\pN\-._\~!$&\'()*+,;=:@]|%[0-9A-Fa-f]{2})* )* # a path (?:\? (?:[\pL\pN\-._\~!$&\'\[\]()*+,;=:@/?]|%[0-9A-Fa-f]{2})* )? # a query (optional) (?:\# (?:[\pL\pN\-._\~!$&\'()*+,;=:@/?]|%[0-9A-Fa-f]{2})* )? # a fragment (optional) $~ixu'; return preg_match($pattern, $value) > 0; } /** * Validate that an attribute is a valid UUID. * * @param string $attribute * @param mixed $value * @return bool */ public function validateUuid($attribute, $value) { return Str::isUuid($value); } /** * Get the size of an attribute. * * @param string $attribute * @param mixed $value * @return mixed */ protected function getSize($attribute, $value) { $hasNumeric = $this->hasRule($attribute, $this->numericRules); // This method will determine if the attribute is a number, string, or file and // return the proper size accordingly. If it is a number, then number itself // is the size. If it is a file, we take kilobytes, and for a string the // entire length of the string will be considered the attribute size. if (is_numeric($value) && $hasNumeric) { return $value; } elseif (is_array($value)) { return count($value); } elseif ($value instanceof File) { return $value->getSize() / 1024; } return mb_strlen($value); } /** * Check that the given value is a valid file instance. * * @param mixed $value * @return bool */ public function isValidFileInstance($value) { if ($value instanceof UploadedFile && ! $value->isValid()) { return false; } return $value instanceof File; } /** * Determine if a comparison passes between the given values. * * @param mixed $first * @param mixed $second * @param string $operator * @return bool * * @throws \InvalidArgumentException */ protected function compare($first, $second, $operator) { switch ($operator) { case '<': return $first < $second; case '>': return $first > $second; case '<=': return $first <= $second; case '>=': return $first >= $second; case '=': return $first == $second; default: throw new InvalidArgumentException; } } /** * Parse named parameters to $key => $value items. * * @param array $parameters * @return array */ protected function parseNamedParameters($parameters) { return array_reduce($parameters, function ($result, $item) { [$key, $value] = array_pad(explode('=', $item, 2), 2, null); $result[$key] = $value; return $result; }); } /** * Require a certain number of parameters to be present. * * @param int $count * @param array $parameters * @param string $rule * @return void * * @throws \InvalidArgumentException */ public function requireParameterCount($count, $parameters, $rule) { if (count($parameters) < $count) { throw new InvalidArgumentException("Validation rule $rule requires at least $count parameters."); } } /** * Check if the parameters are of the same type. * * @param mixed $first * @param mixed $second * @return bool */ protected function isSameType($first, $second) { return gettype($first) == gettype($second); } /** * Adds the existing rule to the numericRules array if the attribute's value is numeric. * * @param string $attribute * @param string $rule * * @return void */ protected function shouldBeNumeric($attribute, $rule) { if (is_numeric($this->getValue($attribute))) { $this->numericRules[] = $rule; } } } validation/Concerns/FormatsMessages.php 0000644 00000031221 14736103231 0014263 0 ustar 00 <?php namespace Illuminate\Validation\Concerns; use Closure; use Illuminate\Support\Arr; use Illuminate\Support\Str; use Symfony\Component\HttpFoundation\File\UploadedFile; trait FormatsMessages { use ReplacesAttributes; /** * Get the validation message for an attribute and rule. * * @param string $attribute * @param string $rule * @return string */ protected function getMessage($attribute, $rule) { $inlineMessage = $this->getInlineMessage($attribute, $rule); // First we will retrieve the custom message for the validation rule if one // exists. If a custom validation message is being used we'll return the // custom message, otherwise we'll keep searching for a valid message. if (! is_null($inlineMessage)) { return $inlineMessage; } $lowerRule = Str::snake($rule); $customMessage = $this->getCustomMessageFromTranslator( $customKey = "validation.custom.{$attribute}.{$lowerRule}" ); // First we check for a custom defined validation message for the attribute // and rule. This allows the developer to specify specific messages for // only some attributes and rules that need to get specially formed. if ($customMessage !== $customKey) { return $customMessage; } // If the rule being validated is a "size" rule, we will need to gather the // specific error message for the type of attribute being validated such // as a number, file or string which all have different message types. elseif (in_array($rule, $this->sizeRules)) { return $this->getSizeMessage($attribute, $rule); } // Finally, if no developer specified messages have been set, and no other // special messages apply for this rule, we will just pull the default // messages out of the translator service for this validation rule. $key = "validation.{$lowerRule}"; if ($key != ($value = $this->translator->get($key))) { return $value; } return $this->getFromLocalArray( $attribute, $lowerRule, $this->fallbackMessages ) ?: $key; } /** * Get the proper inline error message for standard and size rules. * * @param string $attribute * @param string $rule * @return string|null */ protected function getInlineMessage($attribute, $rule) { $inlineEntry = $this->getFromLocalArray($attribute, Str::snake($rule)); return is_array($inlineEntry) && in_array($rule, $this->sizeRules) ? $inlineEntry[$this->getAttributeType($attribute)] : $inlineEntry; } /** * Get the inline message for a rule if it exists. * * @param string $attribute * @param string $lowerRule * @param array|null $source * @return string|null */ protected function getFromLocalArray($attribute, $lowerRule, $source = null) { $source = $source ?: $this->customMessages; $keys = ["{$attribute}.{$lowerRule}", $lowerRule]; // First we will check for a custom message for an attribute specific rule // message for the fields, then we will check for a general custom line // that is not attribute specific. If we find either we'll return it. foreach ($keys as $key) { foreach (array_keys($source) as $sourceKey) { if (Str::is($sourceKey, $key)) { return $source[$sourceKey]; } } } } /** * Get the custom error message from translator. * * @param string $key * @return string */ protected function getCustomMessageFromTranslator($key) { if (($message = $this->translator->get($key)) !== $key) { return $message; } // If an exact match was not found for the key, we will collapse all of these // messages and loop through them and try to find a wildcard match for the // given key. Otherwise, we will simply return the key's value back out. $shortKey = preg_replace( '/^validation\.custom\./', '', $key ); return $this->getWildcardCustomMessages(Arr::dot( (array) $this->translator->get('validation.custom') ), $shortKey, $key); } /** * Check the given messages for a wildcard key. * * @param array $messages * @param string $search * @param string $default * @return string */ protected function getWildcardCustomMessages($messages, $search, $default) { foreach ($messages as $key => $message) { if ($search === $key || (Str::contains($key, ['*']) && Str::is($key, $search))) { return $message; } } return $default; } /** * Get the proper error message for an attribute and size rule. * * @param string $attribute * @param string $rule * @return string */ protected function getSizeMessage($attribute, $rule) { $lowerRule = Str::snake($rule); // There are three different types of size validations. The attribute may be // either a number, file, or string so we will check a few things to know // which type of value it is and return the correct line for that type. $type = $this->getAttributeType($attribute); $key = "validation.{$lowerRule}.{$type}"; return $this->translator->get($key); } /** * Get the data type of the given attribute. * * @param string $attribute * @return string */ protected function getAttributeType($attribute) { // We assume that the attributes present in the file array are files so that // means that if the attribute does not have a numeric rule and the files // list doesn't have it we'll just consider it a string by elimination. if ($this->hasRule($attribute, $this->numericRules)) { return 'numeric'; } elseif ($this->hasRule($attribute, ['Array'])) { return 'array'; } elseif ($this->getValue($attribute) instanceof UploadedFile) { return 'file'; } return 'string'; } /** * Replace all error message place-holders with actual values. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ public function makeReplacements($message, $attribute, $rule, $parameters) { $message = $this->replaceAttributePlaceholder( $message, $this->getDisplayableAttribute($attribute) ); $message = $this->replaceInputPlaceholder($message, $attribute); if (isset($this->replacers[Str::snake($rule)])) { return $this->callReplacer($message, $attribute, Str::snake($rule), $parameters, $this); } elseif (method_exists($this, $replacer = "replace{$rule}")) { return $this->$replacer($message, $attribute, $rule, $parameters); } return $message; } /** * Get the displayable name of the attribute. * * @param string $attribute * @return string */ public function getDisplayableAttribute($attribute) { $primaryAttribute = $this->getPrimaryAttribute($attribute); $expectedAttributes = $attribute != $primaryAttribute ? [$attribute, $primaryAttribute] : [$attribute]; foreach ($expectedAttributes as $name) { // The developer may dynamically specify the array of custom attributes on this // validator instance. If the attribute exists in this array it is used over // the other ways of pulling the attribute name for this given attributes. if (isset($this->customAttributes[$name])) { return $this->customAttributes[$name]; } // We allow for a developer to specify language lines for any attribute in this // application, which allows flexibility for displaying a unique displayable // version of the attribute name instead of the name used in an HTTP POST. if ($line = $this->getAttributeFromTranslations($name)) { return $line; } } // When no language line has been specified for the attribute and it is also // an implicit attribute we will display the raw attribute's name and not // modify it with any of these replacements before we display the name. if (isset($this->implicitAttributes[$primaryAttribute])) { return ($formatter = $this->implicitAttributesFormatter) ? $formatter($attribute) : $attribute; } return str_replace('_', ' ', Str::snake($attribute)); } /** * Get the given attribute from the attribute translations. * * @param string $name * @return string */ protected function getAttributeFromTranslations($name) { return Arr::get($this->translator->get('validation.attributes'), $name); } /** * Replace the :attribute placeholder in the given message. * * @param string $message * @param string $value * @return string */ protected function replaceAttributePlaceholder($message, $value) { return str_replace( [':attribute', ':ATTRIBUTE', ':Attribute'], [$value, Str::upper($value), Str::ucfirst($value)], $message ); } /** * Replace the :input placeholder in the given message. * * @param string $message * @param string $attribute * @return string */ protected function replaceInputPlaceholder($message, $attribute) { $actualValue = $this->getValue($attribute); if (is_scalar($actualValue) || is_null($actualValue)) { $message = str_replace(':input', $this->getDisplayableValue($attribute, $actualValue), $message); } return $message; } /** * Get the displayable name of the value. * * @param string $attribute * @param mixed $value * @return string */ public function getDisplayableValue($attribute, $value) { if (isset($this->customValues[$attribute][$value])) { return $this->customValues[$attribute][$value]; } $key = "validation.values.{$attribute}.{$value}"; if (($line = $this->translator->get($key)) !== $key) { return $line; } if (is_bool($value)) { return $value ? 'true' : 'false'; } return $value; } /** * Transform an array of attributes to their displayable form. * * @param array $values * @return array */ protected function getAttributeList(array $values) { $attributes = []; // For each attribute in the list we will simply get its displayable form as // this is convenient when replacing lists of parameters like some of the // replacement functions do when formatting out the validation message. foreach ($values as $key => $value) { $attributes[$key] = $this->getDisplayableAttribute($value); } return $attributes; } /** * Call a custom validator message replacer. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @param \Illuminate\Validation\Validator $validator * @return string|null */ protected function callReplacer($message, $attribute, $rule, $parameters, $validator) { $callback = $this->replacers[$rule]; if ($callback instanceof Closure) { return call_user_func_array($callback, func_get_args()); } elseif (is_string($callback)) { return $this->callClassBasedReplacer($callback, $message, $attribute, $rule, $parameters, $validator); } } /** * Call a class based validator message replacer. * * @param string $callback * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @param \Illuminate\Validation\Validator $validator * @return string */ protected function callClassBasedReplacer($callback, $message, $attribute, $rule, $parameters, $validator) { [$class, $method] = Str::parseCallback($callback, 'replace'); return call_user_func_array([$this->container->make($class), $method], array_slice(func_get_args(), 1)); } } validation/Concerns/FilterEmailValidation.php 0000644 00000003054 14736103231 0015373 0 ustar 00 <?php namespace Illuminate\Validation\Concerns; use Egulias\EmailValidator\EmailLexer; use Egulias\EmailValidator\Validation\EmailValidation; class FilterEmailValidation implements EmailValidation { /** * The flags to pass to the filter_var function. * * @var int|null */ protected $flags; /** * Create a new validation instance. * * @param int $flags * @return void */ public function __construct($flags = null) { $this->flags = $flags; } /** * Create a new instance which allows any unicode characters in local-part. * * @return static */ public static function unicode() { return new static(FILTER_FLAG_EMAIL_UNICODE); } /** * Returns true if the given email is valid. * * @param string $email * @param \Egulias\EmailValidator\EmailLexer $emailLexer * @return bool */ public function isValid($email, EmailLexer $emailLexer) { return is_null($this->flags) ? filter_var($email, FILTER_VALIDATE_EMAIL) !== false : filter_var($email, FILTER_VALIDATE_EMAIL, $this->flags) !== false; } /** * Returns the validation error. * * @return \Egulias\EmailValidator\Exception\InvalidEmail|null */ public function getError() { // } /** * Returns the validation warnings. * * @return \Egulias\EmailValidator\Warning\Warning[] */ public function getWarnings() { return []; } } validation/Concerns/ReplacesAttributes.php 0000644 00000035113 14736103231 0014771 0 ustar 00 <?php namespace Illuminate\Validation\Concerns; use Illuminate\Support\Arr; trait ReplacesAttributes { /** * Replace all place-holders for the between rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceBetween($message, $attribute, $rule, $parameters) { return str_replace([':min', ':max'], $parameters, $message); } /** * Replace all place-holders for the date_format rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceDateFormat($message, $attribute, $rule, $parameters) { return str_replace(':format', $parameters[0], $message); } /** * Replace all place-holders for the different rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceDifferent($message, $attribute, $rule, $parameters) { return $this->replaceSame($message, $attribute, $rule, $parameters); } /** * Replace all place-holders for the digits rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceDigits($message, $attribute, $rule, $parameters) { return str_replace(':digits', $parameters[0], $message); } /** * Replace all place-holders for the digits (between) rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceDigitsBetween($message, $attribute, $rule, $parameters) { return $this->replaceBetween($message, $attribute, $rule, $parameters); } /** * Replace all place-holders for the min rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceMin($message, $attribute, $rule, $parameters) { return str_replace(':min', $parameters[0], $message); } /** * Replace all place-holders for the max rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceMax($message, $attribute, $rule, $parameters) { return str_replace(':max', $parameters[0], $message); } /** * Replace all place-holders for the in rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceIn($message, $attribute, $rule, $parameters) { foreach ($parameters as &$parameter) { $parameter = $this->getDisplayableValue($attribute, $parameter); } return str_replace(':values', implode(', ', $parameters), $message); } /** * Replace all place-holders for the not_in rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceNotIn($message, $attribute, $rule, $parameters) { return $this->replaceIn($message, $attribute, $rule, $parameters); } /** * Replace all place-holders for the in_array rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceInArray($message, $attribute, $rule, $parameters) { return str_replace(':other', $this->getDisplayableAttribute($parameters[0]), $message); } /** * Replace all place-holders for the mimetypes rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceMimetypes($message, $attribute, $rule, $parameters) { return str_replace(':values', implode(', ', $parameters), $message); } /** * Replace all place-holders for the mimes rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceMimes($message, $attribute, $rule, $parameters) { return str_replace(':values', implode(', ', $parameters), $message); } /** * Replace all place-holders for the required_with rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceRequiredWith($message, $attribute, $rule, $parameters) { return str_replace(':values', implode(' / ', $this->getAttributeList($parameters)), $message); } /** * Replace all place-holders for the required_with_all rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceRequiredWithAll($message, $attribute, $rule, $parameters) { return $this->replaceRequiredWith($message, $attribute, $rule, $parameters); } /** * Replace all place-holders for the required_without rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceRequiredWithout($message, $attribute, $rule, $parameters) { return $this->replaceRequiredWith($message, $attribute, $rule, $parameters); } /** * Replace all place-holders for the required_without_all rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceRequiredWithoutAll($message, $attribute, $rule, $parameters) { return $this->replaceRequiredWith($message, $attribute, $rule, $parameters); } /** * Replace all place-holders for the size rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceSize($message, $attribute, $rule, $parameters) { return str_replace(':size', $parameters[0], $message); } /** * Replace all place-holders for the gt rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceGt($message, $attribute, $rule, $parameters) { if (is_null($value = $this->getValue($parameters[0]))) { return str_replace(':value', $this->getDisplayableAttribute($parameters[0]), $message); } return str_replace(':value', $this->getSize($attribute, $value), $message); } /** * Replace all place-holders for the lt rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceLt($message, $attribute, $rule, $parameters) { if (is_null($value = $this->getValue($parameters[0]))) { return str_replace(':value', $this->getDisplayableAttribute($parameters[0]), $message); } return str_replace(':value', $this->getSize($attribute, $value), $message); } /** * Replace all place-holders for the gte rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceGte($message, $attribute, $rule, $parameters) { if (is_null($value = $this->getValue($parameters[0]))) { return str_replace(':value', $this->getDisplayableAttribute($parameters[0]), $message); } return str_replace(':value', $this->getSize($attribute, $value), $message); } /** * Replace all place-holders for the lte rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceLte($message, $attribute, $rule, $parameters) { if (is_null($value = $this->getValue($parameters[0]))) { return str_replace(':value', $this->getDisplayableAttribute($parameters[0]), $message); } return str_replace(':value', $this->getSize($attribute, $value), $message); } /** * Replace all place-holders for the required_if rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceRequiredIf($message, $attribute, $rule, $parameters) { $parameters[1] = $this->getDisplayableValue($parameters[0], Arr::get($this->data, $parameters[0])); $parameters[0] = $this->getDisplayableAttribute($parameters[0]); return str_replace([':other', ':value'], $parameters, $message); } /** * Replace all place-holders for the required_unless rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceRequiredUnless($message, $attribute, $rule, $parameters) { $other = $this->getDisplayableAttribute($parameters[0]); $values = []; foreach (array_slice($parameters, 1) as $value) { $values[] = $this->getDisplayableValue($parameters[0], $value); } return str_replace([':other', ':values'], [$other, implode(', ', $values)], $message); } /** * Replace all place-holders for the same rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceSame($message, $attribute, $rule, $parameters) { return str_replace(':other', $this->getDisplayableAttribute($parameters[0]), $message); } /** * Replace all place-holders for the before rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceBefore($message, $attribute, $rule, $parameters) { if (! strtotime($parameters[0])) { return str_replace(':date', $this->getDisplayableAttribute($parameters[0]), $message); } return str_replace(':date', $this->getDisplayableValue($attribute, $parameters[0]), $message); } /** * Replace all place-holders for the before_or_equal rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceBeforeOrEqual($message, $attribute, $rule, $parameters) { return $this->replaceBefore($message, $attribute, $rule, $parameters); } /** * Replace all place-holders for the after rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceAfter($message, $attribute, $rule, $parameters) { return $this->replaceBefore($message, $attribute, $rule, $parameters); } /** * Replace all place-holders for the after_or_equal rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceAfterOrEqual($message, $attribute, $rule, $parameters) { return $this->replaceBefore($message, $attribute, $rule, $parameters); } /** * Replace all place-holders for the date_equals rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceDateEquals($message, $attribute, $rule, $parameters) { return $this->replaceBefore($message, $attribute, $rule, $parameters); } /** * Replace all place-holders for the dimensions rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceDimensions($message, $attribute, $rule, $parameters) { $parameters = $this->parseNamedParameters($parameters); if (is_array($parameters)) { foreach ($parameters as $key => $value) { $message = str_replace(':'.$key, $value, $message); } } return $message; } /** * Replace all place-holders for the ends_with rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceEndsWith($message, $attribute, $rule, $parameters) { foreach ($parameters as &$parameter) { $parameter = $this->getDisplayableValue($attribute, $parameter); } return str_replace(':values', implode(', ', $parameters), $message); } /** * Replace all place-holders for the starts_with rule. * * @param string $message * @param string $attribute * @param string $rule * @param array $parameters * @return string */ protected function replaceStartsWith($message, $attribute, $rule, $parameters) { foreach ($parameters as &$parameter) { $parameter = $this->getDisplayableValue($attribute, $parameter); } return str_replace(':values', implode(', ', $parameters), $message); } } validation/DatabasePresenceVerifierInterface.php 0000644 00000000437 14736103231 0016121 0 ustar 00 <?php namespace Illuminate\Validation; interface DatabasePresenceVerifierInterface extends PresenceVerifierInterface { /** * Set the connection to be used. * * @param string $connection * @return void */ public function setConnection($connection); } validation/UnauthorizedException.php 0000644 00000000200 14736103231 0013737 0 ustar 00 <?php namespace Illuminate\Validation; use RuntimeException; class UnauthorizedException extends RuntimeException { // } validation/LICENSE.md 0000644 00000002063 14736103231 0010303 0 ustar 00 The MIT License (MIT) Copyright (c) Taylor Otwell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. validation/Factory.php 0000644 00000016756 14736103231 0011035 0 ustar 00 <?php namespace Illuminate\Validation; use Closure; use Illuminate\Contracts\Container\Container; use Illuminate\Contracts\Translation\Translator; use Illuminate\Contracts\Validation\Factory as FactoryContract; use Illuminate\Support\Str; class Factory implements FactoryContract { /** * The Translator implementation. * * @var \Illuminate\Contracts\Translation\Translator */ protected $translator; /** * The Presence Verifier implementation. * * @var \Illuminate\Validation\PresenceVerifierInterface */ protected $verifier; /** * The IoC container instance. * * @var \Illuminate\Contracts\Container\Container */ protected $container; /** * All of the custom validator extensions. * * @var array */ protected $extensions = []; /** * All of the custom implicit validator extensions. * * @var array */ protected $implicitExtensions = []; /** * All of the custom dependent validator extensions. * * @var array */ protected $dependentExtensions = []; /** * All of the custom validator message replacers. * * @var array */ protected $replacers = []; /** * All of the fallback messages for custom rules. * * @var array */ protected $fallbackMessages = []; /** * The Validator resolver instance. * * @var \Closure */ protected $resolver; /** * Create a new Validator factory instance. * * @param \Illuminate\Contracts\Translation\Translator $translator * @param \Illuminate\Contracts\Container\Container|null $container * @return void */ public function __construct(Translator $translator, Container $container = null) { $this->container = $container; $this->translator = $translator; } /** * Create a new Validator instance. * * @param array $data * @param array $rules * @param array $messages * @param array $customAttributes * @return \Illuminate\Validation\Validator */ public function make(array $data, array $rules, array $messages = [], array $customAttributes = []) { $validator = $this->resolve( $data, $rules, $messages, $customAttributes ); // The presence verifier is responsible for checking the unique and exists data // for the validator. It is behind an interface so that multiple versions of // it may be written besides database. We'll inject it into the validator. if (! is_null($this->verifier)) { $validator->setPresenceVerifier($this->verifier); } // Next we'll set the IoC container instance of the validator, which is used to // resolve out class based validator extensions. If it is not set then these // types of extensions will not be possible on these validation instances. if (! is_null($this->container)) { $validator->setContainer($this->container); } $this->addExtensions($validator); return $validator; } /** * Validate the given data against the provided rules. * * @param array $data * @param array $rules * @param array $messages * @param array $customAttributes * @return array * * @throws \Illuminate\Validation\ValidationException */ public function validate(array $data, array $rules, array $messages = [], array $customAttributes = []) { return $this->make($data, $rules, $messages, $customAttributes)->validate(); } /** * Resolve a new Validator instance. * * @param array $data * @param array $rules * @param array $messages * @param array $customAttributes * @return \Illuminate\Validation\Validator */ protected function resolve(array $data, array $rules, array $messages, array $customAttributes) { if (is_null($this->resolver)) { return new Validator($this->translator, $data, $rules, $messages, $customAttributes); } return call_user_func($this->resolver, $this->translator, $data, $rules, $messages, $customAttributes); } /** * Add the extensions to a validator instance. * * @param \Illuminate\Validation\Validator $validator * @return void */ protected function addExtensions(Validator $validator) { $validator->addExtensions($this->extensions); // Next, we will add the implicit extensions, which are similar to the required // and accepted rule in that they are run even if the attributes is not in a // array of data that is given to a validator instances via instantiation. $validator->addImplicitExtensions($this->implicitExtensions); $validator->addDependentExtensions($this->dependentExtensions); $validator->addReplacers($this->replacers); $validator->setFallbackMessages($this->fallbackMessages); } /** * Register a custom validator extension. * * @param string $rule * @param \Closure|string $extension * @param string|null $message * @return void */ public function extend($rule, $extension, $message = null) { $this->extensions[$rule] = $extension; if ($message) { $this->fallbackMessages[Str::snake($rule)] = $message; } } /** * Register a custom implicit validator extension. * * @param string $rule * @param \Closure|string $extension * @param string|null $message * @return void */ public function extendImplicit($rule, $extension, $message = null) { $this->implicitExtensions[$rule] = $extension; if ($message) { $this->fallbackMessages[Str::snake($rule)] = $message; } } /** * Register a custom dependent validator extension. * * @param string $rule * @param \Closure|string $extension * @param string|null $message * @return void */ public function extendDependent($rule, $extension, $message = null) { $this->dependentExtensions[$rule] = $extension; if ($message) { $this->fallbackMessages[Str::snake($rule)] = $message; } } /** * Register a custom validator message replacer. * * @param string $rule * @param \Closure|string $replacer * @return void */ public function replacer($rule, $replacer) { $this->replacers[$rule] = $replacer; } /** * Set the Validator instance resolver. * * @param \Closure $resolver * @return void */ public function resolver(Closure $resolver) { $this->resolver = $resolver; } /** * Get the Translator implementation. * * @return \Illuminate\Contracts\Translation\Translator */ public function getTranslator() { return $this->translator; } /** * Get the Presence Verifier implementation. * * @return \Illuminate\Validation\PresenceVerifierInterface */ public function getPresenceVerifier() { return $this->verifier; } /** * Set the Presence Verifier implementation. * * @param \Illuminate\Validation\PresenceVerifierInterface $presenceVerifier * @return void */ public function setPresenceVerifier(PresenceVerifierInterface $presenceVerifier) { $this->verifier = $presenceVerifier; } } validation/PresenceVerifierInterface.php 0000644 00000001516 14736103231 0014473 0 ustar 00 <?php namespace Illuminate\Validation; interface PresenceVerifierInterface { /** * Count the number of objects in a collection having the given value. * * @param string $collection * @param string $column * @param string $value * @param int|null $excludeId * @param string|null $idColumn * @param array $extra * @return int */ public function getCount($collection, $column, $value, $excludeId = null, $idColumn = null, array $extra = []); /** * Count the number of objects in a collection with the given values. * * @param string $collection * @param string $column * @param array $values * @param array $extra * @return int */ public function getMultiCount($collection, $column, array $values, array $extra = []); } validation/ValidatesWhenResolvedTrait.php 0000644 00000003723 14736103231 0014662 0 ustar 00 <?php namespace Illuminate\Validation; /** * Provides default implementation of ValidatesWhenResolved contract. */ trait ValidatesWhenResolvedTrait { /** * Validate the class instance. * * @return void */ public function validateResolved() { $this->prepareForValidation(); if (! $this->passesAuthorization()) { $this->failedAuthorization(); } $instance = $this->getValidatorInstance(); if ($instance->fails()) { $this->failedValidation($instance); } $this->passedValidation(); } /** * Prepare the data for validation. * * @return void */ protected function prepareForValidation() { // } /** * Get the validator instance for the request. * * @return \Illuminate\Validation\Validator */ protected function getValidatorInstance() { return $this->validator(); } /** * Handle a passed validation attempt. * * @return void */ protected function passedValidation() { // } /** * Handle a failed validation attempt. * * @param \Illuminate\Validation\Validator $validator * @return void * * @throws \Illuminate\Validation\ValidationException */ protected function failedValidation(Validator $validator) { throw new ValidationException($validator); } /** * Determine if the request passes the authorization check. * * @return bool */ protected function passesAuthorization() { if (method_exists($this, 'authorize')) { return $this->authorize(); } return true; } /** * Handle a failed authorization attempt. * * @return void * * @throws \Illuminate\Validation\UnauthorizedException */ protected function failedAuthorization() { throw new UnauthorizedException; } } console/OutputStyle.php 0000644 00000002747 14736103231 0011252 0 ustar 00 <?php namespace Illuminate\Console; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; class OutputStyle extends SymfonyStyle { /** * The output instance. * * @var \Symfony\Component\Console\Output\OutputInterface */ private $output; /** * Create a new Console OutputStyle instance. * * @param \Symfony\Component\Console\Input\InputInterface $input * @param \Symfony\Component\Console\Output\OutputInterface $output * @return void */ public function __construct(InputInterface $input, OutputInterface $output) { $this->output = $output; parent::__construct($input, $output); } /** * Returns whether verbosity is quiet (-q). * * @return bool */ public function isQuiet() { return $this->output->isQuiet(); } /** * Returns whether verbosity is verbose (-v). * * @return bool */ public function isVerbose() { return $this->output->isVerbose(); } /** * Returns whether verbosity is very verbose (-vv). * * @return bool */ public function isVeryVerbose() { return $this->output->isVeryVerbose(); } /** * Returns whether verbosity is debug (-vvv). * * @return bool */ public function isDebug() { return $this->output->isDebug(); } } console/Parser.php 0000644 00000011244 14736103231 0010155 0 ustar 00 <?php namespace Illuminate\Console; use Illuminate\Support\Str; use InvalidArgumentException; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; class Parser { /** * Parse the given console command definition into an array. * * @param string $expression * @return array * * @throws \InvalidArgumentException */ public static function parse($expression) { $name = static::name($expression); if (preg_match_all('/\{\s*(.*?)\s*\}/', $expression, $matches)) { if (count($matches[1])) { return array_merge([$name], static::parameters($matches[1])); } } return [$name, [], []]; } /** * Extract the name of the command from the expression. * * @param string $expression * @return string * * @throws \InvalidArgumentException */ protected static function name($expression) { if (! preg_match('/[^\s]+/', $expression, $matches)) { throw new InvalidArgumentException('Unable to determine command name from signature.'); } return $matches[0]; } /** * Extract all of the parameters from the tokens. * * @param array $tokens * @return array */ protected static function parameters(array $tokens) { $arguments = []; $options = []; foreach ($tokens as $token) { if (preg_match('/-{2,}(.*)/', $token, $matches)) { $options[] = static::parseOption($matches[1]); } else { $arguments[] = static::parseArgument($token); } } return [$arguments, $options]; } /** * Parse an argument expression. * * @param string $token * @return \Symfony\Component\Console\Input\InputArgument */ protected static function parseArgument($token) { [$token, $description] = static::extractDescription($token); switch (true) { case Str::endsWith($token, '?*'): return new InputArgument(trim($token, '?*'), InputArgument::IS_ARRAY, $description); case Str::endsWith($token, '*'): return new InputArgument(trim($token, '*'), InputArgument::IS_ARRAY | InputArgument::REQUIRED, $description); case Str::endsWith($token, '?'): return new InputArgument(trim($token, '?'), InputArgument::OPTIONAL, $description); case preg_match('/(.+)\=\*(.+)/', $token, $matches): return new InputArgument($matches[1], InputArgument::IS_ARRAY, $description, preg_split('/,\s?/', $matches[2])); case preg_match('/(.+)\=(.+)/', $token, $matches): return new InputArgument($matches[1], InputArgument::OPTIONAL, $description, $matches[2]); default: return new InputArgument($token, InputArgument::REQUIRED, $description); } } /** * Parse an option expression. * * @param string $token * @return \Symfony\Component\Console\Input\InputOption */ protected static function parseOption($token) { [$token, $description] = static::extractDescription($token); $matches = preg_split('/\s*\|\s*/', $token, 2); if (isset($matches[1])) { $shortcut = $matches[0]; $token = $matches[1]; } else { $shortcut = null; } switch (true) { case Str::endsWith($token, '='): return new InputOption(trim($token, '='), $shortcut, InputOption::VALUE_OPTIONAL, $description); case Str::endsWith($token, '=*'): return new InputOption(trim($token, '=*'), $shortcut, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, $description); case preg_match('/(.+)\=\*(.+)/', $token, $matches): return new InputOption($matches[1], $shortcut, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, $description, preg_split('/,\s?/', $matches[2])); case preg_match('/(.+)\=(.+)/', $token, $matches): return new InputOption($matches[1], $shortcut, InputOption::VALUE_OPTIONAL, $description, $matches[2]); default: return new InputOption($token, $shortcut, InputOption::VALUE_NONE, $description); } } /** * Parse the token into its token and description segments. * * @param string $token * @return array */ protected static function extractDescription($token) { $parts = preg_split('/\s+:\s+/', trim($token), 2); return count($parts) === 2 ? $parts : [$token, '']; } } console/Events/ScheduledTaskFinished.php 0000644 00000001215 14736103231 0014357 0 ustar 00 <?php namespace Illuminate\Console\Events; use Illuminate\Console\Scheduling\Event; class ScheduledTaskFinished { /** * The scheduled event that ran. * * @var \Illuminate\Console\Scheduling\Event */ public $task; /** * The runtime of the scheduled event. * * @var float */ public $runtime; /** * Create a new event instance. * * @param \Illuminate\Console\Scheduling\Event $task * @param float $runtime * @return void */ public function __construct(Event $task, $runtime) { $this->task = $task; $this->runtime = $runtime; } } console/Events/ArtisanStarting.php 0000644 00000000652 14736103231 0013303 0 ustar 00 <?php namespace Illuminate\Console\Events; class ArtisanStarting { /** * The Artisan application instance. * * @var \Illuminate\Console\Application */ public $artisan; /** * Create a new event instance. * * @param \Illuminate\Console\Application $artisan * @return void */ public function __construct($artisan) { $this->artisan = $artisan; } } console/Events/CommandFinished.php 0000644 00000002254 14736103231 0013216 0 ustar 00 <?php namespace Illuminate\Console\Events; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class CommandFinished { /** * The command name. * * @var string */ public $command; /** * The console input implementation. * * @var \Symfony\Component\Console\Input\InputInterface|null */ public $input; /** * The command output implementation. * * @var \Symfony\Component\Console\Output\OutputInterface|null */ public $output; /** * The command exit code. * * @var int */ public $exitCode; /** * Create a new event instance. * * @param string $command * @param \Symfony\Component\Console\Input\InputInterface $input * @param \Symfony\Component\Console\Output\OutputInterface $output * @param int $exitCode * @return void */ public function __construct($command, InputInterface $input, OutputInterface $output, $exitCode) { $this->input = $input; $this->output = $output; $this->command = $command; $this->exitCode = $exitCode; } } console/Events/ScheduledTaskSkipped.php 0000644 00000000727 14736103231 0014234 0 ustar 00 <?php namespace Illuminate\Console\Events; use Illuminate\Console\Scheduling\Event; class ScheduledTaskSkipped { /** * The scheduled event being run. * * @var \Illuminate\Console\Scheduling\Event */ public $task; /** * Create a new event instance. * * @param \Illuminate\Console\Scheduling\Event $task * @return void */ public function __construct(Event $task) { $this->task = $task; } } console/Events/CommandStarting.php 0000644 00000002002 14736103231 0013247 0 ustar 00 <?php namespace Illuminate\Console\Events; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class CommandStarting { /** * The command name. * * @var string */ public $command; /** * The console input implementation. * * @var \Symfony\Component\Console\Input\InputInterface|null */ public $input; /** * The command output implementation. * * @var \Symfony\Component\Console\Output\OutputInterface|null */ public $output; /** * Create a new event instance. * * @param string $command * @param \Symfony\Component\Console\Input\InputInterface $input * @param \Symfony\Component\Console\Output\OutputInterface $output * @return void */ public function __construct($command, InputInterface $input, OutputInterface $output) { $this->input = $input; $this->output = $output; $this->command = $command; } } console/Events/ScheduledTaskStarting.php 0000644 00000000730 14736103231 0014422 0 ustar 00 <?php namespace Illuminate\Console\Events; use Illuminate\Console\Scheduling\Event; class ScheduledTaskStarting { /** * The scheduled event being run. * * @var \Illuminate\Console\Scheduling\Event */ public $task; /** * Create a new event instance. * * @param \Illuminate\Console\Scheduling\Event $task * @return void */ public function __construct(Event $task) { $this->task = $task; } } console/Application.php 0000644 00000020552 14736103231 0011166 0 ustar 00 <?php namespace Illuminate\Console; use Closure; use Illuminate\Console\Events\ArtisanStarting; use Illuminate\Console\Events\CommandFinished; use Illuminate\Console\Events\CommandStarting; use Illuminate\Contracts\Console\Application as ApplicationContract; use Illuminate\Contracts\Container\Container; use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Support\ProcessUtils; use Symfony\Component\Console\Application as SymfonyApplication; use Symfony\Component\Console\Command\Command as SymfonyCommand; use Symfony\Component\Console\Exception\CommandNotFoundException; use Symfony\Component\Console\Input\ArgvInput; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\StringInput; use Symfony\Component\Console\Output\BufferedOutput; use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Process\PhpExecutableFinder; class Application extends SymfonyApplication implements ApplicationContract { /** * The Laravel application instance. * * @var \Illuminate\Contracts\Container\Container */ protected $laravel; /** * The output from the previous command. * * @var \Symfony\Component\Console\Output\BufferedOutput */ protected $lastOutput; /** * The console application bootstrappers. * * @var array */ protected static $bootstrappers = []; /** * The Event Dispatcher. * * @var \Illuminate\Contracts\Events\Dispatcher */ protected $events; /** * Create a new Artisan console application. * * @param \Illuminate\Contracts\Container\Container $laravel * @param \Illuminate\Contracts\Events\Dispatcher $events * @param string $version * @return void */ public function __construct(Container $laravel, Dispatcher $events, $version) { parent::__construct('Laravel Framework', $version); $this->laravel = $laravel; $this->events = $events; $this->setAutoExit(false); $this->setCatchExceptions(false); $this->events->dispatch(new ArtisanStarting($this)); $this->bootstrap(); } /** * {@inheritdoc} */ public function run(InputInterface $input = null, OutputInterface $output = null) { $commandName = $this->getCommandName( $input = $input ?: new ArgvInput ); $this->events->dispatch( new CommandStarting( $commandName, $input, $output = $output ?: new ConsoleOutput ) ); $exitCode = parent::run($input, $output); $this->events->dispatch( new CommandFinished($commandName, $input, $output, $exitCode) ); return $exitCode; } /** * Determine the proper PHP executable. * * @return string */ public static function phpBinary() { return ProcessUtils::escapeArgument((new PhpExecutableFinder)->find(false)); } /** * Determine the proper Artisan executable. * * @return string */ public static function artisanBinary() { return defined('ARTISAN_BINARY') ? ProcessUtils::escapeArgument(ARTISAN_BINARY) : 'artisan'; } /** * Format the given command as a fully-qualified executable command. * * @param string $string * @return string */ public static function formatCommandString($string) { return sprintf('%s %s %s', static::phpBinary(), static::artisanBinary(), $string); } /** * Register a console "starting" bootstrapper. * * @param \Closure $callback * @return void */ public static function starting(Closure $callback) { static::$bootstrappers[] = $callback; } /** * Bootstrap the console application. * * @return void */ protected function bootstrap() { foreach (static::$bootstrappers as $bootstrapper) { $bootstrapper($this); } } /** * Clear the console application bootstrappers. * * @return void */ public static function forgetBootstrappers() { static::$bootstrappers = []; } /** * Run an Artisan console command by name. * * @param string $command * @param array $parameters * @param \Symfony\Component\Console\Output\OutputInterface|null $outputBuffer * @return int * * @throws \Symfony\Component\Console\Exception\CommandNotFoundException */ public function call($command, array $parameters = [], $outputBuffer = null) { [$command, $input] = $this->parseCommand($command, $parameters); if (! $this->has($command)) { throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $command)); } return $this->run( $input, $this->lastOutput = $outputBuffer ?: new BufferedOutput ); } /** * Parse the incoming Artisan command and its input. * * @param string $command * @param array $parameters * @return array */ protected function parseCommand($command, $parameters) { if (is_subclass_of($command, SymfonyCommand::class)) { $callingClass = true; $command = $this->laravel->make($command)->getName(); } if (! isset($callingClass) && empty($parameters)) { $command = $this->getCommandName($input = new StringInput($command)); } else { array_unshift($parameters, $command); $input = new ArrayInput($parameters); } return [$command, $input ?? null]; } /** * Get the output for the last run command. * * @return string */ public function output() { return $this->lastOutput && method_exists($this->lastOutput, 'fetch') ? $this->lastOutput->fetch() : ''; } /** * Add a command to the console. * * @param \Symfony\Component\Console\Command\Command $command * @return \Symfony\Component\Console\Command\Command */ public function add(SymfonyCommand $command) { if ($command instanceof Command) { $command->setLaravel($this->laravel); } return $this->addToParent($command); } /** * Add the command to the parent instance. * * @param \Symfony\Component\Console\Command\Command $command * @return \Symfony\Component\Console\Command\Command */ protected function addToParent(SymfonyCommand $command) { return parent::add($command); } /** * Add a command, resolving through the application. * * @param string $command * @return \Symfony\Component\Console\Command\Command */ public function resolve($command) { return $this->add($this->laravel->make($command)); } /** * Resolve an array of commands through the application. * * @param array|mixed $commands * @return $this */ public function resolveCommands($commands) { $commands = is_array($commands) ? $commands : func_get_args(); foreach ($commands as $command) { $this->resolve($command); } return $this; } /** * Get the default input definition for the application. * * This is used to add the --env option to every available command. * * @return \Symfony\Component\Console\Input\InputDefinition */ protected function getDefaultInputDefinition() { return tap(parent::getDefaultInputDefinition(), function ($definition) { $definition->addOption($this->getEnvironmentOption()); }); } /** * Get the global environment option for the definition. * * @return \Symfony\Component\Console\Input\InputOption */ protected function getEnvironmentOption() { $message = 'The environment the command should run under'; return new InputOption('--env', null, InputOption::VALUE_OPTIONAL, $message); } /** * Get the Laravel application instance. * * @return \Illuminate\Contracts\Foundation\Application */ public function getLaravel() { return $this->laravel; } } console/AppNamespaceDetectorTrait.php 0000644 00000000460 14736103231 0013752 0 ustar 00 <?php namespace Illuminate\Console; use Illuminate\Container\Container; trait AppNamespaceDetectorTrait { /** * Get the application namespace. * * @return string */ protected function getAppNamespace() { return Container::getInstance()->getNamespace(); } } console/ScheduleServiceProvider.php 0000644 00000001267 14736103231 0013515 0 ustar 00 <?php namespace Illuminate\Console; use Illuminate\Support\ServiceProvider; class ScheduleServiceProvider extends ServiceProvider { /** * Indicates if loading of the provider is deferred. * * @var bool */ protected $defer = true; /** * Register the service provider. * * @return void */ public function register() { $this->commands('Illuminate\Console\Scheduling\ScheduleRunCommand'); } /** * Get the services provided by the provider. * * @return array */ public function provides() { return [ 'Illuminate\Console\Scheduling\ScheduleRunCommand', ]; } } console/GeneratorCommand.php 0000644 00000015736 14736103231 0012160 0 ustar 00 <?php namespace Illuminate\Console; use Illuminate\Filesystem\Filesystem; use Illuminate\Support\Str; use Symfony\Component\Console\Input\InputArgument; abstract class GeneratorCommand extends Command { /** * The filesystem instance. * * @var \Illuminate\Filesystem\Filesystem */ protected $files; /** * The type of class being generated. * * @var string */ protected $type; /** * Create a new controller creator command instance. * * @param \Illuminate\Filesystem\Filesystem $files * @return void */ public function __construct(Filesystem $files) { parent::__construct(); $this->files = $files; } /** * Get the stub file for the generator. * * @return string */ abstract protected function getStub(); /** * Execute the console command. * * @return bool|null * * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException */ public function handle() { $name = $this->qualifyClass($this->getNameInput()); $path = $this->getPath($name); // First we will check to see if the class already exists. If it does, we don't want // to create the class and overwrite the user's code. So, we will bail out so the // code is untouched. Otherwise, we will continue generating this class' files. if ((! $this->hasOption('force') || ! $this->option('force')) && $this->alreadyExists($this->getNameInput())) { $this->error($this->type.' already exists!'); return false; } // Next, we will generate the path to the location where this class' file should get // written. Then, we will build the class and make the proper replacements on the // stub files so that it gets the correctly formatted namespace and class name. $this->makeDirectory($path); $this->files->put($path, $this->sortImports($this->buildClass($name))); $this->info($this->type.' created successfully.'); } /** * Parse the class name and format according to the root namespace. * * @param string $name * @return string */ protected function qualifyClass($name) { $name = ltrim($name, '\\/'); $rootNamespace = $this->rootNamespace(); if (Str::startsWith($name, $rootNamespace)) { return $name; } $name = str_replace('/', '\\', $name); return $this->qualifyClass( $this->getDefaultNamespace(trim($rootNamespace, '\\')).'\\'.$name ); } /** * Get the default namespace for the class. * * @param string $rootNamespace * @return string */ protected function getDefaultNamespace($rootNamespace) { return $rootNamespace; } /** * Determine if the class already exists. * * @param string $rawName * @return bool */ protected function alreadyExists($rawName) { return $this->files->exists($this->getPath($this->qualifyClass($rawName))); } /** * Get the destination class path. * * @param string $name * @return string */ protected function getPath($name) { $name = Str::replaceFirst($this->rootNamespace(), '', $name); return $this->laravel['path'].'/'.str_replace('\\', '/', $name).'.php'; } /** * Build the directory for the class if necessary. * * @param string $path * @return string */ protected function makeDirectory($path) { if (! $this->files->isDirectory(dirname($path))) { $this->files->makeDirectory(dirname($path), 0777, true, true); } return $path; } /** * Build the class with the given name. * * @param string $name * @return string * * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException */ protected function buildClass($name) { $stub = $this->files->get($this->getStub()); return $this->replaceNamespace($stub, $name)->replaceClass($stub, $name); } /** * Replace the namespace for the given stub. * * @param string $stub * @param string $name * @return $this */ protected function replaceNamespace(&$stub, $name) { $searches = [ ['DummyNamespace', 'DummyRootNamespace', 'NamespacedDummyUserModel'], ['{{ namespace }}', '{{ rootNamespace }}', '{{ namespacedUserModel }}'], ['{{namespace}}', '{{rootNamespace}}', '{{namespacedUserModel}}'], ]; foreach ($searches as $search) { $stub = str_replace( $search, [$this->getNamespace($name), $this->rootNamespace(), $this->userProviderModel()], $stub ); } return $this; } /** * Get the full namespace for a given class, without the class name. * * @param string $name * @return string */ protected function getNamespace($name) { return trim(implode('\\', array_slice(explode('\\', $name), 0, -1)), '\\'); } /** * Replace the class name for the given stub. * * @param string $stub * @param string $name * @return string */ protected function replaceClass($stub, $name) { $class = str_replace($this->getNamespace($name).'\\', '', $name); return str_replace(['DummyClass', '{{ class }}', '{{class}}'], $class, $stub); } /** * Alphabetically sorts the imports for the given stub. * * @param string $stub * @return string */ protected function sortImports($stub) { if (preg_match('/(?P<imports>(?:use [^;]+;$\n?)+)/m', $stub, $match)) { $imports = explode("\n", trim($match['imports'])); sort($imports); return str_replace(trim($match['imports']), implode("\n", $imports), $stub); } return $stub; } /** * Get the desired class name from the input. * * @return string */ protected function getNameInput() { return trim($this->argument('name')); } /** * Get the root namespace for the class. * * @return string */ protected function rootNamespace() { return $this->laravel->getNamespace(); } /** * Get the model for the default guard's user provider. * * @return string|null */ protected function userProviderModel() { $config = $this->laravel['config']; $provider = $config->get('auth.guards.'.$config->get('auth.defaults.guard').'.provider'); return $config->get("auth.providers.{$provider}.model"); } /** * Get the console command arguments. * * @return array */ protected function getArguments() { return [ ['name', InputArgument::REQUIRED, 'The name of the class'], ]; } } console/Concerns/InteractsWithIO.php 0000644 00000023122 14736103231 0013511 0 ustar 00 <?php namespace Illuminate\Console\Concerns; use Illuminate\Console\OutputStyle; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Support\Str; use Symfony\Component\Console\Formatter\OutputFormatterStyle; use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ChoiceQuestion; use Symfony\Component\Console\Question\Question; trait InteractsWithIO { /** * The input interface implementation. * * @var \Symfony\Component\Console\Input\InputInterface */ protected $input; /** * The output interface implementation. * * @var \Illuminate\Console\OutputStyle */ protected $output; /** * The default verbosity of output commands. * * @var int */ protected $verbosity = OutputInterface::VERBOSITY_NORMAL; /** * The mapping between human readable verbosity levels and Symfony's OutputInterface. * * @var array */ protected $verbosityMap = [ 'v' => OutputInterface::VERBOSITY_VERBOSE, 'vv' => OutputInterface::VERBOSITY_VERY_VERBOSE, 'vvv' => OutputInterface::VERBOSITY_DEBUG, 'quiet' => OutputInterface::VERBOSITY_QUIET, 'normal' => OutputInterface::VERBOSITY_NORMAL, ]; /** * Determine if the given argument is present. * * @param string|int $name * @return bool */ public function hasArgument($name) { return $this->input->hasArgument($name); } /** * Get the value of a command argument. * * @param string|null $key * @return string|array|null */ public function argument($key = null) { if (is_null($key)) { return $this->input->getArguments(); } return $this->input->getArgument($key); } /** * Get all of the arguments passed to the command. * * @return array */ public function arguments() { return $this->argument(); } /** * Determine if the given option is present. * * @param string $name * @return bool */ public function hasOption($name) { return $this->input->hasOption($name); } /** * Get the value of a command option. * * @param string|null $key * @return string|array|bool|null */ public function option($key = null) { if (is_null($key)) { return $this->input->getOptions(); } return $this->input->getOption($key); } /** * Get all of the options passed to the command. * * @return array */ public function options() { return $this->option(); } /** * Confirm a question with the user. * * @param string $question * @param bool $default * @return bool */ public function confirm($question, $default = false) { return $this->output->confirm($question, $default); } /** * Prompt the user for input. * * @param string $question * @param string|null $default * @return mixed */ public function ask($question, $default = null) { return $this->output->ask($question, $default); } /** * Prompt the user for input with auto completion. * * @param string $question * @param array|callable $choices * @param string|null $default * @return mixed */ public function anticipate($question, $choices, $default = null) { return $this->askWithCompletion($question, $choices, $default); } /** * Prompt the user for input with auto completion. * * @param string $question * @param array|callable $choices * @param string|null $default * @return mixed */ public function askWithCompletion($question, $choices, $default = null) { $question = new Question($question, $default); is_callable($choices) ? $question->setAutocompleterCallback($choices) : $question->setAutocompleterValues($choices); return $this->output->askQuestion($question); } /** * Prompt the user for input but hide the answer from the console. * * @param string $question * @param bool $fallback * @return mixed */ public function secret($question, $fallback = true) { $question = new Question($question); $question->setHidden(true)->setHiddenFallback($fallback); return $this->output->askQuestion($question); } /** * Give the user a single choice from an array of answers. * * @param string $question * @param array $choices * @param string|null $default * @param mixed|null $attempts * @param bool $multiple * @return string|array */ public function choice($question, array $choices, $default = null, $attempts = null, $multiple = false) { $question = new ChoiceQuestion($question, $choices, $default); $question->setMaxAttempts($attempts)->setMultiselect($multiple); return $this->output->askQuestion($question); } /** * Format input to textual table. * * @param array $headers * @param \Illuminate\Contracts\Support\Arrayable|array $rows * @param string $tableStyle * @param array $columnStyles * @return void */ public function table($headers, $rows, $tableStyle = 'default', array $columnStyles = []) { $table = new Table($this->output); if ($rows instanceof Arrayable) { $rows = $rows->toArray(); } $table->setHeaders((array) $headers)->setRows($rows)->setStyle($tableStyle); foreach ($columnStyles as $columnIndex => $columnStyle) { $table->setColumnStyle($columnIndex, $columnStyle); } $table->render(); } /** * Write a string as information output. * * @param string $string * @param int|string|null $verbosity * @return void */ public function info($string, $verbosity = null) { $this->line($string, 'info', $verbosity); } /** * Write a string as standard output. * * @param string $string * @param string|null $style * @param int|string|null $verbosity * @return void */ public function line($string, $style = null, $verbosity = null) { $styled = $style ? "<$style>$string</$style>" : $string; $this->output->writeln($styled, $this->parseVerbosity($verbosity)); } /** * Write a string as comment output. * * @param string $string * @param int|string|null $verbosity * @return void */ public function comment($string, $verbosity = null) { $this->line($string, 'comment', $verbosity); } /** * Write a string as question output. * * @param string $string * @param int|string|null $verbosity * @return void */ public function question($string, $verbosity = null) { $this->line($string, 'question', $verbosity); } /** * Write a string as error output. * * @param string $string * @param int|string|null $verbosity * @return void */ public function error($string, $verbosity = null) { $this->line($string, 'error', $verbosity); } /** * Write a string as warning output. * * @param string $string * @param int|string|null $verbosity * @return void */ public function warn($string, $verbosity = null) { if (! $this->output->getFormatter()->hasStyle('warning')) { $style = new OutputFormatterStyle('yellow'); $this->output->getFormatter()->setStyle('warning', $style); } $this->line($string, 'warning', $verbosity); } /** * Write a string in an alert box. * * @param string $string * @return void */ public function alert($string) { $length = Str::length(strip_tags($string)) + 12; $this->comment(str_repeat('*', $length)); $this->comment('* '.$string.' *'); $this->comment(str_repeat('*', $length)); $this->output->newLine(); } /** * Set the input interface implementation. * * @param \Symfony\Component\Console\Input\InputInterface $input * @return void */ public function setInput(InputInterface $input) { $this->input = $input; } /** * Set the output interface implementation. * * @param \Illuminate\Console\OutputStyle $output * @return void */ public function setOutput(OutputStyle $output) { $this->output = $output; } /** * Set the verbosity level. * * @param string|int $level * @return void */ protected function setVerbosity($level) { $this->verbosity = $this->parseVerbosity($level); } /** * Get the verbosity level in terms of Symfony's OutputInterface level. * * @param string|int|null $level * @return int */ protected function parseVerbosity($level = null) { if (isset($this->verbosityMap[$level])) { $level = $this->verbosityMap[$level]; } elseif (! is_int($level)) { $level = $this->verbosity; } return $level; } /** * Get the output implementation. * * @return \Illuminate\Console\OutputStyle */ public function getOutput() { return $this->output; } } console/Concerns/HasParameters.php 0000644 00000002661 14736103231 0013235 0 ustar 00 <?php namespace Illuminate\Console\Concerns; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; trait HasParameters { /** * Specify the arguments and options on the command. * * @return void */ protected function specifyParameters() { // We will loop through all of the arguments and options for the command and // set them all on the base command instance. This specifies what can get // passed into these commands as "parameters" to control the execution. foreach ($this->getArguments() as $arguments) { if ($arguments instanceof InputArgument) { $this->getDefinition()->addArgument($arguments); } else { call_user_func_array([$this, 'addArgument'], $arguments); } } foreach ($this->getOptions() as $options) { if ($options instanceof InputOption) { $this->getDefinition()->addOption($options); } else { call_user_func_array([$this, 'addOption'], $options); } } } /** * Get the console command arguments. * * @return array */ protected function getArguments() { return []; } /** * Get the console command options. * * @return array */ protected function getOptions() { return []; } } console/Concerns/CallsCommands.php 0000644 00000005123 14736103231 0013212 0 ustar 00 <?php namespace Illuminate\Console\Concerns; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\NullOutput; use Symfony\Component\Console\Output\OutputInterface; trait CallsCommands { /** * Resolve the console command instance for the given command. * * @param \Symfony\Component\Console\Command\Command|string $command * @return \Symfony\Component\Console\Command\Command */ abstract protected function resolveCommand($command); /** * Call another console command. * * @param \Symfony\Component\Console\Command\Command|string $command * @param array $arguments * @return int */ public function call($command, array $arguments = []) { return $this->runCommand($command, $arguments, $this->output); } /** * Call another console command silently. * * @param \Symfony\Component\Console\Command\Command|string $command * @param array $arguments * @return int */ public function callSilent($command, array $arguments = []) { return $this->runCommand($command, $arguments, new NullOutput); } /** * Run the given the console command. * * @param \Symfony\Component\Console\Command\Command|string $command * @param array $arguments * @param \Symfony\Component\Console\Output\OutputInterface $output * @return int */ protected function runCommand($command, array $arguments, OutputInterface $output) { $arguments['command'] = $command; return $this->resolveCommand($command)->run( $this->createInputFromArguments($arguments), $output ); } /** * Create an input instance from the given arguments. * * @param array $arguments * @return \Symfony\Component\Console\Input\ArrayInput */ protected function createInputFromArguments(array $arguments) { return tap(new ArrayInput(array_merge($this->context(), $arguments)), function ($input) { if ($input->hasParameterOption(['--no-interaction'], true)) { $input->setInteractive(false); } }); } /** * Get all of the context passed to the command. * * @return array */ protected function context() { return collect($this->option())->only([ 'ansi', 'no-ansi', 'no-interaction', 'quiet', 'verbose', ])->filter()->mapWithKeys(function ($value, $key) { return ["--{$key}" => $value]; })->all(); } } console/ConfirmableTrait.php 0000644 00000002333 14736103231 0012145 0 ustar 00 <?php namespace Illuminate\Console; trait ConfirmableTrait { /** * Confirm before proceeding with the action. * * This method only asks for confirmation in production. * * @param string $warning * @param \Closure|bool|null $callback * @return bool */ public function confirmToProceed($warning = 'Application In Production!', $callback = null) { $callback = is_null($callback) ? $this->getDefaultConfirmCallback() : $callback; $shouldConfirm = value($callback); if ($shouldConfirm) { if ($this->hasOption('force') && $this->option('force')) { return true; } $this->alert($warning); $confirmed = $this->confirm('Do you really wish to run this command?'); if (! $confirmed) { $this->comment('Command Canceled!'); return false; } } return true; } /** * Get the default confirmation callback. * * @return \Closure */ protected function getDefaultConfirmCallback() { return function () { return $this->getLaravel()->environment() === 'production'; }; } } console/LICENSE.md 0000644 00000002063 14736103231 0007613 0 ustar 00 The MIT License (MIT) Copyright (c) Taylor Otwell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. console/Scheduling/CacheSchedulingMutex.php 0000644 00000003273 14736103231 0015045 0 ustar 00 <?php namespace Illuminate\Console\Scheduling; use DateTimeInterface; use Illuminate\Contracts\Cache\Factory as Cache; class CacheSchedulingMutex implements SchedulingMutex, CacheAware { /** * The cache factory implementation. * * @var \Illuminate\Contracts\Cache\Factory */ public $cache; /** * The cache store that should be used. * * @var string|null */ public $store; /** * Create a new scheduling strategy. * * @param \Illuminate\Contracts\Cache\Factory $cache * @return void */ public function __construct(Cache $cache) { $this->cache = $cache; } /** * Attempt to obtain a scheduling mutex for the given event. * * @param \Illuminate\Console\Scheduling\Event $event * @param \DateTimeInterface $time * @return bool */ public function create(Event $event, DateTimeInterface $time) { return $this->cache->store($this->store)->add( $event->mutexName().$time->format('Hi'), true, 3600 ); } /** * Determine if a scheduling mutex exists for the given event. * * @param \Illuminate\Console\Scheduling\Event $event * @param \DateTimeInterface $time * @return bool */ public function exists(Event $event, DateTimeInterface $time) { return $this->cache->store($this->store)->has( $event->mutexName().$time->format('Hi') ); } /** * Specify the cache store that should be used. * * @param string $store * @return $this */ public function useStore($store) { $this->store = $store; return $this; } } console/Scheduling/ManagesFrequencies.php 0000644 00000021761 14736103231 0014560 0 ustar 00 <?php namespace Illuminate\Console\Scheduling; use Illuminate\Support\Carbon; trait ManagesFrequencies { /** * The Cron expression representing the event's frequency. * * @param string $expression * @return $this */ public function cron($expression) { $this->expression = $expression; return $this; } /** * Schedule the event to run between start and end time. * * @param string $startTime * @param string $endTime * @return $this */ public function between($startTime, $endTime) { return $this->when($this->inTimeInterval($startTime, $endTime)); } /** * Schedule the event to not run between start and end time. * * @param string $startTime * @param string $endTime * @return $this */ public function unlessBetween($startTime, $endTime) { return $this->skip($this->inTimeInterval($startTime, $endTime)); } /** * Schedule the event to run between start and end time. * * @param string $startTime * @param string $endTime * @return \Closure */ private function inTimeInterval($startTime, $endTime) { [$now, $startTime, $endTime] = [ Carbon::now($this->timezone), Carbon::parse($startTime, $this->timezone), Carbon::parse($endTime, $this->timezone), ]; if ($endTime->lessThan($startTime)) { if ($startTime->greaterThan($now)) { $startTime->subDay(1); } else { $endTime->addDay(1); } } return function () use ($now, $startTime, $endTime) { return $now->between($startTime, $endTime); }; } /** * Schedule the event to run every minute. * * @return $this */ public function everyMinute() { return $this->spliceIntoPosition(1, '*'); } /** * Schedule the event to run every five minutes. * * @return $this */ public function everyFiveMinutes() { return $this->spliceIntoPosition(1, '*/5'); } /** * Schedule the event to run every ten minutes. * * @return $this */ public function everyTenMinutes() { return $this->spliceIntoPosition(1, '*/10'); } /** * Schedule the event to run every fifteen minutes. * * @return $this */ public function everyFifteenMinutes() { return $this->spliceIntoPosition(1, '*/15'); } /** * Schedule the event to run every thirty minutes. * * @return $this */ public function everyThirtyMinutes() { return $this->spliceIntoPosition(1, '0,30'); } /** * Schedule the event to run hourly. * * @return $this */ public function hourly() { return $this->spliceIntoPosition(1, 0); } /** * Schedule the event to run hourly at a given offset in the hour. * * @param array|int $offset * @return $this */ public function hourlyAt($offset) { $offset = is_array($offset) ? implode(',', $offset) : $offset; return $this->spliceIntoPosition(1, $offset); } /** * Schedule the event to run daily. * * @return $this */ public function daily() { return $this->spliceIntoPosition(1, 0) ->spliceIntoPosition(2, 0); } /** * Schedule the command at a given time. * * @param string $time * @return $this */ public function at($time) { return $this->dailyAt($time); } /** * Schedule the event to run daily at a given time (10:00, 19:30, etc). * * @param string $time * @return $this */ public function dailyAt($time) { $segments = explode(':', $time); return $this->spliceIntoPosition(2, (int) $segments[0]) ->spliceIntoPosition(1, count($segments) === 2 ? (int) $segments[1] : '0'); } /** * Schedule the event to run twice daily. * * @param int $first * @param int $second * @return $this */ public function twiceDaily($first = 1, $second = 13) { $hours = $first.','.$second; return $this->spliceIntoPosition(1, 0) ->spliceIntoPosition(2, $hours); } /** * Schedule the event to run only on weekdays. * * @return $this */ public function weekdays() { return $this->spliceIntoPosition(5, '1-5'); } /** * Schedule the event to run only on weekends. * * @return $this */ public function weekends() { return $this->spliceIntoPosition(5, '0,6'); } /** * Schedule the event to run only on Mondays. * * @return $this */ public function mondays() { return $this->days(1); } /** * Schedule the event to run only on Tuesdays. * * @return $this */ public function tuesdays() { return $this->days(2); } /** * Schedule the event to run only on Wednesdays. * * @return $this */ public function wednesdays() { return $this->days(3); } /** * Schedule the event to run only on Thursdays. * * @return $this */ public function thursdays() { return $this->days(4); } /** * Schedule the event to run only on Fridays. * * @return $this */ public function fridays() { return $this->days(5); } /** * Schedule the event to run only on Saturdays. * * @return $this */ public function saturdays() { return $this->days(6); } /** * Schedule the event to run only on Sundays. * * @return $this */ public function sundays() { return $this->days(0); } /** * Schedule the event to run weekly. * * @return $this */ public function weekly() { return $this->spliceIntoPosition(1, 0) ->spliceIntoPosition(2, 0) ->spliceIntoPosition(5, 0); } /** * Schedule the event to run weekly on a given day and time. * * @param int $day * @param string $time * @return $this */ public function weeklyOn($day, $time = '0:0') { $this->dailyAt($time); return $this->spliceIntoPosition(5, $day); } /** * Schedule the event to run monthly. * * @return $this */ public function monthly() { return $this->spliceIntoPosition(1, 0) ->spliceIntoPosition(2, 0) ->spliceIntoPosition(3, 1); } /** * Schedule the event to run monthly on a given day and time. * * @param int $day * @param string $time * @return $this */ public function monthlyOn($day = 1, $time = '0:0') { $this->dailyAt($time); return $this->spliceIntoPosition(3, $day); } /** * Schedule the event to run twice monthly. * * @param int $first * @param int $second * @return $this */ public function twiceMonthly($first = 1, $second = 16) { $days = $first.','.$second; return $this->spliceIntoPosition(1, 0) ->spliceIntoPosition(2, 0) ->spliceIntoPosition(3, $days); } /** * Schedule the event to run quarterly. * * @return $this */ public function quarterly() { return $this->spliceIntoPosition(1, 0) ->spliceIntoPosition(2, 0) ->spliceIntoPosition(3, 1) ->spliceIntoPosition(4, '1-12/3'); } /** * Schedule the event to run yearly. * * @return $this */ public function yearly() { return $this->spliceIntoPosition(1, 0) ->spliceIntoPosition(2, 0) ->spliceIntoPosition(3, 1) ->spliceIntoPosition(4, 1); } /** * Set the days of the week the command should run on. * * @param array|mixed $days * @return $this */ public function days($days) { $days = is_array($days) ? $days : func_get_args(); return $this->spliceIntoPosition(5, implode(',', $days)); } /** * Set the timezone the date should be evaluated on. * * @param \DateTimeZone|string $timezone * @return $this */ public function timezone($timezone) { $this->timezone = $timezone; return $this; } /** * Splice the given value into the given position of the expression. * * @param int $position * @param string $value * @return $this */ protected function spliceIntoPosition($position, $value) { $segments = explode(' ', $this->expression); $segments[$position - 1] = $value; return $this->cron(implode(' ', $segments)); } } console/Scheduling/SchedulingMutex.php 0000644 00000001222 14736103231 0014111 0 ustar 00 <?php namespace Illuminate\Console\Scheduling; use DateTimeInterface; interface SchedulingMutex { /** * Attempt to obtain a scheduling mutex for the given event. * * @param \Illuminate\Console\Scheduling\Event $event * @param \DateTimeInterface $time * @return bool */ public function create(Event $event, DateTimeInterface $time); /** * Determine if a scheduling mutex exists for the given event. * * @param \Illuminate\Console\Scheduling\Event $event * @param \DateTimeInterface $time * @return bool */ public function exists(Event $event, DateTimeInterface $time); } console/Scheduling/EventMutex.php 0000644 00000001255 14736103231 0013113 0 ustar 00 <?php namespace Illuminate\Console\Scheduling; interface EventMutex { /** * Attempt to obtain an event mutex for the given event. * * @param \Illuminate\Console\Scheduling\Event $event * @return bool */ public function create(Event $event); /** * Determine if an event mutex exists for the given event. * * @param \Illuminate\Console\Scheduling\Event $event * @return bool */ public function exists(Event $event); /** * Clear the event mutex for the given event. * * @param \Illuminate\Console\Scheduling\Event $event * @return void */ public function forget(Event $event); } console/Scheduling/Schedule.php 0000644 00000020660 14736103231 0012544 0 ustar 00 <?php namespace Illuminate\Console\Scheduling; use Closure; use DateTimeInterface; use Illuminate\Console\Application; use Illuminate\Container\Container; use Illuminate\Contracts\Bus\Dispatcher; use Illuminate\Contracts\Container\BindingResolutionException; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Queue\CallQueuedClosure; use Illuminate\Support\ProcessUtils; use Illuminate\Support\Str; use Illuminate\Support\Traits\Macroable; use RuntimeException; class Schedule { use Macroable; /** * All of the events on the schedule. * * @var \Illuminate\Console\Scheduling\Event[] */ protected $events = []; /** * The event mutex implementation. * * @var \Illuminate\Console\Scheduling\EventMutex */ protected $eventMutex; /** * The scheduling mutex implementation. * * @var \Illuminate\Console\Scheduling\SchedulingMutex */ protected $schedulingMutex; /** * The timezone the date should be evaluated on. * * @var \DateTimeZone|string */ protected $timezone; /** * The job dispatcher implementation. * * @var \Illuminate\Contracts\Bus\Dispatcher */ protected $dispatcher; /** * Create a new schedule instance. * * @param \DateTimeZone|string|null $timezone * @return void */ public function __construct($timezone = null) { $this->timezone = $timezone; if (! class_exists(Container::class)) { throw new RuntimeException( 'A container implementation is required to use the scheduler. Please install illuminate/container.' ); } $container = Container::getInstance(); $this->eventMutex = $container->bound(EventMutex::class) ? $container->make(EventMutex::class) : $container->make(CacheEventMutex::class); $this->schedulingMutex = $container->bound(SchedulingMutex::class) ? $container->make(SchedulingMutex::class) : $container->make(CacheSchedulingMutex::class); } /** * Add a new callback event to the schedule. * * @param string|callable $callback * @param array $parameters * @return \Illuminate\Console\Scheduling\CallbackEvent */ public function call($callback, array $parameters = []) { $this->events[] = $event = new CallbackEvent( $this->eventMutex, $callback, $parameters ); return $event; } /** * Add a new Artisan command event to the schedule. * * @param string $command * @param array $parameters * @return \Illuminate\Console\Scheduling\Event */ public function command($command, array $parameters = []) { if (class_exists($command)) { $command = Container::getInstance()->make($command)->getName(); } return $this->exec( Application::formatCommandString($command), $parameters ); } /** * Add a new job callback event to the schedule. * * @param object|string $job * @param string|null $queue * @param string|null $connection * @return \Illuminate\Console\Scheduling\CallbackEvent */ public function job($job, $queue = null, $connection = null) { return $this->call(function () use ($job, $queue, $connection) { $job = is_string($job) ? Container::getInstance()->make($job) : $job; if ($job instanceof ShouldQueue) { $this->dispatchToQueue($job, $queue ?? $job->queue, $connection ?? $job->connection); } else { $this->dispatchNow($job); } })->name(is_string($job) ? $job : get_class($job)); } /** * Dispatch the given job to the queue. * * @param object $job * @param string|null $queue * @param string|null $connection * @return void */ protected function dispatchToQueue($job, $queue, $connection) { if ($job instanceof Closure) { if (! class_exists(CallQueuedClosure::class)) { throw new RuntimeException( 'To enable support for closure jobs, please install illuminate/queue.' ); } $job = CallQueuedClosure::create($job); } $this->getDispatcher()->dispatch( $job->onConnection($connection)->onQueue($queue) ); } /** * Dispatch the given job right now. * * @param object $job * @return void */ protected function dispatchNow($job) { $this->getDispatcher()->dispatchNow($job); } /** * Add a new command event to the schedule. * * @param string $command * @param array $parameters * @return \Illuminate\Console\Scheduling\Event */ public function exec($command, array $parameters = []) { if (count($parameters)) { $command .= ' '.$this->compileParameters($parameters); } $this->events[] = $event = new Event($this->eventMutex, $command, $this->timezone); return $event; } /** * Compile parameters for a command. * * @param array $parameters * @return string */ protected function compileParameters(array $parameters) { return collect($parameters)->map(function ($value, $key) { if (is_array($value)) { return $this->compileArrayInput($key, $value); } if (! is_numeric($value) && ! preg_match('/^(-.$|--.*)/i', $value)) { $value = ProcessUtils::escapeArgument($value); } return is_numeric($key) ? $value : "{$key}={$value}"; })->implode(' '); } /** * Compile array input for a command. * * @param string|int $key * @param array $value * @return string */ public function compileArrayInput($key, $value) { $value = collect($value)->map(function ($value) { return ProcessUtils::escapeArgument($value); }); if (Str::startsWith($key, '--')) { $value = $value->map(function ($value) use ($key) { return "{$key}={$value}"; }); } elseif (Str::startsWith($key, '-')) { $value = $value->map(function ($value) use ($key) { return "{$key} {$value}"; }); } return $value->implode(' '); } /** * Determine if the server is allowed to run this event. * * @param \Illuminate\Console\Scheduling\Event $event * @param \DateTimeInterface $time * @return bool */ public function serverShouldRun(Event $event, DateTimeInterface $time) { return $this->schedulingMutex->create($event, $time); } /** * Get all of the events on the schedule that are due. * * @param \Illuminate\Contracts\Foundation\Application $app * @return \Illuminate\Support\Collection */ public function dueEvents($app) { return collect($this->events)->filter->isDue($app); } /** * Get all of the events on the schedule. * * @return \Illuminate\Console\Scheduling\Event[] */ public function events() { return $this->events; } /** * Specify the cache store that should be used to store mutexes. * * @param string $store * @return $this */ public function useCache($store) { if ($this->eventMutex instanceof CacheAware) { $this->eventMutex->useStore($store); } if ($this->schedulingMutex instanceof CacheAware) { $this->schedulingMutex->useStore($store); } return $this; } /** * Get the job dispatcher, if available. * * @return \Illuminate\Contracts\Bus\Dispatcher */ protected function getDispatcher() { if ($this->dispatcher === null) { try { $this->dispatcher = Container::getInstance()->make(Dispatcher::class); } catch (BindingResolutionException $e) { throw new RuntimeException( 'Unable to resolve the dispatcher from the service container. Please bind it or install illuminate/bus.', $e->getCode(), $e ); } } return $this->dispatcher; } } console/Scheduling/Event.php 0000644 00000052240 14736103231 0012070 0 ustar 00 <?php namespace Illuminate\Console\Scheduling; use Closure; use Cron\CronExpression; use GuzzleHttp\Client as HttpClient; use GuzzleHttp\Exception\TransferException; use Illuminate\Contracts\Container\Container; use Illuminate\Contracts\Debug\ExceptionHandler; use Illuminate\Contracts\Mail\Mailer; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Date; use Illuminate\Support\Traits\Macroable; use Illuminate\Support\Traits\ReflectsClosures; use Psr\Http\Client\ClientExceptionInterface; use Symfony\Component\Process\Process; class Event { use Macroable, ManagesFrequencies, ReflectsClosures; /** * The command string. * * @var string */ public $command; /** * The cron expression representing the event's frequency. * * @var string */ public $expression = '* * * * *'; /** * The timezone the date should be evaluated on. * * @var \DateTimeZone|string */ public $timezone; /** * The user the command should run as. * * @var string */ public $user; /** * The list of environments the command should run under. * * @var array */ public $environments = []; /** * Indicates if the command should run in maintenance mode. * * @var bool */ public $evenInMaintenanceMode = false; /** * Indicates if the command should not overlap itself. * * @var bool */ public $withoutOverlapping = false; /** * Indicates if the command should only be allowed to run on one server for each cron expression. * * @var bool */ public $onOneServer = false; /** * The amount of time the mutex should be valid. * * @var int */ public $expiresAt = 1440; /** * Indicates if the command should run in background. * * @var bool */ public $runInBackground = false; /** * The array of filter callbacks. * * @var array */ protected $filters = []; /** * The array of reject callbacks. * * @var array */ protected $rejects = []; /** * The location that output should be sent to. * * @var string */ public $output = '/dev/null'; /** * Indicates whether output should be appended. * * @var bool */ public $shouldAppendOutput = false; /** * The array of callbacks to be run before the event is started. * * @var array */ protected $beforeCallbacks = []; /** * The array of callbacks to be run after the event is finished. * * @var array */ protected $afterCallbacks = []; /** * The human readable description of the event. * * @var string */ public $description; /** * The event mutex implementation. * * @var \Illuminate\Console\Scheduling\EventMutex */ public $mutex; /** * The exit status code of the command. * * @var int|null */ public $exitCode; /** * Create a new event instance. * * @param \Illuminate\Console\Scheduling\EventMutex $mutex * @param string $command * @param \DateTimeZone|string|null $timezone * @return void */ public function __construct(EventMutex $mutex, $command, $timezone = null) { $this->mutex = $mutex; $this->command = $command; $this->timezone = $timezone; $this->output = $this->getDefaultOutput(); } /** * Get the default output depending on the OS. * * @return string */ public function getDefaultOutput() { return (DIRECTORY_SEPARATOR === '\\') ? 'NUL' : '/dev/null'; } /** * Run the given event. * * @param \Illuminate\Contracts\Container\Container $container * @return void */ public function run(Container $container) { if ($this->withoutOverlapping && ! $this->mutex->create($this)) { return; } $this->runInBackground ? $this->runCommandInBackground($container) : $this->runCommandInForeground($container); } /** * Get the mutex name for the scheduled command. * * @return string */ public function mutexName() { return 'framework'.DIRECTORY_SEPARATOR.'schedule-'.sha1($this->expression.$this->command); } /** * Run the command in the foreground. * * @param \Illuminate\Contracts\Container\Container $container * @return void */ protected function runCommandInForeground(Container $container) { $this->callBeforeCallbacks($container); $this->exitCode = Process::fromShellCommandline($this->buildCommand(), base_path(), null, null, null)->run(); $this->callAfterCallbacks($container); } /** * Run the command in the background. * * @param \Illuminate\Contracts\Container\Container $container * @return void */ protected function runCommandInBackground(Container $container) { $this->callBeforeCallbacks($container); Process::fromShellCommandline($this->buildCommand(), base_path(), null, null, null)->run(); } /** * Call all of the "before" callbacks for the event. * * @param \Illuminate\Contracts\Container\Container $container * @return void */ public function callBeforeCallbacks(Container $container) { foreach ($this->beforeCallbacks as $callback) { $container->call($callback); } } /** * Call all of the "after" callbacks for the event. * * @param \Illuminate\Contracts\Container\Container $container * @return void */ public function callAfterCallbacks(Container $container) { foreach ($this->afterCallbacks as $callback) { $container->call($callback); } } /** * Call all of the "after" callbacks for the event. * * @param \Illuminate\Contracts\Container\Container $container * @param int $exitCode * @return void */ public function callAfterCallbacksWithExitCode(Container $container, $exitCode) { $this->exitCode = (int) $exitCode; $this->callAfterCallbacks($container); } /** * Build the command string. * * @return string */ public function buildCommand() { return (new CommandBuilder)->buildCommand($this); } /** * Determine if the given event should run based on the Cron expression. * * @param \Illuminate\Contracts\Foundation\Application $app * @return bool */ public function isDue($app) { if (! $this->runsInMaintenanceMode() && $app->isDownForMaintenance()) { return false; } return $this->expressionPasses() && $this->runsInEnvironment($app->environment()); } /** * Determine if the event runs in maintenance mode. * * @return bool */ public function runsInMaintenanceMode() { return $this->evenInMaintenanceMode; } /** * Determine if the Cron expression passes. * * @return bool */ protected function expressionPasses() { $date = Carbon::now(); if ($this->timezone) { $date->setTimezone($this->timezone); } return CronExpression::factory($this->expression)->isDue($date->toDateTimeString()); } /** * Determine if the event runs in the given environment. * * @param string $environment * @return bool */ public function runsInEnvironment($environment) { return empty($this->environments) || in_array($environment, $this->environments); } /** * Determine if the filters pass for the event. * * @param \Illuminate\Contracts\Foundation\Application $app * @return bool */ public function filtersPass($app) { foreach ($this->filters as $callback) { if (! $app->call($callback)) { return false; } } foreach ($this->rejects as $callback) { if ($app->call($callback)) { return false; } } return true; } /** * Ensure that the output is stored on disk in a log file. * * @return $this */ public function storeOutput() { $this->ensureOutputIsBeingCaptured(); return $this; } /** * Send the output of the command to a given location. * * @param string $location * @param bool $append * @return $this */ public function sendOutputTo($location, $append = false) { $this->output = $location; $this->shouldAppendOutput = $append; return $this; } /** * Append the output of the command to a given location. * * @param string $location * @return $this */ public function appendOutputTo($location) { return $this->sendOutputTo($location, true); } /** * E-mail the results of the scheduled operation. * * @param array|mixed $addresses * @param bool $onlyIfOutputExists * @return $this * * @throws \LogicException */ public function emailOutputTo($addresses, $onlyIfOutputExists = false) { $this->ensureOutputIsBeingCaptured(); $addresses = Arr::wrap($addresses); return $this->then(function (Mailer $mailer) use ($addresses, $onlyIfOutputExists) { $this->emailOutput($mailer, $addresses, $onlyIfOutputExists); }); } /** * E-mail the results of the scheduled operation if it produces output. * * @param array|mixed $addresses * @return $this * * @throws \LogicException */ public function emailWrittenOutputTo($addresses) { return $this->emailOutputTo($addresses, true); } /** * E-mail the results of the scheduled operation if it fails. * * @param array|mixed $addresses * @return $this */ public function emailOutputOnFailure($addresses) { $this->ensureOutputIsBeingCaptured(); $addresses = Arr::wrap($addresses); return $this->onFailure(function (Mailer $mailer) use ($addresses) { $this->emailOutput($mailer, $addresses, false); }); } /** * Ensure that the command output is being captured. * * @return void */ protected function ensureOutputIsBeingCaptured() { if (is_null($this->output) || $this->output == $this->getDefaultOutput()) { $this->sendOutputTo(storage_path('logs/schedule-'.sha1($this->mutexName()).'.log')); } } /** * E-mail the output of the event to the recipients. * * @param \Illuminate\Contracts\Mail\Mailer $mailer * @param array $addresses * @param bool $onlyIfOutputExists * @return void */ protected function emailOutput(Mailer $mailer, $addresses, $onlyIfOutputExists = false) { $text = file_exists($this->output) ? file_get_contents($this->output) : ''; if ($onlyIfOutputExists && empty($text)) { return; } $mailer->raw($text, function ($m) use ($addresses) { $m->to($addresses)->subject($this->getEmailSubject()); }); } /** * Get the e-mail subject line for output results. * * @return string */ protected function getEmailSubject() { if ($this->description) { return $this->description; } return "Scheduled Job Output For [{$this->command}]"; } /** * Register a callback to ping a given URL before the job runs. * * @param string $url * @return $this */ public function pingBefore($url) { return $this->before($this->pingCallback($url)); } /** * Register a callback to ping a given URL before the job runs if the given condition is true. * * @param bool $value * @param string $url * @return $this */ public function pingBeforeIf($value, $url) { return $value ? $this->pingBefore($url) : $this; } /** * Register a callback to ping a given URL after the job runs. * * @param string $url * @return $this */ public function thenPing($url) { return $this->then($this->pingCallback($url)); } /** * Register a callback to ping a given URL after the job runs if the given condition is true. * * @param bool $value * @param string $url * @return $this */ public function thenPingIf($value, $url) { return $value ? $this->thenPing($url) : $this; } /** * Register a callback to ping a given URL if the operation succeeds. * * @param string $url * @return $this */ public function pingOnSuccess($url) { return $this->onSuccess($this->pingCallback($url)); } /** * Register a callback to ping a given URL if the operation fails. * * @param string $url * @return $this */ public function pingOnFailure($url) { return $this->onFailure($this->pingCallback($url)); } /** * Get the callback that pings the given URL. * * @param string $url * @return \Closure */ protected function pingCallback($url) { return function (Container $container, HttpClient $http) use ($url) { try { $http->request('GET', $url); } catch (ClientExceptionInterface | TransferException $e) { $container->make(ExceptionHandler::class)->report($e); } }; } /** * State that the command should run in background. * * @return $this */ public function runInBackground() { $this->runInBackground = true; return $this; } /** * Set which user the command should run as. * * @param string $user * @return $this */ public function user($user) { $this->user = $user; return $this; } /** * Limit the environments the command should run in. * * @param array|mixed $environments * @return $this */ public function environments($environments) { $this->environments = is_array($environments) ? $environments : func_get_args(); return $this; } /** * State that the command should run even in maintenance mode. * * @return $this */ public function evenInMaintenanceMode() { $this->evenInMaintenanceMode = true; return $this; } /** * Do not allow the event to overlap each other. * * @param int $expiresAt * @return $this */ public function withoutOverlapping($expiresAt = 1440) { $this->withoutOverlapping = true; $this->expiresAt = $expiresAt; return $this->then(function () { $this->mutex->forget($this); })->skip(function () { return $this->mutex->exists($this); }); } /** * Allow the event to only run on one server for each cron expression. * * @return $this */ public function onOneServer() { $this->onOneServer = true; return $this; } /** * Register a callback to further filter the schedule. * * @param \Closure|bool $callback * @return $this */ public function when($callback) { $this->filters[] = is_callable($callback) ? $callback : function () use ($callback) { return $callback; }; return $this; } /** * Register a callback to further filter the schedule. * * @param \Closure|bool $callback * @return $this */ public function skip($callback) { $this->rejects[] = is_callable($callback) ? $callback : function () use ($callback) { return $callback; }; return $this; } /** * Register a callback to be called before the operation. * * @param \Closure $callback * @return $this */ public function before(Closure $callback) { $this->beforeCallbacks[] = $callback; return $this; } /** * Register a callback to be called after the operation. * * @param \Closure $callback * @return $this */ public function after(Closure $callback) { return $this->then($callback); } /** * Register a callback to be called after the operation. * * @param \Closure $callback * @return $this */ public function then(Closure $callback) { $this->afterCallbacks[] = $callback; return $this; } /** * Register a callback that uses the output after the job runs. * * @param \Closure $callback * @param bool $onlyIfOutputExists * @return $this */ public function thenWithOutput(Closure $callback, $onlyIfOutputExists = false) { $this->ensureOutputIsBeingCaptured(); return $this->then($this->withOutputCallback($callback, $onlyIfOutputExists)); } /** * Register a callback to be called if the operation succeeds. * * @param \Closure $callback * @return $this */ public function onSuccess(Closure $callback) { return $this->then(function (Container $container) use ($callback) { if (0 === $this->exitCode) { $container->call($callback); } }); } /** * Register a callback that uses the output if the operation succeeds. * * @param \Closure $callback * @param bool $onlyIfOutputExists * @return $this */ public function onSuccessWithOutput(Closure $callback, $onlyIfOutputExists = false) { $this->ensureOutputIsBeingCaptured(); return $this->onSuccess($this->withOutputCallback($callback, $onlyIfOutputExists)); } /** * Register a callback to be called if the operation fails. * * @param \Closure $callback * @return $this */ public function onFailure(Closure $callback) { return $this->then(function (Container $container) use ($callback) { if (0 !== $this->exitCode) { $container->call($callback); } }); } /** * Register a callback that uses the output if the operation fails. * * @param \Closure $callback * @param bool $onlyIfOutputExists * @return $this */ public function onFailureWithOutput(Closure $callback, $onlyIfOutputExists = false) { $this->ensureOutputIsBeingCaptured(); return $this->onFailure($this->withOutputCallback($callback, $onlyIfOutputExists)); } /** * Get a callback that provides output. * * @param \Closure $callback * @param bool $onlyIfOutputExists * @return \Closure */ protected function withOutputCallback(Closure $callback, $onlyIfOutputExists = false) { return function (Container $container) use ($callback, $onlyIfOutputExists) { $output = $this->output && file_exists($this->output) ? file_get_contents($this->output) : ''; return $onlyIfOutputExists && empty($output) ? null : $container->call($callback, ['output' => $output]); }; } /** * Set the human-friendly description of the event. * * @param string $description * @return $this */ public function name($description) { return $this->description($description); } /** * Set the human-friendly description of the event. * * @param string $description * @return $this */ public function description($description) { $this->description = $description; return $this; } /** * Get the summary of the event for display. * * @return string */ public function getSummaryForDisplay() { if (is_string($this->description)) { return $this->description; } return $this->buildCommand(); } /** * Determine the next due date for an event. * * @param \DateTimeInterface|string $currentTime * @param int $nth * @param bool $allowCurrentDate * @return \Illuminate\Support\Carbon */ public function nextRunDate($currentTime = 'now', $nth = 0, $allowCurrentDate = false) { return Date::instance(CronExpression::factory( $this->getExpression() )->getNextRunDate($currentTime, $nth, $allowCurrentDate, $this->timezone)); } /** * Get the Cron expression for the event. * * @return string */ public function getExpression() { return $this->expression; } /** * Set the event mutex implementation to be used. * * @param \Illuminate\Console\Scheduling\EventMutex $mutex * @return $this */ public function preventOverlapsUsing(EventMutex $mutex) { $this->mutex = $mutex; return $this; } } console/Scheduling/CallbackEvent.php 0000644 00000007635 14736103231 0013515 0 ustar 00 <?php namespace Illuminate\Console\Scheduling; use Illuminate\Contracts\Container\Container; use InvalidArgumentException; use LogicException; class CallbackEvent extends Event { /** * The callback to call. * * @var string */ protected $callback; /** * The parameters to pass to the method. * * @var array */ protected $parameters; /** * Create a new event instance. * * @param \Illuminate\Console\Scheduling\EventMutex $mutex * @param string $callback * @param array $parameters * @return void * * @throws \InvalidArgumentException */ public function __construct(EventMutex $mutex, $callback, array $parameters = []) { if (! is_string($callback) && ! is_callable($callback)) { throw new InvalidArgumentException( 'Invalid scheduled callback event. Must be a string or callable.' ); } $this->mutex = $mutex; $this->callback = $callback; $this->parameters = $parameters; } /** * Run the given event. * * @param \Illuminate\Contracts\Container\Container $container * @return mixed * * @throws \Exception */ public function run(Container $container) { if ($this->description && $this->withoutOverlapping && ! $this->mutex->create($this)) { return; } $pid = getmypid(); register_shutdown_function(function () use ($pid) { if ($pid === getmypid()) { $this->removeMutex(); } }); parent::callBeforeCallbacks($container); try { $response = is_object($this->callback) ? $container->call([$this->callback, '__invoke'], $this->parameters) : $container->call($this->callback, $this->parameters); } finally { $this->removeMutex(); parent::callAfterCallbacks($container); } return $response; } /** * Clear the mutex for the event. * * @return void */ protected function removeMutex() { if ($this->description && $this->withoutOverlapping) { $this->mutex->forget($this); } } /** * Do not allow the event to overlap each other. * * @param int $expiresAt * @return $this * * @throws \LogicException */ public function withoutOverlapping($expiresAt = 1440) { if (! isset($this->description)) { throw new LogicException( "A scheduled event name is required to prevent overlapping. Use the 'name' method before 'withoutOverlapping'." ); } $this->withoutOverlapping = true; $this->expiresAt = $expiresAt; return $this->skip(function () { return $this->mutex->exists($this); }); } /** * Allow the event to only run on one server for each cron expression. * * @return $this * * @throws \LogicException */ public function onOneServer() { if (! isset($this->description)) { throw new LogicException( "A scheduled event name is required to only run on one server. Use the 'name' method before 'onOneServer'." ); } $this->onOneServer = true; return $this; } /** * Get the mutex name for the scheduled command. * * @return string */ public function mutexName() { return 'framework/schedule-'.sha1($this->description); } /** * Get the summary of the event for display. * * @return string */ public function getSummaryForDisplay() { if (is_string($this->description)) { return $this->description; } return is_string($this->callback) ? $this->callback : 'Closure'; } } console/Scheduling/ScheduleFinishCommand.php 0000644 00000001754 14736103231 0015207 0 ustar 00 <?php namespace Illuminate\Console\Scheduling; use Illuminate\Console\Command; class ScheduleFinishCommand extends Command { /** * The console command name. * * @var string */ protected $signature = 'schedule:finish {id} {code=0}'; /** * The console command description. * * @var string */ protected $description = 'Handle the completion of a scheduled command'; /** * Indicates whether the command should be shown in the Artisan command list. * * @var bool */ protected $hidden = true; /** * Execute the console command. * * @param \Illuminate\Console\Scheduling\Schedule $schedule * @return void */ public function handle(Schedule $schedule) { collect($schedule->events())->filter(function ($value) { return $value->mutexName() == $this->argument('id'); })->each->callAfterCallbacksWithExitCode($this->laravel, $this->argument('code')); } } console/Scheduling/CacheAware.php 0000644 00000000356 14736103231 0012773 0 ustar 00 <?php namespace Illuminate\Console\Scheduling; interface CacheAware { /** * Specify the cache store that should be used. * * @param string $store * @return $this */ public function useStore($store); } console/Scheduling/ScheduleRunCommand.php 0000644 00000007373 14736103231 0014536 0 ustar 00 <?php namespace Illuminate\Console\Scheduling; use Illuminate\Console\Command; use Illuminate\Console\Events\ScheduledTaskFinished; use Illuminate\Console\Events\ScheduledTaskSkipped; use Illuminate\Console\Events\ScheduledTaskStarting; use Illuminate\Contracts\Debug\ExceptionHandler; use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Support\Facades\Date; use Throwable; class ScheduleRunCommand extends Command { /** * The console command name. * * @var string */ protected $name = 'schedule:run'; /** * The console command description. * * @var string */ protected $description = 'Run the scheduled commands'; /** * The schedule instance. * * @var \Illuminate\Console\Scheduling\Schedule */ protected $schedule; /** * The 24 hour timestamp this scheduler command started running. * * @var \Illuminate\Support\Carbon */ protected $startedAt; /** * Check if any events ran. * * @var bool */ protected $eventsRan = false; /** * The event dispatcher. * * @var \Illuminate\Contracts\Events\Dispatcher */ protected $dispatcher; /** * The exception handler. * * @var \Illuminate\Contracts\Debug\ExceptionHandler */ protected $handler; /** * Create a new command instance. * * @return void */ public function __construct() { $this->startedAt = Date::now(); parent::__construct(); } /** * Execute the console command. * * @param \Illuminate\Console\Scheduling\Schedule $schedule * @param \Illuminate\Contracts\Events\Dispatcher $dispatcher * @param \Illuminate\Contracts\Debug\ExceptionHandler $handler * @return void */ public function handle(Schedule $schedule, Dispatcher $dispatcher, ExceptionHandler $handler) { $this->schedule = $schedule; $this->dispatcher = $dispatcher; $this->handler = $handler; foreach ($this->schedule->dueEvents($this->laravel) as $event) { if (! $event->filtersPass($this->laravel)) { $this->dispatcher->dispatch(new ScheduledTaskSkipped($event)); continue; } if ($event->onOneServer) { $this->runSingleServerEvent($event); } else { $this->runEvent($event); } $this->eventsRan = true; } if (! $this->eventsRan) { $this->info('No scheduled commands are ready to run.'); } } /** * Run the given single server event. * * @param \Illuminate\Console\Scheduling\Event $event * @return void */ protected function runSingleServerEvent($event) { if ($this->schedule->serverShouldRun($event, $this->startedAt)) { $this->runEvent($event); } else { $this->line('<info>Skipping command (has already run on another server):</info> '.$event->getSummaryForDisplay()); } } /** * Run the given event. * * @param \Illuminate\Console\Scheduling\Event $event * @return void */ protected function runEvent($event) { $this->line('<info>Running scheduled command:</info> '.$event->getSummaryForDisplay()); $this->dispatcher->dispatch(new ScheduledTaskStarting($event)); $start = microtime(true); try { $event->run($this->laravel); $this->dispatcher->dispatch(new ScheduledTaskFinished( $event, round(microtime(true) - $start, 2) )); $this->eventsRan = true; } catch (Throwable $e) { $this->handler->report($e); } } } console/Scheduling/CacheEventMutex.php 0000644 00000003375 14736103231 0014044 0 ustar 00 <?php namespace Illuminate\Console\Scheduling; use Illuminate\Contracts\Cache\Factory as Cache; class CacheEventMutex implements EventMutex, CacheAware { /** * The cache repository implementation. * * @var \Illuminate\Contracts\Cache\Factory */ public $cache; /** * The cache store that should be used. * * @var string|null */ public $store; /** * Create a new overlapping strategy. * * @param \Illuminate\Contracts\Cache\Factory $cache * @return void */ public function __construct(Cache $cache) { $this->cache = $cache; } /** * Attempt to obtain an event mutex for the given event. * * @param \Illuminate\Console\Scheduling\Event $event * @return bool */ public function create(Event $event) { return $this->cache->store($this->store)->add( $event->mutexName(), true, $event->expiresAt * 60 ); } /** * Determine if an event mutex exists for the given event. * * @param \Illuminate\Console\Scheduling\Event $event * @return bool */ public function exists(Event $event) { return $this->cache->store($this->store)->has($event->mutexName()); } /** * Clear the event mutex for the given event. * * @param \Illuminate\Console\Scheduling\Event $event * @return void */ public function forget(Event $event) { $this->cache->store($this->store)->forget($event->mutexName()); } /** * Specify the cache store that should be used. * * @param string $store * @return $this */ public function useStore($store) { $this->store = $store; return $this; } } console/Scheduling/CommandBuilder.php 0000644 00000004267 14736103231 0013702 0 ustar 00 <?php namespace Illuminate\Console\Scheduling; use Illuminate\Console\Application; use Illuminate\Support\ProcessUtils; class CommandBuilder { /** * Build the command for the given event. * * @param \Illuminate\Console\Scheduling\Event $event * @return string */ public function buildCommand(Event $event) { if ($event->runInBackground) { return $this->buildBackgroundCommand($event); } return $this->buildForegroundCommand($event); } /** * Build the command for running the event in the foreground. * * @param \Illuminate\Console\Scheduling\Event $event * @return string */ protected function buildForegroundCommand(Event $event) { $output = ProcessUtils::escapeArgument($event->output); return $this->ensureCorrectUser( $event, $event->command.($event->shouldAppendOutput ? ' >> ' : ' > ').$output.' 2>&1' ); } /** * Build the command for running the event in the background. * * @param \Illuminate\Console\Scheduling\Event $event * @return string */ protected function buildBackgroundCommand(Event $event) { $output = ProcessUtils::escapeArgument($event->output); $redirect = $event->shouldAppendOutput ? ' >> ' : ' > '; $finished = Application::formatCommandString('schedule:finish').' "'.$event->mutexName().'"'; if (windows_os()) { return 'start /b cmd /c "('.$event->command.' & '.$finished.' "%errorlevel%")'.$redirect.$output.' 2>&1"'; } return $this->ensureCorrectUser($event, '('.$event->command.$redirect.$output.' 2>&1 ; '.$finished.' "$?") > ' .ProcessUtils::escapeArgument($event->getDefaultOutput()).' 2>&1 &' ); } /** * Finalize the event's command syntax with the correct user. * * @param \Illuminate\Console\Scheduling\Event $event * @param string $command * @return string */ protected function ensureCorrectUser(Event $event, $command) { return $event->user && ! windows_os() ? 'sudo -u '.$event->user.' -- sh -c \''.$command.'\'' : $command; } } console/Command.php 0000644 00000012103 14736103231 0010272 0 ustar 00 <?php namespace Illuminate\Console; use Illuminate\Support\Traits\Macroable; use Symfony\Component\Console\Command\Command as SymfonyCommand; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class Command extends SymfonyCommand { use Concerns\CallsCommands, Concerns\HasParameters, Concerns\InteractsWithIO, Macroable; /** * The Laravel application instance. * * @var \Illuminate\Contracts\Foundation\Application */ protected $laravel; /** * The name and signature of the console command. * * @var string */ protected $signature; /** * The console command name. * * @var string */ protected $name; /** * The console command description. * * @var string|null */ protected $description; /** * The console command help text. * * @var string|null */ protected $help; /** * Indicates whether the command should be shown in the Artisan command list. * * @var bool */ protected $hidden = false; /** * Create a new console command instance. * * @return void */ public function __construct() { // We will go ahead and set the name, description, and parameters on console // commands just to make things a little easier on the developer. This is // so they don't have to all be manually specified in the constructors. if (isset($this->signature)) { $this->configureUsingFluentDefinition(); } else { parent::__construct($this->name); } // Once we have constructed the command, we'll set the description and other // related properties of the command. If a signature wasn't used to build // the command we'll set the arguments and the options on this command. $this->setDescription((string) $this->description); $this->setHelp((string) $this->help); $this->setHidden($this->isHidden()); if (! isset($this->signature)) { $this->specifyParameters(); } } /** * Configure the console command using a fluent definition. * * @return void */ protected function configureUsingFluentDefinition() { [$name, $arguments, $options] = Parser::parse($this->signature); parent::__construct($this->name = $name); // After parsing the signature we will spin through the arguments and options // and set them on this command. These will already be changed into proper // instances of these "InputArgument" and "InputOption" Symfony classes. $this->getDefinition()->addArguments($arguments); $this->getDefinition()->addOptions($options); } /** * Run the console command. * * @param \Symfony\Component\Console\Input\InputInterface $input * @param \Symfony\Component\Console\Output\OutputInterface $output * @return int */ public function run(InputInterface $input, OutputInterface $output) { $this->output = $this->laravel->make( OutputStyle::class, ['input' => $input, 'output' => $output] ); return parent::run( $this->input = $input, $this->output ); } /** * Execute the console command. * * @param \Symfony\Component\Console\Input\InputInterface $input * @param \Symfony\Component\Console\Output\OutputInterface $output * @return int */ protected function execute(InputInterface $input, OutputInterface $output) { return (int) $this->laravel->call([$this, 'handle']); } /** * Resolve the console command instance for the given command. * * @param \Symfony\Component\Console\Command\Command|string $command * @return \Symfony\Component\Console\Command\Command */ protected function resolveCommand($command) { if (! class_exists($command)) { return $this->getApplication()->find($command); } $command = $this->laravel->make($command); if ($command instanceof SymfonyCommand) { $command->setApplication($this->getApplication()); } if ($command instanceof self) { $command->setLaravel($this->getLaravel()); } return $command; } /** * {@inheritdoc} */ public function isHidden() { return $this->hidden; } /** * {@inheritdoc} */ public function setHidden(bool $hidden) { parent::setHidden($this->hidden = $hidden); return $this; } /** * Get the Laravel application instance. * * @return \Illuminate\Contracts\Foundation\Application */ public function getLaravel() { return $this->laravel; } /** * Set the Laravel application instance. * * @param \Illuminate\Contracts\Container\Container $laravel * @return void */ public function setLaravel($laravel) { $this->laravel = $laravel; } } support/Str.php 0000644 00000043676 14736103231 0007561 0 ustar 00 <?php namespace Illuminate\Support; use Illuminate\Support\Traits\Macroable; use Ramsey\Uuid\Codec\TimestampFirstCombCodec; use Ramsey\Uuid\Generator\CombGenerator; use Ramsey\Uuid\Uuid; use Ramsey\Uuid\UuidFactory; use voku\helper\ASCII; class Str { use Macroable; /** * The cache of snake-cased words. * * @var array */ protected static $snakeCache = []; /** * The cache of camel-cased words. * * @var array */ protected static $camelCache = []; /** * The cache of studly-cased words. * * @var array */ protected static $studlyCache = []; /** * The callback that should be used to generate UUIDs. * * @var callable */ protected static $uuidFactory; /** * Get a new stringable object from the given string. * * @param string $string * @return \Illuminate\Support\Stringable */ public static function of($string) { return new Stringable($string); } /** * Return the remainder of a string after the first occurrence of a given value. * * @param string $subject * @param string $search * @return string */ public static function after($subject, $search) { return $search === '' ? $subject : array_reverse(explode($search, $subject, 2))[0]; } /** * Return the remainder of a string after the last occurrence of a given value. * * @param string $subject * @param string $search * @return string */ public static function afterLast($subject, $search) { if ($search === '') { return $subject; } $position = strrpos($subject, (string) $search); if ($position === false) { return $subject; } return substr($subject, $position + strlen($search)); } /** * Transliterate a UTF-8 value to ASCII. * * @param string $value * @param string $language * @return string */ public static function ascii($value, $language = 'en') { return ASCII::to_ascii((string) $value, $language); } /** * Get the portion of a string before the first occurrence of a given value. * * @param string $subject * @param string $search * @return string */ public static function before($subject, $search) { return $search === '' ? $subject : explode($search, $subject)[0]; } /** * Get the portion of a string before the last occurrence of a given value. * * @param string $subject * @param string $search * @return string */ public static function beforeLast($subject, $search) { if ($search === '') { return $subject; } $pos = mb_strrpos($subject, $search); if ($pos === false) { return $subject; } return static::substr($subject, 0, $pos); } /** * Get the portion of a string between two given values. * * @param string $subject * @param string $from * @param string $to * @return string */ public static function between($subject, $from, $to) { if ($from === '' || $to === '') { return $subject; } return static::beforeLast(static::after($subject, $from), $to); } /** * Convert a value to camel case. * * @param string $value * @return string */ public static function camel($value) { if (isset(static::$camelCache[$value])) { return static::$camelCache[$value]; } return static::$camelCache[$value] = lcfirst(static::studly($value)); } /** * Determine if a given string contains a given substring. * * @param string $haystack * @param string|string[] $needles * @return bool */ public static function contains($haystack, $needles) { foreach ((array) $needles as $needle) { if ($needle !== '' && mb_strpos($haystack, $needle) !== false) { return true; } } return false; } /** * Determine if a given string contains all array values. * * @param string $haystack * @param string[] $needles * @return bool */ public static function containsAll($haystack, array $needles) { foreach ($needles as $needle) { if (! static::contains($haystack, $needle)) { return false; } } return true; } /** * Determine if a given string ends with a given substring. * * @param string $haystack * @param string|string[] $needles * @return bool */ public static function endsWith($haystack, $needles) { foreach ((array) $needles as $needle) { if (substr($haystack, -strlen($needle)) === (string) $needle) { return true; } } return false; } /** * Cap a string with a single instance of a given value. * * @param string $value * @param string $cap * @return string */ public static function finish($value, $cap) { $quoted = preg_quote($cap, '/'); return preg_replace('/(?:'.$quoted.')+$/u', '', $value).$cap; } /** * Determine if a given string matches a given pattern. * * @param string|array $pattern * @param string $value * @return bool */ public static function is($pattern, $value) { $patterns = Arr::wrap($pattern); if (empty($patterns)) { return false; } foreach ($patterns as $pattern) { // If the given value is an exact match we can of course return true right // from the beginning. Otherwise, we will translate asterisks and do an // actual pattern match against the two strings to see if they match. if ($pattern == $value) { return true; } $pattern = preg_quote($pattern, '#'); // Asterisks are translated into zero-or-more regular expression wildcards // to make it convenient to check if the strings starts with the given // pattern such as "library/*", making any string check convenient. $pattern = str_replace('\*', '.*', $pattern); if (preg_match('#^'.$pattern.'\z#u', $value) === 1) { return true; } } return false; } /** * Determine if a given string is 7 bit ASCII. * * @param string $value * @return bool */ public static function isAscii($value) { return ASCII::is_ascii((string) $value); } /** * Determine if a given string is a valid UUID. * * @param string $value * @return bool */ public static function isUuid($value) { if (! is_string($value)) { return false; } return preg_match('/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iD', $value) > 0; } /** * Convert a string to kebab case. * * @param string $value * @return string */ public static function kebab($value) { return static::snake($value, '-'); } /** * Return the length of the given string. * * @param string $value * @param string|null $encoding * @return int */ public static function length($value, $encoding = null) { if ($encoding) { return mb_strlen($value, $encoding); } return mb_strlen($value); } /** * Limit the number of characters in a string. * * @param string $value * @param int $limit * @param string $end * @return string */ public static function limit($value, $limit = 100, $end = '...') { if (mb_strwidth($value, 'UTF-8') <= $limit) { return $value; } return rtrim(mb_strimwidth($value, 0, $limit, '', 'UTF-8')).$end; } /** * Convert the given string to lower-case. * * @param string $value * @return string */ public static function lower($value) { return mb_strtolower($value, 'UTF-8'); } /** * Limit the number of words in a string. * * @param string $value * @param int $words * @param string $end * @return string */ public static function words($value, $words = 100, $end = '...') { preg_match('/^\s*+(?:\S++\s*+){1,'.$words.'}/u', $value, $matches); if (! isset($matches[0]) || static::length($value) === static::length($matches[0])) { return $value; } return rtrim($matches[0]).$end; } /** * Parse a Class[@]method style callback into class and method. * * @param string $callback * @param string|null $default * @return array<int, string|null> */ public static function parseCallback($callback, $default = null) { return static::contains($callback, '@') ? explode('@', $callback, 2) : [$callback, $default]; } /** * Get the plural form of an English word. * * @param string $value * @param int $count * @return string */ public static function plural($value, $count = 2) { return Pluralizer::plural($value, $count); } /** * Pluralize the last word of an English, studly caps case string. * * @param string $value * @param int $count * @return string */ public static function pluralStudly($value, $count = 2) { $parts = preg_split('/(.)(?=[A-Z])/u', $value, -1, PREG_SPLIT_DELIM_CAPTURE); $lastWord = array_pop($parts); return implode('', $parts).self::plural($lastWord, $count); } /** * Generate a more truly "random" alpha-numeric string. * * @param int $length * @return string */ public static function random($length = 16) { $string = ''; while (($len = strlen($string)) < $length) { $size = $length - $len; $bytes = random_bytes($size); $string .= substr(str_replace(['/', '+', '='], '', base64_encode($bytes)), 0, $size); } return $string; } /** * Replace a given value in the string sequentially with an array. * * @param string $search * @param array<int|string, string> $replace * @param string $subject * @return string */ public static function replaceArray($search, array $replace, $subject) { $segments = explode($search, $subject); $result = array_shift($segments); foreach ($segments as $segment) { $result .= (array_shift($replace) ?? $search).$segment; } return $result; } /** * Replace the first occurrence of a given value in the string. * * @param string $search * @param string $replace * @param string $subject * @return string */ public static function replaceFirst($search, $replace, $subject) { if ($search == '') { return $subject; } $position = strpos($subject, $search); if ($position !== false) { return substr_replace($subject, $replace, $position, strlen($search)); } return $subject; } /** * Replace the last occurrence of a given value in the string. * * @param string $search * @param string $replace * @param string $subject * @return string */ public static function replaceLast($search, $replace, $subject) { $position = strrpos($subject, $search); if ($position !== false) { return substr_replace($subject, $replace, $position, strlen($search)); } return $subject; } /** * Begin a string with a single instance of a given value. * * @param string $value * @param string $prefix * @return string */ public static function start($value, $prefix) { $quoted = preg_quote($prefix, '/'); return $prefix.preg_replace('/^(?:'.$quoted.')+/u', '', $value); } /** * Convert the given string to upper-case. * * @param string $value * @return string */ public static function upper($value) { return mb_strtoupper($value, 'UTF-8'); } /** * Convert the given string to title case. * * @param string $value * @return string */ public static function title($value) { return mb_convert_case($value, MB_CASE_TITLE, 'UTF-8'); } /** * Get the singular form of an English word. * * @param string $value * @return string */ public static function singular($value) { return Pluralizer::singular($value); } /** * Generate a URL friendly "slug" from a given string. * * @param string $title * @param string $separator * @param string|null $language * @return string */ public static function slug($title, $separator = '-', $language = 'en') { $title = $language ? static::ascii($title, $language) : $title; // Convert all dashes/underscores into separator $flip = $separator === '-' ? '_' : '-'; $title = preg_replace('!['.preg_quote($flip).']+!u', $separator, $title); // Replace @ with the word 'at' $title = str_replace('@', $separator.'at'.$separator, $title); // Remove all characters that are not the separator, letters, numbers, or whitespace. $title = preg_replace('![^'.preg_quote($separator).'\pL\pN\s]+!u', '', static::lower($title)); // Replace all separator characters and whitespace by a single separator $title = preg_replace('!['.preg_quote($separator).'\s]+!u', $separator, $title); return trim($title, $separator); } /** * Convert a string to snake case. * * @param string $value * @param string $delimiter * @return string */ public static function snake($value, $delimiter = '_') { $key = $value; if (isset(static::$snakeCache[$key][$delimiter])) { return static::$snakeCache[$key][$delimiter]; } if (! ctype_lower($value)) { $value = preg_replace('/\s+/u', '', ucwords($value)); $value = static::lower(preg_replace('/(.)(?=[A-Z])/u', '$1'.$delimiter, $value)); } return static::$snakeCache[$key][$delimiter] = $value; } /** * Determine if a given string starts with a given substring. * * @param string $haystack * @param string|string[] $needles * @return bool */ public static function startsWith($haystack, $needles) { foreach ((array) $needles as $needle) { if ((string) $needle !== '' && strncmp($haystack, $needle, strlen($needle)) === 0) { return true; } } return false; } /** * Convert a value to studly caps case. * * @param string $value * @return string */ public static function studly($value) { $key = $value; if (isset(static::$studlyCache[$key])) { return static::$studlyCache[$key]; } $value = ucwords(str_replace(['-', '_'], ' ', $value)); return static::$studlyCache[$key] = str_replace(' ', '', $value); } /** * Returns the portion of string specified by the start and length parameters. * * @param string $string * @param int $start * @param int|null $length * @return string */ public static function substr($string, $start, $length = null) { return mb_substr($string, $start, $length, 'UTF-8'); } /** * Returns the number of substring occurrences. * * @param string $haystack * @param string $needle * @param int $offset * @param int|null $length * @return int */ public static function substrCount($haystack, $needle, $offset = 0, $length = null) { if (! is_null($length)) { return substr_count($haystack, $needle, $offset, $length); } else { return substr_count($haystack, $needle, $offset); } } /** * Make a string's first character uppercase. * * @param string $string * @return string */ public static function ucfirst($string) { return static::upper(static::substr($string, 0, 1)).static::substr($string, 1); } /** * Generate a UUID (version 4). * * @return \Ramsey\Uuid\UuidInterface */ public static function uuid() { return static::$uuidFactory ? call_user_func(static::$uuidFactory) : Uuid::uuid4(); } /** * Generate a time-ordered UUID (version 4). * * @return \Ramsey\Uuid\UuidInterface */ public static function orderedUuid() { if (static::$uuidFactory) { return call_user_func(static::$uuidFactory); } $factory = new UuidFactory(); $factory->setRandomGenerator(new CombGenerator( $factory->getRandomGenerator(), $factory->getNumberConverter() )); $factory->setCodec(new TimestampFirstCombCodec( $factory->getUuidBuilder() )); return $factory->uuid4(); } /** * Set the callable that will be used to generate UUIDs. * * @param callable|null $factory * @return void */ public static function createUuidsUsing(callable $factory = null) { static::$uuidFactory = $factory; } /** * Indicate that UUIDs should be created normally and not using a custom factory. * * @return void */ public static function createUuidsNormally() { static::$uuidFactory = null; } } support/Env.php 0000644 00000005205 14736103231 0007523 0 ustar 00 <?php namespace Illuminate\Support; use Dotenv\Repository\Adapter\EnvConstAdapter; use Dotenv\Repository\Adapter\PutenvAdapter; use Dotenv\Repository\Adapter\ServerConstAdapter; use Dotenv\Repository\RepositoryBuilder; use PhpOption\Option; class Env { /** * Indicates if the putenv adapter is enabled. * * @var bool */ protected static $putenv = true; /** * The environment repository instance. * * @var \Dotenv\Repository\RepositoryInterface|null */ protected static $repository; /** * Enable the putenv adapter. * * @return void */ public static function enablePutenv() { static::$putenv = true; static::$repository = null; } /** * Disable the putenv adapter. * * @return void */ public static function disablePutenv() { static::$putenv = false; static::$repository = null; } /** * Get the environment repository instance. * * @return \Dotenv\Repository\RepositoryInterface */ public static function getRepository() { if (static::$repository === null) { $adapters = array_merge( [new EnvConstAdapter, new ServerConstAdapter], static::$putenv ? [new PutenvAdapter] : [] ); static::$repository = RepositoryBuilder::create() ->withReaders($adapters) ->withWriters($adapters) ->immutable() ->make(); } return static::$repository; } /** * Gets the value of an environment variable. * * @param string $key * @param mixed $default * @return mixed */ public static function get($key, $default = null) { return Option::fromValue(static::getRepository()->get($key)) ->map(function ($value) { switch (strtolower($value)) { case 'true': case '(true)': return true; case 'false': case '(false)': return false; case 'empty': case '(empty)': return ''; case 'null': case '(null)': return; } if (preg_match('/\A([\'"])(.*)\1\z/', $value, $matches)) { return $matches[2]; } return $value; }) ->getOrCall(function () use ($default) { return value($default); }); } } support/Fluent.php 0000644 00000007447 14736103231 0010242 0 ustar 00 <?php namespace Illuminate\Support; use ArrayAccess; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Contracts\Support\Jsonable; use JsonSerializable; class Fluent implements Arrayable, ArrayAccess, Jsonable, JsonSerializable { /** * All of the attributes set on the fluent instance. * * @var array */ protected $attributes = []; /** * Create a new fluent instance. * * @param array|object $attributes * @return void */ public function __construct($attributes = []) { foreach ($attributes as $key => $value) { $this->attributes[$key] = $value; } } /** * Get an attribute from the fluent instance. * * @param string $key * @param mixed $default * @return mixed */ public function get($key, $default = null) { if (array_key_exists($key, $this->attributes)) { return $this->attributes[$key]; } return value($default); } /** * Get the attributes from the fluent instance. * * @return array */ public function getAttributes() { return $this->attributes; } /** * Convert the fluent instance to an array. * * @return array */ public function toArray() { return $this->attributes; } /** * Convert the object into something JSON serializable. * * @return array */ public function jsonSerialize() { return $this->toArray(); } /** * Convert the fluent instance to JSON. * * @param int $options * @return string */ public function toJson($options = 0) { return json_encode($this->jsonSerialize(), $options); } /** * Determine if the given offset exists. * * @param string $offset * @return bool */ public function offsetExists($offset) { return isset($this->attributes[$offset]); } /** * Get the value for a given offset. * * @param string $offset * @return mixed */ public function offsetGet($offset) { return $this->get($offset); } /** * Set the value at the given offset. * * @param string $offset * @param mixed $value * @return void */ public function offsetSet($offset, $value) { $this->attributes[$offset] = $value; } /** * Unset the value at the given offset. * * @param string $offset * @return void */ public function offsetUnset($offset) { unset($this->attributes[$offset]); } /** * Handle dynamic calls to the fluent instance to set attributes. * * @param string $method * @param array $parameters * @return $this */ public function __call($method, $parameters) { $this->attributes[$method] = count($parameters) > 0 ? $parameters[0] : true; return $this; } /** * Dynamically retrieve the value of an attribute. * * @param string $key * @return mixed */ public function __get($key) { return $this->get($key); } /** * Dynamically set the value of an attribute. * * @param string $key * @param mixed $value * @return void */ public function __set($key, $value) { $this->offsetSet($key, $value); } /** * Dynamically check if an attribute is set. * * @param string $key * @return bool */ public function __isset($key) { return $this->offsetExists($key); } /** * Dynamically unset an attribute. * * @param string $key * @return void */ public function __unset($key) { $this->offsetUnset($key); } } support/ServiceProvider.php 0000644 00000022425 14736103231 0012111 0 ustar 00 <?php namespace Illuminate\Support; use Illuminate\Console\Application as Artisan; use Illuminate\Contracts\Foundation\CachesConfiguration; use Illuminate\Contracts\Foundation\CachesRoutes; use Illuminate\Contracts\Support\DeferrableProvider; use Illuminate\Database\Eloquent\Factory as ModelFactory; use Illuminate\View\Compilers\BladeCompiler; abstract class ServiceProvider { /** * The application instance. * * @var \Illuminate\Contracts\Foundation\Application */ protected $app; /** * The paths that should be published. * * @var array */ public static $publishes = []; /** * The paths that should be published by group. * * @var array */ public static $publishGroups = []; /** * Create a new service provider instance. * * @param \Illuminate\Contracts\Foundation\Application $app * @return void */ public function __construct($app) { $this->app = $app; } /** * Register any application services. * * @return void */ public function register() { // } /** * Merge the given configuration with the existing configuration. * * @param string $path * @param string $key * @return void */ protected function mergeConfigFrom($path, $key) { if (! ($this->app instanceof CachesConfiguration && $this->app->configurationIsCached())) { $this->app['config']->set($key, array_merge( require $path, $this->app['config']->get($key, []) )); } } /** * Load the given routes file if routes are not already cached. * * @param string $path * @return void */ protected function loadRoutesFrom($path) { if (! ($this->app instanceof CachesRoutes && $this->app->routesAreCached())) { require $path; } } /** * Register a view file namespace. * * @param string|array $path * @param string $namespace * @return void */ protected function loadViewsFrom($path, $namespace) { $this->callAfterResolving('view', function ($view) use ($path, $namespace) { if (isset($this->app->config['view']['paths']) && is_array($this->app->config['view']['paths'])) { foreach ($this->app->config['view']['paths'] as $viewPath) { if (is_dir($appPath = $viewPath.'/vendor/'.$namespace)) { $view->addNamespace($namespace, $appPath); } } } $view->addNamespace($namespace, $path); }); } /** * Register the given view components with a custom prefix. * * @param string $prefix * @param array $components * @return void */ protected function loadViewComponentsAs($prefix, array $components) { $this->callAfterResolving(BladeCompiler::class, function ($blade) use ($prefix, $components) { foreach ($components as $alias => $component) { $blade->component($component, is_string($alias) ? $alias : null, $prefix); } }); } /** * Register a translation file namespace. * * @param string $path * @param string $namespace * @return void */ protected function loadTranslationsFrom($path, $namespace) { $this->callAfterResolving('translator', function ($translator) use ($path, $namespace) { $translator->addNamespace($namespace, $path); }); } /** * Register a JSON translation file path. * * @param string $path * @return void */ protected function loadJsonTranslationsFrom($path) { $this->callAfterResolving('translator', function ($translator) use ($path) { $translator->addJsonPath($path); }); } /** * Register database migration paths. * * @param array|string $paths * @return void */ protected function loadMigrationsFrom($paths) { $this->callAfterResolving('migrator', function ($migrator) use ($paths) { foreach ((array) $paths as $path) { $migrator->path($path); } }); } /** * Register Eloquent model factory paths. * * @param array|string $paths * @return void */ protected function loadFactoriesFrom($paths) { $this->callAfterResolving(ModelFactory::class, function ($factory) use ($paths) { foreach ((array) $paths as $path) { $factory->load($path); } }); } /** * Setup an after resolving listener, or fire immediately if already resolved. * * @param string $name * @param callable $callback * @return void */ protected function callAfterResolving($name, $callback) { $this->app->afterResolving($name, $callback); if ($this->app->resolved($name)) { $callback($this->app->make($name), $this->app); } } /** * Register paths to be published by the publish command. * * @param array $paths * @param mixed $groups * @return void */ protected function publishes(array $paths, $groups = null) { $this->ensurePublishArrayInitialized($class = static::class); static::$publishes[$class] = array_merge(static::$publishes[$class], $paths); foreach ((array) $groups as $group) { $this->addPublishGroup($group, $paths); } } /** * Ensure the publish array for the service provider is initialized. * * @param string $class * @return void */ protected function ensurePublishArrayInitialized($class) { if (! array_key_exists($class, static::$publishes)) { static::$publishes[$class] = []; } } /** * Add a publish group / tag to the service provider. * * @param string $group * @param array $paths * @return void */ protected function addPublishGroup($group, $paths) { if (! array_key_exists($group, static::$publishGroups)) { static::$publishGroups[$group] = []; } static::$publishGroups[$group] = array_merge( static::$publishGroups[$group], $paths ); } /** * Get the paths to publish. * * @param string|null $provider * @param string|null $group * @return array */ public static function pathsToPublish($provider = null, $group = null) { if (! is_null($paths = static::pathsForProviderOrGroup($provider, $group))) { return $paths; } return collect(static::$publishes)->reduce(function ($paths, $p) { return array_merge($paths, $p); }, []); } /** * Get the paths for the provider or group (or both). * * @param string|null $provider * @param string|null $group * @return array */ protected static function pathsForProviderOrGroup($provider, $group) { if ($provider && $group) { return static::pathsForProviderAndGroup($provider, $group); } elseif ($group && array_key_exists($group, static::$publishGroups)) { return static::$publishGroups[$group]; } elseif ($provider && array_key_exists($provider, static::$publishes)) { return static::$publishes[$provider]; } elseif ($group || $provider) { return []; } } /** * Get the paths for the provider and group. * * @param string $provider * @param string $group * @return array */ protected static function pathsForProviderAndGroup($provider, $group) { if (! empty(static::$publishes[$provider]) && ! empty(static::$publishGroups[$group])) { return array_intersect_key(static::$publishes[$provider], static::$publishGroups[$group]); } return []; } /** * Get the service providers available for publishing. * * @return array */ public static function publishableProviders() { return array_keys(static::$publishes); } /** * Get the groups available for publishing. * * @return array */ public static function publishableGroups() { return array_keys(static::$publishGroups); } /** * Register the package's custom Artisan commands. * * @param array|mixed $commands * @return void */ public function commands($commands) { $commands = is_array($commands) ? $commands : func_get_args(); Artisan::starting(function ($artisan) use ($commands) { $artisan->resolveCommands($commands); }); } /** * Get the services provided by the provider. * * @return array */ public function provides() { return []; } /** * Get the events that trigger this service provider to register. * * @return array */ public function when() { return []; } /** * Determine if the provider is deferred. * * @return bool */ public function isDeferred() { return $this instanceof DeferrableProvider; } } support/Testing/Fakes/NotificationFake.php 0000644 00000017563 14736103231 0014670 0 ustar 00 <?php namespace Illuminate\Support\Testing\Fakes; use Closure; use Exception; use Illuminate\Contracts\Notifications\Dispatcher as NotificationDispatcher; use Illuminate\Contracts\Notifications\Factory as NotificationFactory; use Illuminate\Contracts\Translation\HasLocalePreference; use Illuminate\Support\Collection; use Illuminate\Support\Str; use Illuminate\Support\Traits\Macroable; use Illuminate\Support\Traits\ReflectsClosures; use PHPUnit\Framework\Assert as PHPUnit; class NotificationFake implements NotificationDispatcher, NotificationFactory { use Macroable, ReflectsClosures; /** * All of the notifications that have been sent. * * @var array */ protected $notifications = []; /** * Locale used when sending notifications. * * @var string|null */ public $locale; /** * Assert if a notification was sent based on a truth-test callback. * * @param mixed $notifiable * @param string|\Closure $notification * @param callable|null $callback * @return void * * @throws \Exception */ public function assertSentTo($notifiable, $notification, $callback = null) { if (is_array($notifiable) || $notifiable instanceof Collection) { if (count($notifiable) === 0) { throw new Exception('No notifiable given.'); } foreach ($notifiable as $singleNotifiable) { $this->assertSentTo($singleNotifiable, $notification, $callback); } return; } if ($notification instanceof Closure) { [$notification, $callback] = [$this->firstClosureParameterType($notification), $notification]; } if (is_numeric($callback)) { return $this->assertSentToTimes($notifiable, $notification, $callback); } PHPUnit::assertTrue( $this->sent($notifiable, $notification, $callback)->count() > 0, "The expected [{$notification}] notification was not sent." ); } /** * Assert if a notification was sent a number of times. * * @param mixed $notifiable * @param string $notification * @param int $times * @return void */ public function assertSentToTimes($notifiable, $notification, $times = 1) { $count = $this->sent($notifiable, $notification)->count(); PHPUnit::assertSame( $times, $count, "Expected [{$notification}] to be sent {$times} times, but was sent {$count} times." ); } /** * Determine if a notification was sent based on a truth-test callback. * * @param mixed $notifiable * @param string|\Closure $notification * @param callable|null $callback * @return void * * @throws \Exception */ public function assertNotSentTo($notifiable, $notification, $callback = null) { if (is_array($notifiable) || $notifiable instanceof Collection) { if (count($notifiable) === 0) { throw new Exception('No notifiable given.'); } foreach ($notifiable as $singleNotifiable) { $this->assertNotSentTo($singleNotifiable, $notification, $callback); } return; } if ($notification instanceof Closure) { [$notification, $callback] = [$this->firstClosureParameterType($notification), $notification]; } PHPUnit::assertCount( 0, $this->sent($notifiable, $notification, $callback), "The unexpected [{$notification}] notification was sent." ); } /** * Assert that no notifications were sent. * * @return void */ public function assertNothingSent() { PHPUnit::assertEmpty($this->notifications, 'Notifications were sent unexpectedly.'); } /** * Assert the total amount of times a notification was sent. * * @param int $expectedCount * @param string $notification * @return void */ public function assertTimesSent($expectedCount, $notification) { $actualCount = collect($this->notifications) ->flatten(1) ->reduce(function ($count, $sent) use ($notification) { return $count + count($sent[$notification] ?? []); }, 0); PHPUnit::assertSame( $expectedCount, $actualCount, "Expected [{$notification}] to be sent {$expectedCount} times, but was sent {$actualCount} times." ); } /** * Get all of the notifications matching a truth-test callback. * * @param mixed $notifiable * @param string $notification * @param callable|null $callback * @return \Illuminate\Support\Collection */ public function sent($notifiable, $notification, $callback = null) { if (! $this->hasSent($notifiable, $notification)) { return collect(); } $callback = $callback ?: function () { return true; }; $notifications = collect($this->notificationsFor($notifiable, $notification)); return $notifications->filter(function ($arguments) use ($callback) { return $callback(...array_values($arguments)); })->pluck('notification'); } /** * Determine if there are more notifications left to inspect. * * @param mixed $notifiable * @param string $notification * @return bool */ public function hasSent($notifiable, $notification) { return ! empty($this->notificationsFor($notifiable, $notification)); } /** * Get all of the notifications for a notifiable entity by type. * * @param mixed $notifiable * @param string $notification * @return array */ protected function notificationsFor($notifiable, $notification) { return $this->notifications[get_class($notifiable)][$notifiable->getKey()][$notification] ?? []; } /** * Send the given notification to the given notifiable entities. * * @param \Illuminate\Support\Collection|array|mixed $notifiables * @param mixed $notification * @return void */ public function send($notifiables, $notification) { return $this->sendNow($notifiables, $notification); } /** * Send the given notification immediately. * * @param \Illuminate\Support\Collection|array|mixed $notifiables * @param mixed $notification * @param array|null $channels * @return void */ public function sendNow($notifiables, $notification, array $channels = null) { if (! $notifiables instanceof Collection && ! is_array($notifiables)) { $notifiables = [$notifiables]; } foreach ($notifiables as $notifiable) { if (! $notification->id) { $notification->id = Str::uuid()->toString(); } $this->notifications[get_class($notifiable)][$notifiable->getKey()][get_class($notification)][] = [ 'notification' => $notification, 'channels' => $channels ?: $notification->via($notifiable), 'notifiable' => $notifiable, 'locale' => $notification->locale ?? $this->locale ?? value(function () use ($notifiable) { if ($notifiable instanceof HasLocalePreference) { return $notifiable->preferredLocale(); } }), ]; } } /** * Get a channel instance by name. * * @param string|null $name * @return mixed */ public function channel($name = null) { // } /** * Set the locale of notifications. * * @param string $locale * @return $this */ public function locale($locale) { $this->locale = $locale; return $this; } } support/Testing/Fakes/MailFake.php 0000644 00000023253 14736103231 0013115 0 ustar 00 <?php namespace Illuminate\Support\Testing\Fakes; use Closure; use Illuminate\Contracts\Mail\Factory; use Illuminate\Contracts\Mail\Mailable; use Illuminate\Contracts\Mail\Mailer; use Illuminate\Contracts\Mail\MailQueue; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Support\Traits\ReflectsClosures; use PHPUnit\Framework\Assert as PHPUnit; class MailFake implements Factory, Mailer, MailQueue { use ReflectsClosures; /** * The mailer currently being used to send a message. * * @var string */ protected $currentMailer; /** * All of the mailables that have been sent. * * @var array */ protected $mailables = []; /** * All of the mailables that have been queued. * * @var array */ protected $queuedMailables = []; /** * Assert if a mailable was sent based on a truth-test callback. * * @param string|\Closure $mailable * @param callable|int|null $callback * @return void */ public function assertSent($mailable, $callback = null) { if ($mailable instanceof Closure) { [$mailable, $callback] = [$this->firstClosureParameterType($mailable), $mailable]; } if (is_numeric($callback)) { return $this->assertSentTimes($mailable, $callback); } $message = "The expected [{$mailable}] mailable was not sent."; if (count($this->queuedMailables) > 0) { $message .= ' Did you mean to use assertQueued() instead?'; } PHPUnit::assertTrue( $this->sent($mailable, $callback)->count() > 0, $message ); } /** * Assert if a mailable was sent a number of times. * * @param string $mailable * @param int $times * @return void */ protected function assertSentTimes($mailable, $times = 1) { $count = $this->sent($mailable)->count(); PHPUnit::assertSame( $times, $count, "The expected [{$mailable}] mailable was sent {$count} times instead of {$times} times." ); } /** * Determine if a mailable was not sent based on a truth-test callback. * * @param string $mailable * @param callable|null $callback * @return void */ public function assertNotSent($mailable, $callback = null) { PHPUnit::assertCount( 0, $this->sent($mailable, $callback), "The unexpected [{$mailable}] mailable was sent." ); } /** * Assert that no mailables were sent. * * @return void */ public function assertNothingSent() { $mailableNames = collect($this->mailables)->map(function ($mailable) { return get_class($mailable); })->join(', '); PHPUnit::assertEmpty($this->mailables, 'The following mailables were sent unexpectedly: '.$mailableNames); } /** * Assert if a mailable was queued based on a truth-test callback. * * @param string|\Closure $mailable * @param callable|int|null $callback * @return void */ public function assertQueued($mailable, $callback = null) { if ($mailable instanceof Closure) { [$mailable, $callback] = [$this->firstClosureParameterType($mailable), $mailable]; } if (is_numeric($callback)) { return $this->assertQueuedTimes($mailable, $callback); } PHPUnit::assertTrue( $this->queued($mailable, $callback)->count() > 0, "The expected [{$mailable}] mailable was not queued." ); } /** * Assert if a mailable was queued a number of times. * * @param string $mailable * @param int $times * @return void */ protected function assertQueuedTimes($mailable, $times = 1) { $count = $this->queued($mailable)->count(); PHPUnit::assertSame( $times, $count, "The expected [{$mailable}] mailable was queued {$count} times instead of {$times} times." ); } /** * Determine if a mailable was not queued based on a truth-test callback. * * @param string $mailable * @param callable|null $callback * @return void */ public function assertNotQueued($mailable, $callback = null) { PHPUnit::assertCount( 0, $this->queued($mailable, $callback), "The unexpected [{$mailable}] mailable was queued." ); } /** * Assert that no mailables were queued. * * @return void */ public function assertNothingQueued() { $mailableNames = collect($this->queuedMailables)->map(function ($mailable) { return get_class($mailable); })->join(', '); PHPUnit::assertEmpty($this->queuedMailables, 'The following mailables were queued unexpectedly: '.$mailableNames); } /** * Get all of the mailables matching a truth-test callback. * * @param string $mailable * @param callable|null $callback * @return \Illuminate\Support\Collection */ public function sent($mailable, $callback = null) { if (! $this->hasSent($mailable)) { return collect(); } $callback = $callback ?: function () { return true; }; return $this->mailablesOf($mailable)->filter(function ($mailable) use ($callback) { return $callback($mailable); }); } /** * Determine if the given mailable has been sent. * * @param string $mailable * @return bool */ public function hasSent($mailable) { return $this->mailablesOf($mailable)->count() > 0; } /** * Get all of the queued mailables matching a truth-test callback. * * @param string $mailable * @param callable|null $callback * @return \Illuminate\Support\Collection */ public function queued($mailable, $callback = null) { if (! $this->hasQueued($mailable)) { return collect(); } $callback = $callback ?: function () { return true; }; return $this->queuedMailablesOf($mailable)->filter(function ($mailable) use ($callback) { return $callback($mailable); }); } /** * Determine if the given mailable has been queued. * * @param string $mailable * @return bool */ public function hasQueued($mailable) { return $this->queuedMailablesOf($mailable)->count() > 0; } /** * Get all of the mailed mailables for a given type. * * @param string $type * @return \Illuminate\Support\Collection */ protected function mailablesOf($type) { return collect($this->mailables)->filter(function ($mailable) use ($type) { return $mailable instanceof $type; }); } /** * Get all of the mailed mailables for a given type. * * @param string $type * @return \Illuminate\Support\Collection */ protected function queuedMailablesOf($type) { return collect($this->queuedMailables)->filter(function ($mailable) use ($type) { return $mailable instanceof $type; }); } /** * Get a mailer instance by name. * * @param string|null $name * @return \Illuminate\Mail\Mailer */ public function mailer($name = null) { $this->currentMailer = $name; return $this; } /** * Begin the process of mailing a mailable class instance. * * @param mixed $users * @return \Illuminate\Mail\PendingMail */ public function to($users) { return (new PendingMailFake($this))->to($users); } /** * Begin the process of mailing a mailable class instance. * * @param mixed $users * @return \Illuminate\Mail\PendingMail */ public function bcc($users) { return (new PendingMailFake($this))->bcc($users); } /** * Send a new message with only a raw text part. * * @param string $text * @param \Closure|string $callback * @return void */ public function raw($text, $callback) { // } /** * Send a new message using a view. * * @param string|array $view * @param array $data * @param \Closure|string|null $callback * @return void */ public function send($view, array $data = [], $callback = null) { if (! $view instanceof Mailable) { return; } $view->mailer($this->currentMailer); $this->currentMailer = null; if ($view instanceof ShouldQueue) { return $this->queue($view, $data); } $this->mailables[] = $view; } /** * Queue a new e-mail message for sending. * * @param string|array $view * @param string|null $queue * @return mixed */ public function queue($view, $queue = null) { if (! $view instanceof Mailable) { return; } $view->mailer($this->currentMailer); $this->currentMailer = null; $this->queuedMailables[] = $view; } /** * Queue a new e-mail message for sending after (n) seconds. * * @param \DateTimeInterface|\DateInterval|int $delay * @param \Illuminate\Contracts\Mail\Mailable|string|array $view * @param string|null $queue * @return mixed */ public function later($delay, $view, $queue = null) { $this->queue($view, $queue); } /** * Get the array of failed recipients. * * @return array */ public function failures() { return []; } } support/Testing/Fakes/BusFake.php 0000644 00000024056 14736103231 0012766 0 ustar 00 <?php namespace Illuminate\Support\Testing\Fakes; use Closure; use Illuminate\Contracts\Bus\QueueingDispatcher; use Illuminate\Support\Arr; use Illuminate\Support\Traits\ReflectsClosures; use PHPUnit\Framework\Assert as PHPUnit; class BusFake implements QueueingDispatcher { use ReflectsClosures; /** * The original Bus dispatcher implementation. * * @var \Illuminate\Contracts\Bus\QueueingDispatcher */ protected $dispatcher; /** * The job types that should be intercepted instead of dispatched. * * @var array */ protected $jobsToFake; /** * The commands that have been dispatched. * * @var array */ protected $commands = []; /** * The commands that have been dispatched after the response has been sent. * * @var array */ protected $commandsAfterResponse = []; /** * Create a new bus fake instance. * * @param \Illuminate\Contracts\Bus\QueueingDispatcher $dispatcher * @param array|string $jobsToFake * @return void */ public function __construct(QueueingDispatcher $dispatcher, $jobsToFake = []) { $this->dispatcher = $dispatcher; $this->jobsToFake = Arr::wrap($jobsToFake); } /** * Assert if a job was dispatched based on a truth-test callback. * * @param string|\Closure $command * @param callable|int|null $callback * @return void */ public function assertDispatched($command, $callback = null) { if ($command instanceof Closure) { [$command, $callback] = [$this->firstClosureParameterType($command), $command]; } if (is_numeric($callback)) { return $this->assertDispatchedTimes($command, $callback); } PHPUnit::assertTrue( $this->dispatched($command, $callback)->count() > 0 || $this->dispatchedAfterResponse($command, $callback)->count() > 0, "The expected [{$command}] job was not dispatched." ); } /** * Assert if a job was pushed a number of times. * * @param string $command * @param int $times * @return void */ public function assertDispatchedTimes($command, $times = 1) { $count = $this->dispatched($command)->count() + $this->dispatchedAfterResponse($command)->count(); PHPUnit::assertSame( $times, $count, "The expected [{$command}] job was pushed {$count} times instead of {$times} times." ); } /** * Determine if a job was dispatched based on a truth-test callback. * * @param string|\Closure $command * @param callable|null $callback * @return void */ public function assertNotDispatched($command, $callback = null) { if ($command instanceof Closure) { [$command, $callback] = [$this->firstClosureParameterType($command), $command]; } PHPUnit::assertTrue( $this->dispatched($command, $callback)->count() === 0 && $this->dispatchedAfterResponse($command, $callback)->count() === 0, "The unexpected [{$command}] job was dispatched." ); } /** * Assert if a job was dispatched after the response was sent based on a truth-test callback. * * @param string|\Closure $command * @param callable|int|null $callback * @return void */ public function assertDispatchedAfterResponse($command, $callback = null) { if ($command instanceof Closure) { [$command, $callback] = [$this->firstClosureParameterType($command), $command]; } if (is_numeric($callback)) { return $this->assertDispatchedAfterResponseTimes($command, $callback); } PHPUnit::assertTrue( $this->dispatchedAfterResponse($command, $callback)->count() > 0, "The expected [{$command}] job was not dispatched for after sending the response." ); } /** * Assert if a job was pushed after the response was sent a number of times. * * @param string $command * @param int $times * @return void */ public function assertDispatchedAfterResponseTimes($command, $times = 1) { $count = $this->dispatchedAfterResponse($command)->count(); PHPUnit::assertSame( $times, $count, "The expected [{$command}] job was pushed {$count} times instead of {$times} times." ); } /** * Determine if a job was dispatched based on a truth-test callback. * * @param string|\Closure $command * @param callable|null $callback * @return void */ public function assertNotDispatchedAfterResponse($command, $callback = null) { if ($command instanceof Closure) { [$command, $callback] = [$this->firstClosureParameterType($command), $command]; } PHPUnit::assertCount( 0, $this->dispatchedAfterResponse($command, $callback), "The unexpected [{$command}] job was dispatched for after sending the response." ); } /** * Get all of the jobs matching a truth-test callback. * * @param string $command * @param callable|null $callback * @return \Illuminate\Support\Collection */ public function dispatched($command, $callback = null) { if (! $this->hasDispatched($command)) { return collect(); } $callback = $callback ?: function () { return true; }; return collect($this->commands[$command])->filter(function ($command) use ($callback) { return $callback($command); }); } /** * Get all of the jobs dispatched after the response was sent matching a truth-test callback. * * @param string $command * @param callable|null $callback * @return \Illuminate\Support\Collection */ public function dispatchedAfterResponse(string $command, $callback = null) { if (! $this->hasDispatchedAfterResponse($command)) { return collect(); } $callback = $callback ?: function () { return true; }; return collect($this->commandsAfterResponse[$command])->filter(function ($command) use ($callback) { return $callback($command); }); } /** * Determine if there are any stored commands for a given class. * * @param string $command * @return bool */ public function hasDispatched($command) { return isset($this->commands[$command]) && ! empty($this->commands[$command]); } /** * Determine if there are any stored commands for a given class. * * @param string $command * @return bool */ public function hasDispatchedAfterResponse($command) { return isset($this->commandsAfterResponse[$command]) && ! empty($this->commandsAfterResponse[$command]); } /** * Dispatch a command to its appropriate handler. * * @param mixed $command * @return mixed */ public function dispatch($command) { if ($this->shouldFakeJob($command)) { $this->commands[get_class($command)][] = $command; } else { return $this->dispatcher->dispatch($command); } } /** * Dispatch a command to its appropriate handler in the current process. * * @param mixed $command * @param mixed $handler * @return mixed */ public function dispatchNow($command, $handler = null) { if ($this->shouldFakeJob($command)) { $this->commands[get_class($command)][] = $command; } else { return $this->dispatcher->dispatchNow($command, $handler); } } /** * Dispatch a command to its appropriate handler behind a queue. * * @param mixed $command * @return mixed */ public function dispatchToQueue($command) { if ($this->shouldFakeJob($command)) { $this->commands[get_class($command)][] = $command; } else { return $this->dispatcher->dispatchToQueue($command); } } /** * Dispatch a command to its appropriate handler. * * @param mixed $command * @return mixed */ public function dispatchAfterResponse($command) { if ($this->shouldFakeJob($command)) { $this->commandsAfterResponse[get_class($command)][] = $command; } else { return $this->dispatcher->dispatch($command); } } /** * Determine if an command should be faked or actually dispatched. * * @param mixed $command * @return bool */ protected function shouldFakeJob($command) { if (empty($this->jobsToFake)) { return true; } return collect($this->jobsToFake) ->filter(function ($job) use ($command) { return $job instanceof Closure ? $job($command) : $job === get_class($command); })->isNotEmpty(); } /** * Set the pipes commands should be piped through before dispatching. * * @param array $pipes * @return $this */ public function pipeThrough(array $pipes) { $this->dispatcher->pipeThrough($pipes); return $this; } /** * Determine if the given command has a handler. * * @param mixed $command * @return bool */ public function hasCommandHandler($command) { return $this->dispatcher->hasCommandHandler($command); } /** * Retrieve the handler for a command. * * @param mixed $command * @return mixed */ public function getCommandHandler($command) { return $this->dispatcher->getCommandHandler($command); } /** * Map a command to a handler. * * @param array $map * @return $this */ public function map(array $map) { $this->dispatcher->map($map); return $this; } } support/Testing/Fakes/EventFake.php 0000644 00000015005 14736103231 0013310 0 ustar 00 <?php namespace Illuminate\Support\Testing\Fakes; use Closure; use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Support\Arr; use Illuminate\Support\Traits\ReflectsClosures; use PHPUnit\Framework\Assert as PHPUnit; class EventFake implements Dispatcher { use ReflectsClosures; /** * The original event dispatcher. * * @var \Illuminate\Contracts\Events\Dispatcher */ protected $dispatcher; /** * The event types that should be intercepted instead of dispatched. * * @var array */ protected $eventsToFake; /** * All of the events that have been intercepted keyed by type. * * @var array */ protected $events = []; /** * Create a new event fake instance. * * @param \Illuminate\Contracts\Events\Dispatcher $dispatcher * @param array|string $eventsToFake * @return void */ public function __construct(Dispatcher $dispatcher, $eventsToFake = []) { $this->dispatcher = $dispatcher; $this->eventsToFake = Arr::wrap($eventsToFake); } /** * Assert if an event was dispatched based on a truth-test callback. * * @param string|\Closure $event * @param callable|int|null $callback * @return void */ public function assertDispatched($event, $callback = null) { if ($event instanceof Closure) { [$event, $callback] = [$this->firstClosureParameterType($event), $event]; } if (is_int($callback)) { return $this->assertDispatchedTimes($event, $callback); } PHPUnit::assertTrue( $this->dispatched($event, $callback)->count() > 0, "The expected [{$event}] event was not dispatched." ); } /** * Assert if a event was dispatched a number of times. * * @param string $event * @param int $times * @return void */ public function assertDispatchedTimes($event, $times = 1) { $count = $this->dispatched($event)->count(); PHPUnit::assertSame( $times, $count, "The expected [{$event}] event was dispatched {$count} times instead of {$times} times." ); } /** * Determine if an event was dispatched based on a truth-test callback. * * @param string|\Closure $event * @param callable|null $callback * @return void */ public function assertNotDispatched($event, $callback = null) { if ($event instanceof Closure) { [$event, $callback] = [$this->firstClosureParameterType($event), $event]; } PHPUnit::assertCount( 0, $this->dispatched($event, $callback), "The unexpected [{$event}] event was dispatched." ); } /** * Get all of the events matching a truth-test callback. * * @param string $event * @param callable|null $callback * @return \Illuminate\Support\Collection */ public function dispatched($event, $callback = null) { if (! $this->hasDispatched($event)) { return collect(); } $callback = $callback ?: function () { return true; }; return collect($this->events[$event])->filter(function ($arguments) use ($callback) { return $callback(...$arguments); }); } /** * Determine if the given event has been dispatched. * * @param string $event * @return bool */ public function hasDispatched($event) { return isset($this->events[$event]) && ! empty($this->events[$event]); } /** * Register an event listener with the dispatcher. * * @param string|array $events * @param mixed $listener * @return void */ public function listen($events, $listener) { $this->dispatcher->listen($events, $listener); } /** * Determine if a given event has listeners. * * @param string $eventName * @return bool */ public function hasListeners($eventName) { return $this->dispatcher->hasListeners($eventName); } /** * Register an event and payload to be dispatched later. * * @param string $event * @param array $payload * @return void */ public function push($event, $payload = []) { // } /** * Register an event subscriber with the dispatcher. * * @param object|string $subscriber * @return void */ public function subscribe($subscriber) { $this->dispatcher->subscribe($subscriber); } /** * Flush a set of pushed events. * * @param string $event * @return void */ public function flush($event) { // } /** * Fire an event and call the listeners. * * @param string|object $event * @param mixed $payload * @param bool $halt * @return array|null */ public function dispatch($event, $payload = [], $halt = false) { $name = is_object($event) ? get_class($event) : (string) $event; if ($this->shouldFakeEvent($name, $payload)) { $this->events[$name][] = func_get_args(); } else { return $this->dispatcher->dispatch($event, $payload, $halt); } } /** * Determine if an event should be faked or actually dispatched. * * @param string $eventName * @param mixed $payload * @return bool */ protected function shouldFakeEvent($eventName, $payload) { if (empty($this->eventsToFake)) { return true; } return collect($this->eventsToFake) ->filter(function ($event) use ($eventName, $payload) { return $event instanceof Closure ? $event($eventName, $payload) : $event === $eventName; }) ->isNotEmpty(); } /** * Remove a set of listeners from the dispatcher. * * @param string $event * @return void */ public function forget($event) { // } /** * Forget all of the queued listeners. * * @return void */ public function forgetPushed() { // } /** * Dispatch an event and call the listeners. * * @param string|object $event * @param mixed $payload * @return void */ public function until($event, $payload = []) { return $this->dispatch($event, $payload, true); } } support/Testing/Fakes/QueueFake.php 0000644 00000024731 14736103231 0013321 0 ustar 00 <?php namespace Illuminate\Support\Testing\Fakes; use BadMethodCallException; use Closure; use Illuminate\Contracts\Queue\Queue; use Illuminate\Queue\QueueManager; use Illuminate\Support\Traits\ReflectsClosures; use PHPUnit\Framework\Assert as PHPUnit; class QueueFake extends QueueManager implements Queue { use ReflectsClosures; /** * All of the jobs that have been pushed. * * @var array */ protected $jobs = []; /** * Assert if a job was pushed based on a truth-test callback. * * @param string|\Closure $job * @param callable|int|null $callback * @return void */ public function assertPushed($job, $callback = null) { if ($job instanceof Closure) { [$job, $callback] = [$this->firstClosureParameterType($job), $job]; } if (is_numeric($callback)) { return $this->assertPushedTimes($job, $callback); } PHPUnit::assertTrue( $this->pushed($job, $callback)->count() > 0, "The expected [{$job}] job was not pushed." ); } /** * Assert if a job was pushed a number of times. * * @param string $job * @param int $times * @return void */ protected function assertPushedTimes($job, $times = 1) { $count = $this->pushed($job)->count(); PHPUnit::assertSame( $times, $count, "The expected [{$job}] job was pushed {$count} times instead of {$times} times." ); } /** * Assert if a job was pushed based on a truth-test callback. * * @param string $queue * @param string|\Closure $job * @param callable|null $callback * @return void */ public function assertPushedOn($queue, $job, $callback = null) { if ($job instanceof Closure) { [$job, $callback] = [$this->firstClosureParameterType($job), $job]; } return $this->assertPushed($job, function ($job, $pushedQueue) use ($callback, $queue) { if ($pushedQueue !== $queue) { return false; } return $callback ? $callback(...func_get_args()) : true; }); } /** * Assert if a job was pushed with chained jobs based on a truth-test callback. * * @param string $job * @param array $expectedChain * @param callable|null $callback * @return void */ public function assertPushedWithChain($job, $expectedChain = [], $callback = null) { PHPUnit::assertTrue( $this->pushed($job, $callback)->isNotEmpty(), "The expected [{$job}] job was not pushed." ); PHPUnit::assertTrue( collect($expectedChain)->isNotEmpty(), 'The expected chain can not be empty.' ); $this->isChainOfObjects($expectedChain) ? $this->assertPushedWithChainOfObjects($job, $expectedChain, $callback) : $this->assertPushedWithChainOfClasses($job, $expectedChain, $callback); } /** * Assert if a job was pushed with an empty chain based on a truth-test callback. * * @param string $job * @param callable|null $callback * @return void */ public function assertPushedWithoutChain($job, $callback = null) { PHPUnit::assertTrue( $this->pushed($job, $callback)->isNotEmpty(), "The expected [{$job}] job was not pushed." ); $this->assertPushedWithChainOfClasses($job, [], $callback); } /** * Assert if a job was pushed with chained jobs based on a truth-test callback. * * @param string $job * @param array $expectedChain * @param callable|null $callback * @return void */ protected function assertPushedWithChainOfObjects($job, $expectedChain, $callback) { $chain = collect($expectedChain)->map(function ($job) { return serialize($job); })->all(); PHPUnit::assertTrue( $this->pushed($job, $callback)->filter(function ($job) use ($chain) { return $job->chained == $chain; })->isNotEmpty(), 'The expected chain was not pushed.' ); } /** * Assert if a job was pushed with chained jobs based on a truth-test callback. * * @param string $job * @param array $expectedChain * @param callable|null $callback * @return void */ protected function assertPushedWithChainOfClasses($job, $expectedChain, $callback) { $matching = $this->pushed($job, $callback)->map->chained->map(function ($chain) { return collect($chain)->map(function ($job) { return get_class(unserialize($job)); }); })->filter(function ($chain) use ($expectedChain) { return $chain->all() === $expectedChain; }); PHPUnit::assertTrue( $matching->isNotEmpty(), 'The expected chain was not pushed.' ); } /** * Determine if the given chain is entirely composed of objects. * * @param array $chain * @return bool */ protected function isChainOfObjects($chain) { return ! collect($chain)->contains(function ($job) { return ! is_object($job); }); } /** * Determine if a job was pushed based on a truth-test callback. * * @param string|\Closure $job * @param callable|null $callback * @return void */ public function assertNotPushed($job, $callback = null) { if ($job instanceof Closure) { [$job, $callback] = [$this->firstClosureParameterType($job), $job]; } PHPUnit::assertCount( 0, $this->pushed($job, $callback), "The unexpected [{$job}] job was pushed." ); } /** * Assert that no jobs were pushed. * * @return void */ public function assertNothingPushed() { PHPUnit::assertEmpty($this->jobs, 'Jobs were pushed unexpectedly.'); } /** * Get all of the jobs matching a truth-test callback. * * @param string $job * @param callable|null $callback * @return \Illuminate\Support\Collection */ public function pushed($job, $callback = null) { if (! $this->hasPushed($job)) { return collect(); } $callback = $callback ?: function () { return true; }; return collect($this->jobs[$job])->filter(function ($data) use ($callback) { return $callback($data['job'], $data['queue']); })->pluck('job'); } /** * Determine if there are any stored jobs for a given class. * * @param string $job * @return bool */ public function hasPushed($job) { return isset($this->jobs[$job]) && ! empty($this->jobs[$job]); } /** * Resolve a queue connection instance. * * @param mixed $value * @return \Illuminate\Contracts\Queue\Queue */ public function connection($value = null) { return $this; } /** * Get the size of the queue. * * @param string|null $queue * @return int */ public function size($queue = null) { return collect($this->jobs)->flatten(1)->filter(function ($job) use ($queue) { return $job['queue'] === $queue; })->count(); } /** * Push a new job onto the queue. * * @param string $job * @param mixed $data * @param string|null $queue * @return mixed */ public function push($job, $data = '', $queue = null) { $this->jobs[is_object($job) ? get_class($job) : $job][] = [ 'job' => $job, 'queue' => $queue, ]; } /** * Push a raw payload onto the queue. * * @param string $payload * @param string|null $queue * @param array $options * @return mixed */ public function pushRaw($payload, $queue = null, array $options = []) { // } /** * Push a new job onto the queue after a delay. * * @param \DateTimeInterface|\DateInterval|int $delay * @param string $job * @param mixed $data * @param string|null $queue * @return mixed */ public function later($delay, $job, $data = '', $queue = null) { return $this->push($job, $data, $queue); } /** * Push a new job onto the queue. * * @param string $queue * @param string $job * @param mixed $data * @return mixed */ public function pushOn($queue, $job, $data = '') { return $this->push($job, $data, $queue); } /** * Push a new job onto the queue after a delay. * * @param string $queue * @param \DateTimeInterface|\DateInterval|int $delay * @param string $job * @param mixed $data * @return mixed */ public function laterOn($queue, $delay, $job, $data = '') { return $this->push($job, $data, $queue); } /** * Pop the next job off of the queue. * * @param string|null $queue * @return \Illuminate\Contracts\Queue\Job|null */ public function pop($queue = null) { // } /** * Push an array of jobs onto the queue. * * @param array $jobs * @param mixed $data * @param string|null $queue * @return mixed */ public function bulk($jobs, $data = '', $queue = null) { foreach ($jobs as $job) { $this->push($job, $data, $queue); } } /** * Get the jobs that have been pushed. * * @return array */ public function pushedJobs() { return $this->jobs; } /** * Get the connection name for the queue. * * @return string */ public function getConnectionName() { // } /** * Set the connection name for the queue. * * @param string $name * @return $this */ public function setConnectionName($name) { return $this; } /** * Override the QueueManager to prevent circular dependency. * * @param string $method * @param array $parameters * @return mixed * * @throws \BadMethodCallException */ public function __call($method, $parameters) { throw new BadMethodCallException(sprintf( 'Call to undefined method %s::%s()', static::class, $method )); } } support/Testing/Fakes/PendingMailFake.php 0000644 00000002320 14736103231 0014412 0 ustar 00 <?php namespace Illuminate\Support\Testing\Fakes; use Illuminate\Contracts\Mail\Mailable; use Illuminate\Mail\PendingMail; class PendingMailFake extends PendingMail { /** * Create a new instance. * * @param \Illuminate\Support\Testing\Fakes\MailFake $mailer * @return void */ public function __construct($mailer) { $this->mailer = $mailer; } /** * Send a new mailable message instance. * * @param \Illuminate\Contracts\Mail\Mailable $mailable; * @return mixed */ public function send(Mailable $mailable) { return $this->mailer->send($this->fill($mailable)); } /** * Send a mailable message immediately. * * @param \Illuminate\Contracts\Mail\Mailable $mailable; * @return mixed * @deprecated Use send() instead. */ public function sendNow(Mailable $mailable) { return $this->send($mailable); } /** * Push the given mailable onto the queue. * * @param \Illuminate\Contracts\Mail\Mailable $mailable; * @return mixed */ public function queue(Mailable $mailable) { return $this->mailer->queue($this->fill($mailable)); } } support/helpers.php 0000644 00000032336 14736103231 0010442 0 ustar 00 <?php use Illuminate\Contracts\Support\DeferringDisplayableValue; use Illuminate\Contracts\Support\Htmlable; use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\Env; use Illuminate\Support\HigherOrderTapProxy; use Illuminate\Support\Optional; if (! function_exists('append_config')) { /** * Assign high numeric IDs to a config item to force appending. * * @param array $array * @return array */ function append_config(array $array) { $start = 9999; foreach ($array as $key => $value) { if (is_numeric($key)) { $start++; $array[$start] = Arr::pull($array, $key); } } return $array; } } if (! function_exists('blank')) { /** * Determine if the given value is "blank". * * @param mixed $value * @return bool */ function blank($value) { if (is_null($value)) { return true; } if (is_string($value)) { return trim($value) === ''; } if (is_numeric($value) || is_bool($value)) { return false; } if ($value instanceof Countable) { return count($value) === 0; } return empty($value); } } if (! function_exists('class_basename')) { /** * Get the class "basename" of the given object / class. * * @param string|object $class * @return string */ function class_basename($class) { $class = is_object($class) ? get_class($class) : $class; return basename(str_replace('\\', '/', $class)); } } if (! function_exists('class_uses_recursive')) { /** * Returns all traits used by a class, its parent classes and trait of their traits. * * @param object|string $class * @return array */ function class_uses_recursive($class) { if (is_object($class)) { $class = get_class($class); } $results = []; foreach (array_reverse(class_parents($class)) + [$class => $class] as $class) { $results += trait_uses_recursive($class); } return array_unique($results); } } if (! function_exists('collect')) { /** * Create a collection from the given value. * * @param mixed $value * @return \Illuminate\Support\Collection */ function collect($value = null) { return new Collection($value); } } if (! function_exists('data_fill')) { /** * Fill in data where it's missing. * * @param mixed $target * @param string|array $key * @param mixed $value * @return mixed */ function data_fill(&$target, $key, $value) { return data_set($target, $key, $value, false); } } if (! function_exists('data_get')) { /** * Get an item from an array or object using "dot" notation. * * @param mixed $target * @param string|array|int|null $key * @param mixed $default * @return mixed */ function data_get($target, $key, $default = null) { if (is_null($key)) { return $target; } $key = is_array($key) ? $key : explode('.', $key); foreach ($key as $i => $segment) { unset($key[$i]); if (is_null($segment)) { return $target; } if ($segment === '*') { if ($target instanceof Collection) { $target = $target->all(); } elseif (! is_array($target)) { return value($default); } $result = []; foreach ($target as $item) { $result[] = data_get($item, $key); } return in_array('*', $key) ? Arr::collapse($result) : $result; } if (Arr::accessible($target) && Arr::exists($target, $segment)) { $target = $target[$segment]; } elseif (is_object($target) && isset($target->{$segment})) { $target = $target->{$segment}; } else { return value($default); } } return $target; } } if (! function_exists('data_set')) { /** * Set an item on an array or object using dot notation. * * @param mixed $target * @param string|array $key * @param mixed $value * @param bool $overwrite * @return mixed */ function data_set(&$target, $key, $value, $overwrite = true) { $segments = is_array($key) ? $key : explode('.', $key); if (($segment = array_shift($segments)) === '*') { if (! Arr::accessible($target)) { $target = []; } if ($segments) { foreach ($target as &$inner) { data_set($inner, $segments, $value, $overwrite); } } elseif ($overwrite) { foreach ($target as &$inner) { $inner = $value; } } } elseif (Arr::accessible($target)) { if ($segments) { if (! Arr::exists($target, $segment)) { $target[$segment] = []; } data_set($target[$segment], $segments, $value, $overwrite); } elseif ($overwrite || ! Arr::exists($target, $segment)) { $target[$segment] = $value; } } elseif (is_object($target)) { if ($segments) { if (! isset($target->{$segment})) { $target->{$segment} = []; } data_set($target->{$segment}, $segments, $value, $overwrite); } elseif ($overwrite || ! isset($target->{$segment})) { $target->{$segment} = $value; } } else { $target = []; if ($segments) { data_set($target[$segment], $segments, $value, $overwrite); } elseif ($overwrite) { $target[$segment] = $value; } } return $target; } } if (! function_exists('e')) { /** * Encode HTML special characters in a string. * * @param \Illuminate\Contracts\Support\DeferringDisplayableValue|\Illuminate\Contracts\Support\Htmlable|string $value * @param bool $doubleEncode * @return string */ function e($value, $doubleEncode = true) { if ($value instanceof DeferringDisplayableValue) { $value = $value->resolveDisplayableValue(); } if ($value instanceof Htmlable) { return $value->toHtml(); } return htmlspecialchars($value, ENT_QUOTES, 'UTF-8', $doubleEncode); } } if (! function_exists('env')) { /** * Gets the value of an environment variable. * * @param string $key * @param mixed $default * @return mixed */ function env($key, $default = null) { return Env::get($key, $default); } } if (! function_exists('filled')) { /** * Determine if a value is "filled". * * @param mixed $value * @return bool */ function filled($value) { return ! blank($value); } } if (! function_exists('head')) { /** * Get the first element of an array. Useful for method chaining. * * @param array $array * @return mixed */ function head($array) { return reset($array); } } if (! function_exists('last')) { /** * Get the last element from an array. * * @param array $array * @return mixed */ function last($array) { return end($array); } } if (! function_exists('object_get')) { /** * Get an item from an object using "dot" notation. * * @param object $object * @param string|null $key * @param mixed $default * @return mixed */ function object_get($object, $key, $default = null) { if (is_null($key) || trim($key) == '') { return $object; } foreach (explode('.', $key) as $segment) { if (! is_object($object) || ! isset($object->{$segment})) { return value($default); } $object = $object->{$segment}; } return $object; } } if (! function_exists('optional')) { /** * Provide access to optional objects. * * @param mixed $value * @param callable|null $callback * @return mixed */ function optional($value = null, callable $callback = null) { if (is_null($callback)) { return new Optional($value); } elseif (! is_null($value)) { return $callback($value); } } } if (! function_exists('preg_replace_array')) { /** * Replace a given pattern with each value in the array in sequentially. * * @param string $pattern * @param array $replacements * @param string $subject * @return string */ function preg_replace_array($pattern, array $replacements, $subject) { return preg_replace_callback($pattern, function () use (&$replacements) { foreach ($replacements as $key => $value) { return array_shift($replacements); } }, $subject); } } if (! function_exists('retry')) { /** * Retry an operation a given number of times. * * @param int $times * @param callable $callback * @param int $sleep * @param callable|null $when * @return mixed * * @throws \Exception */ function retry($times, callable $callback, $sleep = 0, $when = null) { $attempts = 0; beginning: $attempts++; $times--; try { return $callback($attempts); } catch (Exception $e) { if ($times < 1 || ($when && ! $when($e))) { throw $e; } if ($sleep) { usleep($sleep * 1000); } goto beginning; } } } if (! function_exists('tap')) { /** * Call the given Closure with the given value then return the value. * * @param mixed $value * @param callable|null $callback * @return mixed */ function tap($value, $callback = null) { if (is_null($callback)) { return new HigherOrderTapProxy($value); } $callback($value); return $value; } } if (! function_exists('throw_if')) { /** * Throw the given exception if the given condition is true. * * @param mixed $condition * @param \Throwable|string $exception * @param array ...$parameters * @return mixed * * @throws \Throwable */ function throw_if($condition, $exception, ...$parameters) { if ($condition) { throw (is_string($exception) ? new $exception(...$parameters) : $exception); } return $condition; } } if (! function_exists('throw_unless')) { /** * Throw the given exception unless the given condition is true. * * @param mixed $condition * @param \Throwable|string $exception * @param array ...$parameters * @return mixed * * @throws \Throwable */ function throw_unless($condition, $exception, ...$parameters) { if (! $condition) { throw (is_string($exception) ? new $exception(...$parameters) : $exception); } return $condition; } } if (! function_exists('trait_uses_recursive')) { /** * Returns all traits used by a trait and its traits. * * @param string $trait * @return array */ function trait_uses_recursive($trait) { $traits = class_uses($trait); foreach ($traits as $trait) { $traits += trait_uses_recursive($trait); } return $traits; } } if (! function_exists('transform')) { /** * Transform the given value if it is present. * * @param mixed $value * @param callable $callback * @param mixed $default * @return mixed|null */ function transform($value, callable $callback, $default = null) { if (filled($value)) { return $callback($value); } if (is_callable($default)) { return $default($value); } return $default; } } if (! function_exists('value')) { /** * Return the default value of the given value. * * @param mixed $value * @return mixed */ function value($value) { return $value instanceof Closure ? $value() : $value; } } if (! function_exists('windows_os')) { /** * Determine whether the current environment is Windows based. * * @return bool */ function windows_os() { return PHP_OS_FAMILY === 'Windows'; } } if (! function_exists('with')) { /** * Return the given value, optionally passed through the given callback. * * @param mixed $value * @param callable|null $callback * @return mixed */ function with($value, callable $callback = null) { return is_null($callback) ? $value : $callback($value); } } support/Enumerable.php 0000644 00000053072 14736103231 0011057 0 ustar 00 <?php namespace Illuminate\Support; use Countable; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Contracts\Support\Jsonable; use IteratorAggregate; use JsonSerializable; interface Enumerable extends Arrayable, Countable, IteratorAggregate, Jsonable, JsonSerializable { /** * Create a new collection instance if the value isn't one already. * * @param mixed $items * @return static */ public static function make($items = []); /** * Create a new instance by invoking the callback a given amount of times. * * @param int $number * @param callable|null $callback * @return static */ public static function times($number, callable $callback = null); /** * Wrap the given value in a collection if applicable. * * @param mixed $value * @return static */ public static function wrap($value); /** * Get the underlying items from the given collection if applicable. * * @param array|static $value * @return array */ public static function unwrap($value); /** * Get all items in the enumerable. * * @return array */ public function all(); /** * Alias for the "avg" method. * * @param callable|string|null $callback * @return mixed */ public function average($callback = null); /** * Get the median of a given key. * * @param string|array|null $key * @return mixed */ public function median($key = null); /** * Get the mode of a given key. * * @param string|array|null $key * @return array|null */ public function mode($key = null); /** * Collapse the items into a single enumerable. * * @return static */ public function collapse(); /** * Alias for the "contains" method. * * @param mixed $key * @param mixed $operator * @param mixed $value * @return bool */ public function some($key, $operator = null, $value = null); /** * Determine if an item exists, using strict comparison. * * @param mixed $key * @param mixed $value * @return bool */ public function containsStrict($key, $value = null); /** * Get the average value of a given key. * * @param callable|string|null $callback * @return mixed */ public function avg($callback = null); /** * Determine if an item exists in the enumerable. * * @param mixed $key * @param mixed $operator * @param mixed $value * @return bool */ public function contains($key, $operator = null, $value = null); /** * Dump the collection and end the script. * * @param mixed ...$args * @return void */ public function dd(...$args); /** * Dump the collection. * * @return $this */ public function dump(); /** * Get the items that are not present in the given items. * * @param mixed $items * @return static */ public function diff($items); /** * Get the items that are not present in the given items, using the callback. * * @param mixed $items * @param callable $callback * @return static */ public function diffUsing($items, callable $callback); /** * Get the items whose keys and values are not present in the given items. * * @param mixed $items * @return static */ public function diffAssoc($items); /** * Get the items whose keys and values are not present in the given items, using the callback. * * @param mixed $items * @param callable $callback * @return static */ public function diffAssocUsing($items, callable $callback); /** * Get the items whose keys are not present in the given items. * * @param mixed $items * @return static */ public function diffKeys($items); /** * Get the items whose keys are not present in the given items, using the callback. * * @param mixed $items * @param callable $callback * @return static */ public function diffKeysUsing($items, callable $callback); /** * Retrieve duplicate items. * * @param callable|null $callback * @param bool $strict * @return static */ public function duplicates($callback = null, $strict = false); /** * Retrieve duplicate items using strict comparison. * * @param callable|null $callback * @return static */ public function duplicatesStrict($callback = null); /** * Execute a callback over each item. * * @param callable $callback * @return $this */ public function each(callable $callback); /** * Execute a callback over each nested chunk of items. * * @param callable $callback * @return static */ public function eachSpread(callable $callback); /** * Determine if all items pass the given truth test. * * @param string|callable $key * @param mixed $operator * @param mixed $value * @return bool */ public function every($key, $operator = null, $value = null); /** * Get all items except for those with the specified keys. * * @param mixed $keys * @return static */ public function except($keys); /** * Run a filter over each of the items. * * @param callable|null $callback * @return static */ public function filter(callable $callback = null); /** * Apply the callback if the value is truthy. * * @param bool $value * @param callable $callback * @param callable|null $default * @return static|mixed */ public function when($value, callable $callback, callable $default = null); /** * Apply the callback if the collection is empty. * * @param callable $callback * @param callable|null $default * @return static|mixed */ public function whenEmpty(callable $callback, callable $default = null); /** * Apply the callback if the collection is not empty. * * @param callable $callback * @param callable|null $default * @return static|mixed */ public function whenNotEmpty(callable $callback, callable $default = null); /** * Apply the callback if the value is falsy. * * @param bool $value * @param callable $callback * @param callable|null $default * @return static|mixed */ public function unless($value, callable $callback, callable $default = null); /** * Apply the callback unless the collection is empty. * * @param callable $callback * @param callable|null $default * @return static|mixed */ public function unlessEmpty(callable $callback, callable $default = null); /** * Apply the callback unless the collection is not empty. * * @param callable $callback * @param callable|null $default * @return static|mixed */ public function unlessNotEmpty(callable $callback, callable $default = null); /** * Filter items by the given key value pair. * * @param string $key * @param mixed $operator * @param mixed $value * @return static */ public function where($key, $operator = null, $value = null); /** * Filter items by the given key value pair using strict comparison. * * @param string $key * @param mixed $value * @return static */ public function whereStrict($key, $value); /** * Filter items by the given key value pair. * * @param string $key * @param mixed $values * @param bool $strict * @return static */ public function whereIn($key, $values, $strict = false); /** * Filter items by the given key value pair using strict comparison. * * @param string $key * @param mixed $values * @return static */ public function whereInStrict($key, $values); /** * Filter items such that the value of the given key is between the given values. * * @param string $key * @param array $values * @return static */ public function whereBetween($key, $values); /** * Filter items such that the value of the given key is not between the given values. * * @param string $key * @param array $values * @return static */ public function whereNotBetween($key, $values); /** * Filter items by the given key value pair. * * @param string $key * @param mixed $values * @param bool $strict * @return static */ public function whereNotIn($key, $values, $strict = false); /** * Filter items by the given key value pair using strict comparison. * * @param string $key * @param mixed $values * @return static */ public function whereNotInStrict($key, $values); /** * Filter the items, removing any items that don't match the given type. * * @param string $type * @return static */ public function whereInstanceOf($type); /** * Get the first item from the enumerable passing the given truth test. * * @param callable|null $callback * @param mixed $default * @return mixed */ public function first(callable $callback = null, $default = null); /** * Get the first item by the given key value pair. * * @param string $key * @param mixed $operator * @param mixed $value * @return mixed */ public function firstWhere($key, $operator = null, $value = null); /** * Flip the values with their keys. * * @return static */ public function flip(); /** * Get an item from the collection by key. * * @param mixed $key * @param mixed $default * @return mixed */ public function get($key, $default = null); /** * Group an associative array by a field or using a callback. * * @param array|callable|string $groupBy * @param bool $preserveKeys * @return static */ public function groupBy($groupBy, $preserveKeys = false); /** * Key an associative array by a field or using a callback. * * @param callable|string $keyBy * @return static */ public function keyBy($keyBy); /** * Determine if an item exists in the collection by key. * * @param mixed $key * @return bool */ public function has($key); /** * Concatenate values of a given key as a string. * * @param string $value * @param string|null $glue * @return string */ public function implode($value, $glue = null); /** * Intersect the collection with the given items. * * @param mixed $items * @return static */ public function intersect($items); /** * Intersect the collection with the given items by key. * * @param mixed $items * @return static */ public function intersectByKeys($items); /** * Determine if the collection is empty or not. * * @return bool */ public function isEmpty(); /** * Determine if the collection is not empty. * * @return bool */ public function isNotEmpty(); /** * Join all items from the collection using a string. The final items can use a separate glue string. * * @param string $glue * @param string $finalGlue * @return string */ public function join($glue, $finalGlue = ''); /** * Get the keys of the collection items. * * @return static */ public function keys(); /** * Get the last item from the collection. * * @param callable|null $callback * @param mixed $default * @return mixed */ public function last(callable $callback = null, $default = null); /** * Run a map over each of the items. * * @param callable $callback * @return static */ public function map(callable $callback); /** * Run a map over each nested chunk of items. * * @param callable $callback * @return static */ public function mapSpread(callable $callback); /** * Run a dictionary map over the items. * * The callback should return an associative array with a single key/value pair. * * @param callable $callback * @return static */ public function mapToDictionary(callable $callback); /** * Run a grouping map over the items. * * The callback should return an associative array with a single key/value pair. * * @param callable $callback * @return static */ public function mapToGroups(callable $callback); /** * Run an associative map over each of the items. * * The callback should return an associative array with a single key/value pair. * * @param callable $callback * @return static */ public function mapWithKeys(callable $callback); /** * Map a collection and flatten the result by a single level. * * @param callable $callback * @return static */ public function flatMap(callable $callback); /** * Map the values into a new class. * * @param string $class * @return static */ public function mapInto($class); /** * Merge the collection with the given items. * * @param mixed $items * @return static */ public function merge($items); /** * Recursively merge the collection with the given items. * * @param mixed $items * @return static */ public function mergeRecursive($items); /** * Create a collection by using this collection for keys and another for its values. * * @param mixed $values * @return static */ public function combine($values); /** * Union the collection with the given items. * * @param mixed $items * @return static */ public function union($items); /** * Get the min value of a given key. * * @param callable|string|null $callback * @return mixed */ public function min($callback = null); /** * Get the max value of a given key. * * @param callable|string|null $callback * @return mixed */ public function max($callback = null); /** * Create a new collection consisting of every n-th element. * * @param int $step * @param int $offset * @return static */ public function nth($step, $offset = 0); /** * Get the items with the specified keys. * * @param mixed $keys * @return static */ public function only($keys); /** * "Paginate" the collection by slicing it into a smaller collection. * * @param int $page * @param int $perPage * @return static */ public function forPage($page, $perPage); /** * Partition the collection into two arrays using the given callback or key. * * @param callable|string $key * @param mixed $operator * @param mixed $value * @return static */ public function partition($key, $operator = null, $value = null); /** * Push all of the given items onto the collection. * * @param iterable $source * @return static */ public function concat($source); /** * Get one or a specified number of items randomly from the collection. * * @param int|null $number * @return static|mixed * * @throws \InvalidArgumentException */ public function random($number = null); /** * Reduce the collection to a single value. * * @param callable $callback * @param mixed $initial * @return mixed */ public function reduce(callable $callback, $initial = null); /** * Replace the collection items with the given items. * * @param mixed $items * @return static */ public function replace($items); /** * Recursively replace the collection items with the given items. * * @param mixed $items * @return static */ public function replaceRecursive($items); /** * Reverse items order. * * @return static */ public function reverse(); /** * Search the collection for a given value and return the corresponding key if successful. * * @param mixed $value * @param bool $strict * @return mixed */ public function search($value, $strict = false); /** * Shuffle the items in the collection. * * @param int|null $seed * @return static */ public function shuffle($seed = null); /** * Skip the first {$count} items. * * @param int $count * @return static */ public function skip($count); /** * Get a slice of items from the enumerable. * * @param int $offset * @param int|null $length * @return static */ public function slice($offset, $length = null); /** * Split a collection into a certain number of groups. * * @param int $numberOfGroups * @return static */ public function split($numberOfGroups); /** * Chunk the collection into chunks of the given size. * * @param int $size * @return static */ public function chunk($size); /** * Sort through each item with a callback. * * @param callable|null|int $callback * @return static */ public function sort($callback = null); /** * Sort items in descending order. * * @param int $options * @return static */ public function sortDesc($options = SORT_REGULAR); /** * Sort the collection using the given callback. * * @param callable|string $callback * @param int $options * @param bool $descending * @return static */ public function sortBy($callback, $options = SORT_REGULAR, $descending = false); /** * Sort the collection in descending order using the given callback. * * @param callable|string $callback * @param int $options * @return static */ public function sortByDesc($callback, $options = SORT_REGULAR); /** * Sort the collection keys. * * @param int $options * @param bool $descending * @return static */ public function sortKeys($options = SORT_REGULAR, $descending = false); /** * Sort the collection keys in descending order. * * @param int $options * @return static */ public function sortKeysDesc($options = SORT_REGULAR); /** * Get the sum of the given values. * * @param callable|string|null $callback * @return mixed */ public function sum($callback = null); /** * Take the first or last {$limit} items. * * @param int $limit * @return static */ public function take($limit); /** * Pass the collection to the given callback and then return it. * * @param callable $callback * @return $this */ public function tap(callable $callback); /** * Pass the enumerable to the given callback and return the result. * * @param callable $callback * @return mixed */ public function pipe(callable $callback); /** * Get the values of a given key. * * @param string|array $value * @param string|null $key * @return static */ public function pluck($value, $key = null); /** * Create a collection of all elements that do not pass a given truth test. * * @param callable|mixed $callback * @return static */ public function reject($callback = true); /** * Return only unique items from the collection array. * * @param string|callable|null $key * @param bool $strict * @return static */ public function unique($key = null, $strict = false); /** * Return only unique items from the collection array using strict comparison. * * @param string|callable|null $key * @return static */ public function uniqueStrict($key = null); /** * Reset the keys on the underlying array. * * @return static */ public function values(); /** * Pad collection to the specified length with a value. * * @param int $size * @param mixed $value * @return static */ public function pad($size, $value); /** * Count the number of items in the collection using a given truth test. * * @param callable|null $callback * @return static */ public function countBy($callback = null); /** * Collect the values into a collection. * * @return \Illuminate\Support\Collection */ public function collect(); /** * Convert the collection to its string representation. * * @return string */ public function __toString(); /** * Add a method to the list of proxied methods. * * @param string $method * @return void */ public static function proxy($method); /** * Dynamically access collection proxies. * * @param string $key * @return mixed * * @throws \Exception */ public function __get($key); } support/Pluralizer.php 0000644 00000006207 14736103231 0011127 0 ustar 00 <?php namespace Illuminate\Support; use Doctrine\Inflector\CachedWordInflector; use Doctrine\Inflector\Inflector; use Doctrine\Inflector\Rules\English; use Doctrine\Inflector\RulesetInflector; class Pluralizer { /** * Uncountable word forms. * * @var array */ public static $uncountable = [ 'audio', 'bison', 'cattle', 'chassis', 'compensation', 'coreopsis', 'data', 'deer', 'education', 'emoji', 'equipment', 'evidence', 'feedback', 'firmware', 'fish', 'furniture', 'gold', 'hardware', 'information', 'jedi', 'kin', 'knowledge', 'love', 'metadata', 'money', 'moose', 'news', 'nutrition', 'offspring', 'plankton', 'pokemon', 'police', 'rain', 'recommended', 'related', 'rice', 'series', 'sheep', 'software', 'species', 'swine', 'traffic', 'wheat', ]; /** * Get the plural form of an English word. * * @param string $value * @param int $count * @return string */ public static function plural($value, $count = 2) { if ((int) abs($count) === 1 || static::uncountable($value)) { return $value; } $plural = static::inflector()->pluralize($value); return static::matchCase($plural, $value); } /** * Get the singular form of an English word. * * @param string $value * @return string */ public static function singular($value) { $singular = static::inflector()->singularize($value); return static::matchCase($singular, $value); } /** * Determine if the given value is uncountable. * * @param string $value * @return bool */ protected static function uncountable($value) { return in_array(strtolower($value), static::$uncountable); } /** * Attempt to match the case on two strings. * * @param string $value * @param string $comparison * @return string */ protected static function matchCase($value, $comparison) { $functions = ['mb_strtolower', 'mb_strtoupper', 'ucfirst', 'ucwords']; foreach ($functions as $function) { if ($function($comparison) === $comparison) { return $function($value); } } return $value; } /** * Get the inflector instance. * * @return \Doctrine\Inflector\Inflector */ public static function inflector() { static $inflector; if (is_null($inflector)) { $inflector = new Inflector( new CachedWordInflector(new RulesetInflector( English\Rules::getSingularRuleset() )), new CachedWordInflector(new RulesetInflector( English\Rules::getPluralRuleset() )) ); } return $inflector; } } support/ViewErrorBag.php 0000644 00000005076 14736103231 0011337 0 ustar 00 <?php namespace Illuminate\Support; use Countable; use Illuminate\Contracts\Support\MessageBag as MessageBagContract; /** * @mixin \Illuminate\Contracts\Support\MessageBag */ class ViewErrorBag implements Countable { /** * The array of the view error bags. * * @var array */ protected $bags = []; /** * Checks if a named MessageBag exists in the bags. * * @param string $key * @return bool */ public function hasBag($key = 'default') { return isset($this->bags[$key]); } /** * Get a MessageBag instance from the bags. * * @param string $key * @return \Illuminate\Contracts\Support\MessageBag */ public function getBag($key) { return Arr::get($this->bags, $key) ?: new MessageBag; } /** * Get all the bags. * * @return array */ public function getBags() { return $this->bags; } /** * Add a new MessageBag instance to the bags. * * @param string $key * @param \Illuminate\Contracts\Support\MessageBag $bag * @return $this */ public function put($key, MessageBagContract $bag) { $this->bags[$key] = $bag; return $this; } /** * Determine if the default message bag has any messages. * * @return bool */ public function any() { return $this->count() > 0; } /** * Get the number of messages in the default bag. * * @return int */ public function count() { return $this->getBag('default')->count(); } /** * Dynamically call methods on the default bag. * * @param string $method * @param array $parameters * @return mixed */ public function __call($method, $parameters) { return $this->getBag('default')->$method(...$parameters); } /** * Dynamically access a view error bag. * * @param string $key * @return \Illuminate\Contracts\Support\MessageBag */ public function __get($key) { return $this->getBag($key); } /** * Dynamically set a view error bag. * * @param string $key * @param \Illuminate\Contracts\Support\MessageBag $value * @return void */ public function __set($key, $value) { $this->put($key, $value); } /** * Convert the default bag to its string representation. * * @return string */ public function __toString() { return (string) $this->getBag('default'); } } support/Debug/Dumper.php 0000644 00000001053 14736103231 0011252 0 ustar 00 <?php namespace Illuminate\Support\Debug; use Symfony\Component\VarDumper\Dumper\CliDumper; use Symfony\Component\VarDumper\Cloner\VarCloner; class Dumper { /** * Dump a value with elegance. * * @param mixed $value * @return void */ public function dump($value) { if (class_exists(CliDumper::class)) { $dumper = 'cli' === PHP_SAPI ? new CliDumper : new HtmlDumper; $dumper->dump((new VarCloner)->cloneVar($value)); } else { var_dump($value); } } } support/Debug/HtmlDumper.php 0000644 00000001626 14736103231 0012105 0 ustar 00 <?php namespace Illuminate\Support\Debug; use Symfony\Component\VarDumper\Dumper\HtmlDumper as SymfonyHtmlDumper; class HtmlDumper extends SymfonyHtmlDumper { /** * Colour definitions for output. * * @var array */ protected $styles = [ 'default' => 'background-color:#fff; color:#222; line-height:1.2em; font-weight:normal; font:12px Monaco, Consolas, monospace; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:100000', 'num' => 'color:#a71d5d', 'const' => 'color:#795da3', 'str' => 'color:#df5000', 'cchr' => 'color:#222', 'note' => 'color:#a71d5d', 'ref' => 'color:#a0a0a0', 'public' => 'color:#795da3', 'protected' => 'color:#795da3', 'private' => 'color:#795da3', 'meta' => 'color:#b729d9', 'key' => 'color:#df5000', 'index' => 'color:#a71d5d', ]; } support/NamespacedItemResolver.php 0000644 00000006305 14736103231 0013376 0 ustar 00 <?php namespace Illuminate\Support; class NamespacedItemResolver { /** * A cache of the parsed items. * * @var array */ protected $parsed = []; /** * Parse a key into namespace, group, and item. * * @param string $key * @return array */ public function parseKey($key) { // If we've already parsed the given key, we'll return the cached version we // already have, as this will save us some processing. We cache off every // key we parse so we can quickly return it on all subsequent requests. if (isset($this->parsed[$key])) { return $this->parsed[$key]; } // If the key does not contain a double colon, it means the key is not in a // namespace, and is just a regular configuration item. Namespaces are a // tool for organizing configuration items for things such as modules. if (strpos($key, '::') === false) { $segments = explode('.', $key); $parsed = $this->parseBasicSegments($segments); } else { $parsed = $this->parseNamespacedSegments($key); } // Once we have the parsed array of this key's elements, such as its groups // and namespace, we will cache each array inside a simple list that has // the key and the parsed array for quick look-ups for later requests. return $this->parsed[$key] = $parsed; } /** * Parse an array of basic segments. * * @param array $segments * @return array */ protected function parseBasicSegments(array $segments) { // The first segment in a basic array will always be the group, so we can go // ahead and grab that segment. If there is only one total segment we are // just pulling an entire group out of the array and not a single item. $group = $segments[0]; // If there is more than one segment in this group, it means we are pulling // a specific item out of a group and will need to return this item name // as well as the group so we know which item to pull from the arrays. $item = count($segments) === 1 ? null : implode('.', array_slice($segments, 1)); return [null, $group, $item]; } /** * Parse an array of namespaced segments. * * @param string $key * @return array */ protected function parseNamespacedSegments($key) { [$namespace, $item] = explode('::', $key); // First we'll just explode the first segment to get the namespace and group // since the item should be in the remaining segments. Once we have these // two pieces of data we can proceed with parsing out the item's value. $itemSegments = explode('.', $item); $groupAndItem = array_slice( $this->parseBasicSegments($itemSegments), 1 ); return array_merge([$namespace], $groupAndItem); } /** * Set the parsed value of a key. * * @param string $key * @param array $parsed * @return void */ public function setParsedKey($key, $parsed) { $this->parsed[$key] = $parsed; } } support/MessageBag.php 0000644 00000022305 14736103231 0010771 0 ustar 00 <?php namespace Illuminate\Support; use Countable; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Contracts\Support\Jsonable; use Illuminate\Contracts\Support\MessageBag as MessageBagContract; use Illuminate\Contracts\Support\MessageProvider; use JsonSerializable; class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, MessageBagContract, MessageProvider { /** * All of the registered messages. * * @var array */ protected $messages = []; /** * Default format for message output. * * @var string */ protected $format = ':message'; /** * Create a new message bag instance. * * @param array $messages * @return void */ public function __construct(array $messages = []) { foreach ($messages as $key => $value) { $value = $value instanceof Arrayable ? $value->toArray() : (array) $value; $this->messages[$key] = array_unique($value); } } /** * Get the keys present in the message bag. * * @return array */ public function keys() { return array_keys($this->messages); } /** * Add a message to the message bag. * * @param string $key * @param string $message * @return $this */ public function add($key, $message) { if ($this->isUnique($key, $message)) { $this->messages[$key][] = $message; } return $this; } /** * Determine if a key and message combination already exists. * * @param string $key * @param string $message * @return bool */ protected function isUnique($key, $message) { $messages = (array) $this->messages; return ! isset($messages[$key]) || ! in_array($message, $messages[$key]); } /** * Merge a new array of messages into the message bag. * * @param \Illuminate\Contracts\Support\MessageProvider|array $messages * @return $this */ public function merge($messages) { if ($messages instanceof MessageProvider) { $messages = $messages->getMessageBag()->getMessages(); } $this->messages = array_merge_recursive($this->messages, $messages); return $this; } /** * Determine if messages exist for all of the given keys. * * @param array|string|null $key * @return bool */ public function has($key) { if ($this->isEmpty()) { return false; } if (is_null($key)) { return $this->any(); } $keys = is_array($key) ? $key : func_get_args(); foreach ($keys as $key) { if ($this->first($key) === '') { return false; } } return true; } /** * Determine if messages exist for any of the given keys. * * @param array|string $keys * @return bool */ public function hasAny($keys = []) { if ($this->isEmpty()) { return false; } $keys = is_array($keys) ? $keys : func_get_args(); foreach ($keys as $key) { if ($this->has($key)) { return true; } } return false; } /** * Get the first message from the message bag for a given key. * * @param string|null $key * @param string|null $format * @return string */ public function first($key = null, $format = null) { $messages = is_null($key) ? $this->all($format) : $this->get($key, $format); $firstMessage = Arr::first($messages, null, ''); return is_array($firstMessage) ? Arr::first($firstMessage) : $firstMessage; } /** * Get all of the messages from the message bag for a given key. * * @param string $key * @param string|null $format * @return array */ public function get($key, $format = null) { // If the message exists in the message bag, we will transform it and return // the message. Otherwise, we will check if the key is implicit & collect // all the messages that match the given key and output it as an array. if (array_key_exists($key, $this->messages)) { return $this->transform( $this->messages[$key], $this->checkFormat($format), $key ); } if (Str::contains($key, '*')) { return $this->getMessagesForWildcardKey($key, $format); } return []; } /** * Get the messages for a wildcard key. * * @param string $key * @param string|null $format * @return array */ protected function getMessagesForWildcardKey($key, $format) { return collect($this->messages) ->filter(function ($messages, $messageKey) use ($key) { return Str::is($key, $messageKey); }) ->map(function ($messages, $messageKey) use ($format) { return $this->transform( $messages, $this->checkFormat($format), $messageKey ); })->all(); } /** * Get all of the messages for every key in the message bag. * * @param string|null $format * @return array */ public function all($format = null) { $format = $this->checkFormat($format); $all = []; foreach ($this->messages as $key => $messages) { $all = array_merge($all, $this->transform($messages, $format, $key)); } return $all; } /** * Get all of the unique messages for every key in the message bag. * * @param string|null $format * @return array */ public function unique($format = null) { return array_unique($this->all($format)); } /** * Format an array of messages. * * @param array $messages * @param string $format * @param string $messageKey * @return array */ protected function transform($messages, $format, $messageKey) { return collect((array) $messages) ->map(function ($message) use ($format, $messageKey) { // We will simply spin through the given messages and transform each one // replacing the :message place holder with the real message allowing // the messages to be easily formatted to each developer's desires. return str_replace([':message', ':key'], [$message, $messageKey], $format); })->all(); } /** * Get the appropriate format based on the given format. * * @param string $format * @return string */ protected function checkFormat($format) { return $format ?: $this->format; } /** * Get the raw messages in the message bag. * * @return array */ public function messages() { return $this->messages; } /** * Get the raw messages in the message bag. * * @return array */ public function getMessages() { return $this->messages(); } /** * Get the messages for the instance. * * @return \Illuminate\Support\MessageBag */ public function getMessageBag() { return $this; } /** * Get the default message format. * * @return string */ public function getFormat() { return $this->format; } /** * Set the default message format. * * @param string $format * @return \Illuminate\Support\MessageBag */ public function setFormat($format = ':message') { $this->format = $format; return $this; } /** * Determine if the message bag has any messages. * * @return bool */ public function isEmpty() { return ! $this->any(); } /** * Determine if the message bag has any messages. * * @return bool */ public function isNotEmpty() { return $this->any(); } /** * Determine if the message bag has any messages. * * @return bool */ public function any() { return $this->count() > 0; } /** * Get the number of messages in the message bag. * * @return int */ public function count() { return count($this->messages, COUNT_RECURSIVE) - count($this->messages); } /** * Get the instance as an array. * * @return array */ public function toArray() { return $this->getMessages(); } /** * Convert the object into something JSON serializable. * * @return array */ public function jsonSerialize() { return $this->toArray(); } /** * Convert the object to its JSON representation. * * @param int $options * @return string */ public function toJson($options = 0) { return json_encode($this->jsonSerialize(), $options); } /** * Convert the message bag to its string representation. * * @return string */ public function __toString() { return $this->toJson(); } } support/DateFactory.php 0000644 00000017526 14736103231 0011211 0 ustar 00 <?php namespace Illuminate\Support; use Carbon\Factory; use InvalidArgumentException; /** * @see https://carbon.nesbot.com/docs/ * @see https://github.com/briannesbitt/Carbon/blob/master/src/Carbon/Factory.php * * @method static Carbon create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $tz = null) * @method static Carbon createFromDate($year = null, $month = null, $day = null, $tz = null) * @method static Carbon|false createFromFormat($format, $time, $tz = null) * @method static Carbon createFromTime($hour = 0, $minute = 0, $second = 0, $tz = null) * @method static Carbon createFromTimeString($time, $tz = null) * @method static Carbon createFromTimestamp($timestamp, $tz = null) * @method static Carbon createFromTimestampMs($timestamp, $tz = null) * @method static Carbon createFromTimestampUTC($timestamp) * @method static Carbon createMidnightDate($year = null, $month = null, $day = null, $tz = null) * @method static Carbon|false createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $tz = null) * @method static Carbon disableHumanDiffOption($humanDiffOption) * @method static Carbon enableHumanDiffOption($humanDiffOption) * @method static mixed executeWithLocale($locale, $func) * @method static Carbon fromSerialized($value) * @method static array getAvailableLocales() * @method static array getDays() * @method static int getHumanDiffOptions() * @method static array getIsoUnits() * @method static Carbon getLastErrors() * @method static string getLocale() * @method static int getMidDayAt() * @method static Carbon getTestNow() * @method static \Symfony\Component\Translation\TranslatorInterface getTranslator() * @method static int getWeekEndsAt() * @method static int getWeekStartsAt() * @method static array getWeekendDays() * @method static bool hasFormat($date, $format) * @method static bool hasMacro($name) * @method static bool hasRelativeKeywords($time) * @method static bool hasTestNow() * @method static Carbon instance($date) * @method static bool isImmutable() * @method static bool isModifiableUnit($unit) * @method static Carbon isMutable() * @method static bool isStrictModeEnabled() * @method static bool localeHasDiffOneDayWords($locale) * @method static bool localeHasDiffSyntax($locale) * @method static bool localeHasDiffTwoDayWords($locale) * @method static bool localeHasPeriodSyntax($locale) * @method static bool localeHasShortUnits($locale) * @method static void macro($name, $macro) * @method static Carbon|null make($var) * @method static Carbon maxValue() * @method static Carbon minValue() * @method static void mixin($mixin) * @method static Carbon now($tz = null) * @method static Carbon parse($time = null, $tz = null) * @method static string pluralUnit(string $unit) * @method static void resetMonthsOverflow() * @method static void resetToStringFormat() * @method static void resetYearsOverflow() * @method static void serializeUsing($callback) * @method static Carbon setHumanDiffOptions($humanDiffOptions) * @method static bool setLocale($locale) * @method static void setMidDayAt($hour) * @method static Carbon setTestNow($testNow = null) * @method static void setToStringFormat($format) * @method static void setTranslator(\Symfony\Component\Translation\TranslatorInterface $translator) * @method static Carbon setUtf8($utf8) * @method static void setWeekEndsAt($day) * @method static void setWeekStartsAt($day) * @method static void setWeekendDays($days) * @method static bool shouldOverflowMonths() * @method static bool shouldOverflowYears() * @method static string singularUnit(string $unit) * @method static Carbon today($tz = null) * @method static Carbon tomorrow($tz = null) * @method static void useMonthsOverflow($monthsOverflow = true) * @method static Carbon useStrictMode($strictModeEnabled = true) * @method static void useYearsOverflow($yearsOverflow = true) * @method static Carbon yesterday($tz = null) */ class DateFactory { /** * The default class that will be used for all created dates. * * @var string */ const DEFAULT_CLASS_NAME = Carbon::class; /** * The type (class) of dates that should be created. * * @var string */ protected static $dateClass; /** * This callable may be used to intercept date creation. * * @var callable */ protected static $callable; /** * The Carbon factory that should be used when creating dates. * * @var object */ protected static $factory; /** * Use the given handler when generating dates (class name, callable, or factory). * * @param mixed $handler * @return mixed * * @throws \InvalidArgumentException */ public static function use($handler) { if (is_callable($handler) && is_object($handler)) { return static::useCallable($handler); } elseif (is_string($handler)) { return static::useClass($handler); } elseif ($handler instanceof Factory) { return static::useFactory($handler); } throw new InvalidArgumentException('Invalid date creation handler. Please provide a class name, callable, or Carbon factory.'); } /** * Use the default date class when generating dates. * * @return void */ public static function useDefault() { static::$dateClass = null; static::$callable = null; static::$factory = null; } /** * Execute the given callable on each date creation. * * @param callable $callable * @return void */ public static function useCallable(callable $callable) { static::$callable = $callable; static::$dateClass = null; static::$factory = null; } /** * Use the given date type (class) when generating dates. * * @param string $dateClass * @return void */ public static function useClass($dateClass) { static::$dateClass = $dateClass; static::$factory = null; static::$callable = null; } /** * Use the given Carbon factory when generating dates. * * @param object $factory * @return void */ public static function useFactory($factory) { static::$factory = $factory; static::$dateClass = null; static::$callable = null; } /** * Handle dynamic calls to generate dates. * * @param string $method * @param array $parameters * @return mixed * * @throws \RuntimeException */ public function __call($method, $parameters) { $defaultClassName = static::DEFAULT_CLASS_NAME; // Using callable to generate dates... if (static::$callable) { return call_user_func(static::$callable, $defaultClassName::$method(...$parameters)); } // Using Carbon factory to generate dates... if (static::$factory) { return static::$factory->$method(...$parameters); } $dateClass = static::$dateClass ?: $defaultClassName; // Check if date can be created using public class method... if (method_exists($dateClass, $method) || method_exists($dateClass, 'hasMacro') && $dateClass::hasMacro($method)) { return $dateClass::$method(...$parameters); } // If that fails, create the date with the default class.. $date = $defaultClassName::$method(...$parameters); // If the configured class has an "instance" method, we'll try to pass our date into there... if (method_exists($dateClass, 'instance')) { return $dateClass::instance($date); } // Otherwise, assume the configured class has a DateTime compatible constructor... return new $dateClass($date->format('Y-m-d H:i:s.u'), $date->getTimezone()); } } support/Carbon.php 0000644 00000000163 14736103231 0010175 0 ustar 00 <?php namespace Illuminate\Support; use Carbon\Carbon as BaseCarbon; class Carbon extends BaseCarbon { // } support/HigherOrderCollectionProxy.php 0000644 00000002600 14736103231 0014247 0 ustar 00 <?php namespace Illuminate\Support; /** * @mixin \Illuminate\Support\Enumerable */ class HigherOrderCollectionProxy { /** * The collection being operated on. * * @var \Illuminate\Support\Enumerable */ protected $collection; /** * The method being proxied. * * @var string */ protected $method; /** * Create a new proxy instance. * * @param \Illuminate\Support\Enumerable $collection * @param string $method * @return void */ public function __construct(Enumerable $collection, $method) { $this->method = $method; $this->collection = $collection; } /** * Proxy accessing an attribute onto the collection items. * * @param string $key * @return mixed */ public function __get($key) { return $this->collection->{$this->method}(function ($value) use ($key) { return is_array($value) ? $value[$key] : $value->{$key}; }); } /** * Proxy a method call onto the collection items. * * @param string $method * @param array $parameters * @return mixed */ public function __call($method, $parameters) { return $this->collection->{$this->method}(function ($value) use ($method, $parameters) { return $value->{$method}(...$parameters); }); } } support/ProcessUtils.php 0000644 00000004002 14736103231 0011424 0 ustar 00 <?php namespace Illuminate\Support; /** * ProcessUtils is a bunch of utility methods. * * This class was originally copied from Symfony 3. */ class ProcessUtils { /** * Escapes a string to be used as a shell argument. * * @param string $argument * @return string */ public static function escapeArgument($argument) { // Fix for PHP bug #43784 escapeshellarg removes % from given string // Fix for PHP bug #49446 escapeshellarg doesn't work on Windows // @see https://bugs.php.net/bug.php?id=43784 // @see https://bugs.php.net/bug.php?id=49446 if ('\\' === DIRECTORY_SEPARATOR) { if ('' === $argument) { return '""'; } $escapedArgument = ''; $quote = false; foreach (preg_split('/(")/', $argument, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) as $part) { if ('"' === $part) { $escapedArgument .= '\\"'; } elseif (self::isSurroundedBy($part, '%')) { // Avoid environment variable expansion $escapedArgument .= '^%"'.substr($part, 1, -1).'"^%'; } else { // escape trailing backslash if ('\\' === substr($part, -1)) { $part .= '\\'; } $quote = true; $escapedArgument .= $part; } } if ($quote) { $escapedArgument = '"'.$escapedArgument.'"'; } return $escapedArgument; } return "'".str_replace("'", "'\\''", $argument)."'"; } /** * Is the given string surrounded by the given character? * * @param string $arg * @param string $char * @return bool */ protected static function isSurroundedBy($arg, $char) { return 2 < strlen($arg) && $char === $arg[0] && $char === $arg[strlen($arg) - 1]; } } support/HigherOrderWhenProxy.php 0000644 00000002433 14736103231 0013061 0 ustar 00 <?php namespace Illuminate\Support; /** * @mixin \Illuminate\Support\Enumerable */ class HigherOrderWhenProxy { /** * The collection being operated on. * * @var \Illuminate\Support\Enumerable */ protected $collection; /** * The condition for proxying. * * @var bool */ protected $condition; /** * Create a new proxy instance. * * @param \Illuminate\Support\Enumerable $collection * @param bool $condition * @return void */ public function __construct(Enumerable $collection, $condition) { $this->condition = $condition; $this->collection = $collection; } /** * Proxy accessing an attribute onto the collection. * * @param string $key * @return mixed */ public function __get($key) { return $this->condition ? $this->collection->{$key} : $this->collection; } /** * Proxy a method call onto the collection. * * @param string $method * @param array $parameters * @return mixed */ public function __call($method, $parameters) { return $this->condition ? $this->collection->{$method}(...$parameters) : $this->collection; } } support/HigherOrderTapProxy.php 0000644 00000001231 14736103231 0012677 0 ustar 00 <?php namespace Illuminate\Support; class HigherOrderTapProxy { /** * The target being tapped. * * @var mixed */ public $target; /** * Create a new tap proxy instance. * * @param mixed $target * @return void */ public function __construct($target) { $this->target = $target; } /** * Dynamically pass method calls to the target. * * @param string $method * @param array $parameters * @return mixed */ public function __call($method, $parameters) { $this->target->{$method}(...$parameters); return $this->target; } } support/AggregateServiceProvider.php 0000644 00000001743 14736103231 0013720 0 ustar 00 <?php namespace Illuminate\Support; class AggregateServiceProvider extends ServiceProvider { /** * The provider class names. * * @var array */ protected $providers = []; /** * An array of the service provider instances. * * @var array */ protected $instances = []; /** * Register the service provider. * * @return void */ public function register() { $this->instances = []; foreach ($this->providers as $provider) { $this->instances[] = $this->app->register($provider); } } /** * Get the services provided by the provider. * * @return array */ public function provides() { $provides = []; foreach ($this->providers as $provider) { $instance = $this->app->resolveProvider($provider); $provides = array_merge($provides, $instance->provides()); } return $provides; } } support/ClassLoader.php 0000644 00000004403 14736103231 0011166 0 ustar 00 <?php namespace Illuminate\Support; class ClassLoader { /** * The registered directories. * * @var array */ protected static $directories = []; /** * Indicates if a ClassLoader has been registered. * * @var bool */ protected static $registered = false; /** * Load the given class file. * * @param string $class * @return bool */ public static function load($class) { $class = static::normalizeClass($class); foreach (static::$directories as $directory) { if (file_exists($path = $directory.DIRECTORY_SEPARATOR.$class)) { require_once $path; return true; } } return false; } /** * Get the normal file name for a class. * * @param string $class * @return string */ public static function normalizeClass($class) { if ($class[0] == '\\') { $class = substr($class, 1); } return str_replace(['\\', '_'], DIRECTORY_SEPARATOR, $class).'.php'; } /** * Register the given class loader on the auto-loader stack. * * @return void */ public static function register() { if (! static::$registered) { static::$registered = spl_autoload_register([static::class, 'load']); } } /** * Add directories to the class loader. * * @param string|array $directories * @return void */ public static function addDirectories($directories) { static::$directories = array_unique(array_merge(static::$directories, (array) $directories)); } /** * Remove directories from the class loader. * * @param string|array $directories * @return void */ public static function removeDirectories($directories = null) { if (is_null($directories)) { static::$directories = []; } else { static::$directories = array_diff(static::$directories, (array) $directories); } } /** * Gets all the directories registered with the loader. * * @return array */ public static function getDirectories() { return static::$directories; } } support/Facades/Broadcast.php 0000644 00000001344 14736103231 0012223 0 ustar 00 <?php namespace Illuminate\Support\Facades; use Illuminate\Contracts\Broadcasting\Factory as BroadcastingFactoryContract; /** * @method static \Illuminate\Broadcasting\Broadcasters\Broadcaster channel(string $channel, callable|string $callback, array $options = []) * @method static mixed auth(\Illuminate\Http\Request $request) * @method static void connection($name = null); * @method static void routes(array $attributes = null) * * @see \Illuminate\Contracts\Broadcasting\Factory */ class Broadcast extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return BroadcastingFactoryContract::class; } } support/Facades/Artisan.php 0000644 00000002077 14736103231 0011726 0 ustar 00 <?php namespace Illuminate\Support\Facades; use Illuminate\Contracts\Console\Kernel as ConsoleKernelContract; /** * @method static \Illuminate\Foundation\Bus\PendingDispatch queue(string $command, array $parameters = []) * @method static \Illuminate\Foundation\Console\ClosureCommand command(string $command, callable $callback) * @method static array all() * @method static int call(string $command, array $parameters = [], \Symfony\Component\Console\Output\OutputInterface|null $outputBuffer = null) * @method static int handle(\Symfony\Component\Console\Input\InputInterface $input, \Symfony\Component\Console\Output\OutputInterface|null $output = null) * @method static string output() * @method static void terminate(\Symfony\Component\Console\Input\InputInterface $input, int $status) * * @see \Illuminate\Contracts\Console\Kernel */ class Artisan extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return ConsoleKernelContract::class; } } support/Facades/Lang.php 0000644 00000001164 14736103231 0011202 0 ustar 00 <?php namespace Illuminate\Support\Facades; /** * @method static mixed get(string $key, array $replace = [], string $locale = null, bool $fallback = true) * @method static string choice(string $key, \Countable|int|array $number, array $replace = [], string $locale = null) * @method static string getLocale() * @method static void setLocale(string $locale) * * @see \Illuminate\Translation\Translator */ class Lang extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'translator'; } } support/Facades/Redirect.php 0000644 00000004004 14736103231 0012056 0 ustar 00 <?php namespace Illuminate\Support\Facades; /** * @method static \Illuminate\Http\RedirectResponse action(string $action, array $parameters = [], int $status = 302, array $headers = []) * @method static \Illuminate\Http\RedirectResponse away(string $path, int $status = 302, array $headers = []) * @method static \Illuminate\Http\RedirectResponse back(int $status = 302, array $headers = [], $fallback = false) * @method static \Illuminate\Http\RedirectResponse guest(string $path, int $status = 302, array $headers = [], bool $secure = null) * @method static \Illuminate\Http\RedirectResponse home(int $status = 302) * @method static \Illuminate\Http\RedirectResponse intended(string $default = '/', int $status = 302, array $headers = [], bool $secure = null) * @method static \Illuminate\Http\RedirectResponse refresh(int $status = 302, array $headers = []) * @method static \Illuminate\Http\RedirectResponse route(string $route, array $parameters = [], int $status = 302, array $headers = []) * @method static \Illuminate\Http\RedirectResponse secure(string $path, int $status = 302, array $headers = []) * @method static \Illuminate\Http\RedirectResponse signedRoute(string $name, array $parameters = [], \DateTimeInterface|\DateInterval|int $expiration = null, int $status = 302, array $headers = []) * @method static \Illuminate\Http\RedirectResponse temporarySignedRoute(string $name, \DateTimeInterface|\DateInterval|int $expiration, array $parameters = [], int $status = 302, array $headers = []) * @method static \Illuminate\Http\RedirectResponse to(string $path, int $status = 302, array $headers = [], bool $secure = null) * @method static \Illuminate\Routing\UrlGenerator getUrlGenerator() * @method static void setSession(\Illuminate\Session\Store $session) * * @see \Illuminate\Routing\Redirector */ class Redirect extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'redirect'; } } support/Facades/Notification.php 0000644 00000004016 14736103231 0012746 0 ustar 00 <?php namespace Illuminate\Support\Facades; use Illuminate\Notifications\AnonymousNotifiable; use Illuminate\Notifications\ChannelManager; use Illuminate\Support\Testing\Fakes\NotificationFake; /** * @method static \Illuminate\Notifications\ChannelManager locale(string|null $locale) * @method static \Illuminate\Support\Collection sent(mixed $notifiable, string $notification, callable $callback = null) * @method static bool hasSent(mixed $notifiable, string $notification) * @method static mixed channel(string|null $name = null) * @method static void assertNotSentTo(mixed $notifiable, string $notification, callable $callback = null) * @method static void assertNothingSent() * @method static void assertSentTo(mixed $notifiable, string $notification, callable $callback = null) * @method static void assertSentToTimes(mixed $notifiable, string $notification, int $times = 1) * @method static void assertTimesSent(int $expectedCount, string $notification) * @method static void send(\Illuminate\Support\Collection|array|mixed $notifiables, $notification) * @method static void sendNow(\Illuminate\Support\Collection|array|mixed $notifiables, $notification) * * @see \Illuminate\Notifications\ChannelManager */ class Notification extends Facade { /** * Replace the bound instance with a fake. * * @return \Illuminate\Support\Testing\Fakes\NotificationFake */ public static function fake() { static::swap($fake = new NotificationFake); return $fake; } /** * Begin sending a notification to an anonymous notifiable. * * @param string $channel * @param mixed $route * @return \Illuminate\Notifications\AnonymousNotifiable */ public static function route($channel, $route) { return (new AnonymousNotifiable)->route($channel, $route); } /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return ChannelManager::class; } } support/Facades/Cookie.php 0000644 00000001715 14736103231 0011534 0 ustar 00 <?php namespace Illuminate\Support\Facades; /** * @method static array getQueuedCookies() * @method static unqueue($name) * @method static void queue(...$parameters) * * @see \Illuminate\Cookie\CookieJar */ class Cookie extends Facade { /** * Determine if a cookie exists on the request. * * @param string $key * @return bool */ public static function has($key) { return ! is_null(static::$app['request']->cookie($key, null)); } /** * Retrieve a cookie from the request. * * @param string|null $key * @param mixed $default * @return string|array|null */ public static function get($key = null, $default = null) { return static::$app['request']->cookie($key, $default); } /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'cookie'; } } support/Facades/Session.php 0000644 00000002566 14736103231 0011753 0 ustar 00 <?php namespace Illuminate\Support\Facades; /** * @method static \SessionHandlerInterface getHandler() * @method static array all() * @method static bool exists(string|array $key) * @method static bool handlerNeedsRequest() * @method static bool has(string|array $key) * @method static bool isStarted() * @method static bool migrate(bool $destroy = false) * @method static bool save() * @method static bool start() * @method static mixed get(string $key, $default = null) * @method static mixed pull(string $key, $default = null) * @method static mixed remove(string $key) * @method static string getId() * @method static string getName() * @method static string token() * @method static string|null previousUrl() * @method static void flush() * @method static void forget(string|array $keys) * @method static void push(string $key, mixed $value) * @method static void put(string|array $key, $value = null) * @method static void setId(string $id) * @method static void setPreviousUrl(string $url) * @method static void setRequestOnHandler(\Illuminate\Http\Request $request) * * @see \Illuminate\Session\SessionManager * @see \Illuminate\Session\Store */ class Session extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'session'; } } support/Facades/Http.php 0000644 00000005441 14736103231 0011242 0 ustar 00 <?php namespace Illuminate\Support\Facades; use Illuminate\Http\Client\Factory; /** * @method static \Illuminate\Http\Client\PendingRequest accept(string $contentType) * @method static \Illuminate\Http\Client\PendingRequest acceptJson() * @method static \Illuminate\Http\Client\PendingRequest asForm() * @method static \Illuminate\Http\Client\PendingRequest asJson() * @method static \Illuminate\Http\Client\PendingRequest asMultipart() * @method static \Illuminate\Http\Client\PendingRequest attach(string $name, string $contents, string|null $filename = null, array $headers = []) * @method static \Illuminate\Http\Client\PendingRequest beforeSending(callable $callback) * @method static \Illuminate\Http\Client\PendingRequest bodyFormat(string $format) * @method static \Illuminate\Http\Client\PendingRequest contentType(string $contentType) * @method static \Illuminate\Http\Client\PendingRequest retry(int $times, int $sleep = 0) * @method static \Illuminate\Http\Client\PendingRequest stub(callable $callback) * @method static \Illuminate\Http\Client\PendingRequest timeout(int $seconds) * @method static \Illuminate\Http\Client\PendingRequest withBasicAuth(string $username, string $password) * @method static \Illuminate\Http\Client\PendingRequest withCookies(array $cookies, string $domain) * @method static \Illuminate\Http\Client\PendingRequest withDigestAuth(string $username, string $password) * @method static \Illuminate\Http\Client\PendingRequest withHeaders(array $headers) * @method static \Illuminate\Http\Client\PendingRequest withOptions(array $options) * @method static \Illuminate\Http\Client\PendingRequest withToken(string $token, string $type = 'Bearer') * @method static \Illuminate\Http\Client\PendingRequest withoutRedirecting() * @method static \Illuminate\Http\Client\PendingRequest withoutVerifying() * @method static \Illuminate\Http\Client\Response delete(string $url, array $data = []) * @method static \Illuminate\Http\Client\Response get(string $url, array $query = []) * @method static \Illuminate\Http\Client\Response head(string $url, array $query = []) * @method static \Illuminate\Http\Client\Response patch(string $url, array $data = []) * @method static \Illuminate\Http\Client\Response post(string $url, array $data = []) * @method static \Illuminate\Http\Client\Response put(string $url, array $data = []) * @method static \Illuminate\Http\Client\Response send(string $method, string $url, array $options = []) * @method static \Illuminate\Http\Client\ResponseSequence fakeSequence(string $urlPattern = '*') * * @see \Illuminate\Http\Client\Factory */ class Http extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return Factory::class; } } support/Facades/Validator.php 0000644 00000001335 14736103231 0012246 0 ustar 00 <?php namespace Illuminate\Support\Facades; /** * @method static \Illuminate\Contracts\Validation\Validator make(array $data, array $rules, array $messages = [], array $customAttributes = []) * @method static void extend(string $rule, \Closure|string $extension, string $message = null) * @method static void extendImplicit(string $rule, \Closure|string $extension, string $message = null) * @method static void replacer(string $rule, \Closure|string $replacer) * * @see \Illuminate\Validation\Factory */ class Validator extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'validator'; } } support/Facades/Queue.php 0000644 00000003625 14736103231 0011411 0 ustar 00 <?php namespace Illuminate\Support\Facades; use Illuminate\Support\Testing\Fakes\QueueFake; /** * @method static \Illuminate\Contracts\Queue\Job|null pop(string $queue = null) * @method static \Illuminate\Contracts\Queue\Queue setConnectionName(string $name) * @method static int size(string $queue = null) * @method static mixed bulk(array $jobs, mixed $data = '', string $queue = null) * @method static mixed later(\DateTimeInterface|\DateInterval|int $delay, string|object $job, mixed $data = '', string $queue = null) * @method static mixed laterOn(string $queue, \DateTimeInterface|\DateInterval|int $delay, string|object $job, mixed $data = '') * @method static mixed push(string|object $job, mixed $data = '', $queue = null) * @method static mixed pushOn(string $queue, string|object $job, mixed $data = '') * @method static mixed pushRaw(string $payload, string $queue = null, array $options = []) * @method static string getConnectionName() * @method static void assertNotPushed(string $job, callable $callback = null) * @method static void assertNothingPushed() * @method static void assertPushed(string $job, callable|int $callback = null) * @method static void assertPushedOn(string $queue, string $job, callable|int $callback = null) * @method static void assertPushedWithChain(string $job, array $expectedChain = [], callable $callback = null) * * @see \Illuminate\Queue\QueueManager * @see \Illuminate\Queue\Queue */ class Queue extends Facade { /** * Replace the bound instance with a fake. * * @return \Illuminate\Support\Testing\Fakes\QueueFake */ public static function fake() { static::swap($fake = new QueueFake(static::getFacadeApplication())); return $fake; } /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'queue'; } } support/Facades/URL.php 0000644 00000002632 14736103231 0010764 0 ustar 00 <?php namespace Illuminate\Support\Facades; /** * @method static \Illuminate\Contracts\Routing\UrlGenerator setRootControllerNamespace(string $rootNamespace) * @method static bool hasValidSignature(\Illuminate\Http\Request $request, bool $absolute = true) * @method static string action(string $action, $parameters = [], bool $absolute = true) * @method static string asset(string $path, bool $secure = null) * @method static string current() * @method static string full() * @method static string previous($fallback = false) * @method static string route(string $name, $parameters = [], bool $absolute = true) * @method static string secure(string $path, array $parameters = []) * @method static string signedRoute(string $name, array $parameters = [], \DateTimeInterface|\DateInterval|int $expiration = null, bool $absolute = true) * @method static string temporarySignedRoute(string $name, \DateTimeInterface|\DateInterval|int $expiration, array $parameters = [], bool $absolute = true) * @method static string to(string $path, $extra = [], bool $secure = null) * @method static void defaults(array $defaults) * @method static void forceScheme(string $scheme) * * @see \Illuminate\Routing\UrlGenerator */ class URL extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'url'; } } support/Facades/Blade.php 0000644 00000003103 14736103231 0011323 0 ustar 00 <?php namespace Illuminate\Support\Facades; /** * @method static array getClassComponentAliases() * @method static array getCustomDirectives() * @method static array getExtensions() * @method static bool check(string $name, array ...$parameters) * @method static string compileString(string $value) * @method static string getPath() * @method static string stripParentheses(string $expression) * @method static void aliasComponent(string $path, string|null $alias = null) * @method static void aliasInclude(string $path, string|null $alias = null) * @method static void compile(string|null $path = null) * @method static void component(string $class, string|null $alias = null, string $prefix = '') * @method static void components(array $components, string $prefix = '') * @method static void directive(string $name, callable $handler) * @method static void extend(callable $compiler) * @method static void if(string $name, callable $callback) * @method static void include(string $path, string|null $alias = null) * @method static void precompiler(callable $precompiler) * @method static void setEchoFormat(string $format) * @method static void setPath(string $path) * @method static void withDoubleEncoding() * @method static void withoutComponentTags() * @method static void withoutDoubleEncoding() * * @see \Illuminate\View\Compilers\BladeCompiler */ class Blade extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'blade.compiler'; } } support/Facades/Auth.php 0000644 00000004613 14736103231 0011224 0 ustar 00 <?php namespace Illuminate\Support\Facades; use Laravel\Ui\UiServiceProvider; use LogicException; /** * @method static \Illuminate\Auth\AuthManager extend(string $driver, \Closure $callback) * @method static \Illuminate\Auth\AuthManager provider(string $name, \Closure $callback) * @method static \Illuminate\Contracts\Auth\Authenticatable loginUsingId(mixed $id, bool $remember = false) * @method static \Illuminate\Contracts\Auth\Authenticatable|null user() * @method static \Illuminate\Contracts\Auth\Guard|\Illuminate\Contracts\Auth\StatefulGuard guard(string|null $name = null) * @method static \Illuminate\Contracts\Auth\UserProvider|null createUserProvider(string $provider = null) * @method static \Symfony\Component\HttpFoundation\Response|null onceBasic(string $field = 'email',array $extraConditions = []) * @method static bool attempt(array $credentials = [], bool $remember = false) * @method static bool check() * @method static bool guest() * @method static bool once(array $credentials = []) * @method static bool onceUsingId(mixed $id) * @method static bool validate(array $credentials = []) * @method static bool viaRemember() * @method static bool|null logoutOtherDevices(string $password, string $attribute = 'password') * @method static int|string|null id() * @method static void login(\Illuminate\Contracts\Auth\Authenticatable $user, bool $remember = false) * @method static void logout() * @method static void setUser(\Illuminate\Contracts\Auth\Authenticatable $user) * @method static void shouldUse(string $name); * * @see \Illuminate\Auth\AuthManager * @see \Illuminate\Contracts\Auth\Factory * @see \Illuminate\Contracts\Auth\Guard * @see \Illuminate\Contracts\Auth\StatefulGuard */ class Auth extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'auth'; } /** * Register the typical authentication routes for an application. * * @param array $options * @return void */ public static function routes(array $options = []) { if (! array_key_exists(UiServiceProvider::class, static::$app->getLoadedProviders())) { throw new LogicException('Please install the laravel/ui package in order to use the Auth::routes() method.'); } static::$app->make('router')->auth($options); } } support/Facades/Schema.php 0000644 00000003132 14736103231 0011516 0 ustar 00 <?php namespace Illuminate\Support\Facades; /** * @method static \Illuminate\Database\Schema\Builder create(string $table, \Closure $callback) * @method static \Illuminate\Database\Schema\Builder disableForeignKeyConstraints() * @method static \Illuminate\Database\Schema\Builder drop(string $table) * @method static \Illuminate\Database\Schema\Builder dropIfExists(string $table) * @method static \Illuminate\Database\Schema\Builder enableForeignKeyConstraints() * @method static \Illuminate\Database\Schema\Builder rename(string $from, string $to) * @method static \Illuminate\Database\Schema\Builder table(string $table, \Closure $callback) * @method static bool hasColumn(string $table, string $column) * @method static bool hasColumns(string $table, array $columns) * @method static bool hasTable(string $table) * @method static void defaultStringLength(int $length) * @method static void registerCustomDoctrineType(string $class, string $name, string $type) * * @see \Illuminate\Database\Schema\Builder */ class Schema extends Facade { /** * Get a schema builder instance for a connection. * * @param string|null $name * @return \Illuminate\Database\Schema\Builder */ public static function connection($name) { return static::$app['db']->connection($name)->getSchemaBuilder(); } /** * Get a schema builder instance for the default connection. * * @return \Illuminate\Database\Schema\Builder */ protected static function getFacadeAccessor() { return static::$app['db']->connection()->getSchemaBuilder(); } } support/Facades/Redis.php 0000644 00000001161 14736103231 0011364 0 ustar 00 <?php namespace Illuminate\Support\Facades; /** * @method static \Illuminate\Redis\Connections\Connection connection(string $name = null) * @method static \Illuminate\Redis\Limiters\ConcurrencyLimiterBuilder funnel(string $name) * @method static \Illuminate\Redis\Limiters\DurationLimiterBuilder throttle(string $name) * * @see \Illuminate\Redis\RedisManager * @see \Illuminate\Contracts\Redis\Factory */ class Redis extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'redis'; } } support/Facades/Mail.php 0000644 00000003704 14736103231 0011205 0 ustar 00 <?php namespace Illuminate\Support\Facades; use Illuminate\Support\Testing\Fakes\MailFake; /** * @method static \Illuminate\Mail\PendingMail bcc($users) * @method static \Illuminate\Mail\PendingMail to($users) * @method static \Illuminate\Support\Collection queued(string $mailable, \Closure|string $callback = null) * @method static \Illuminate\Support\Collection sent(string $mailable, \Closure|string $callback = null) * @method static array failures() * @method static bool hasQueued(string $mailable) * @method static bool hasSent(string $mailable) * @method static mixed later(\DateTimeInterface|\DateInterval|int $delay, \Illuminate\Contracts\Mail\Mailable|string|array $view, string $queue = null) * @method static mixed queue(\Illuminate\Contracts\Mail\Mailable|string|array $view, string $queue = null) * @method static void assertNotQueued(string $mailable, callable $callback = null) * @method static void assertNotSent(string $mailable, callable|int $callback = null) * @method static void assertNothingQueued() * @method static void assertNothingSent() * @method static void assertQueued(string $mailable, callable|int $callback = null) * @method static void assertSent(string $mailable, callable|int $callback = null) * @method static void raw(string $text, $callback) * @method static void send(\Illuminate\Contracts\Mail\Mailable|string|array $view, array $data = [], \Closure|string $callback = null) * * @see \Illuminate\Mail\Mailer * @see \Illuminate\Support\Testing\Fakes\MailFake */ class Mail extends Facade { /** * Replace the bound instance with a fake. * * @return \Illuminate\Support\Testing\Fakes\MailFake */ public static function fake() { static::swap($fake = new MailFake); return $fake; } /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'mail.manager'; } } support/Facades/DB.php 0000644 00000003234 14736103231 0010606 0 ustar 00 <?php namespace Illuminate\Support\Facades; /** * @method static \Illuminate\Database\ConnectionInterface connection(string $name = null) * @method static \Illuminate\Database\Query\Builder table(string $table, string $as = null) * @method static \Illuminate\Database\Query\Expression raw($value) * @method static array prepareBindings(array $bindings) * @method static array pretend(\Closure $callback) * @method static array select(string $query, array $bindings = [], bool $useReadPdo = true) * @method static bool insert(string $query, array $bindings = []) * @method static bool statement(string $query, array $bindings = []) * @method static bool unprepared(string $query) * @method static int affectingStatement(string $query, array $bindings = []) * @method static int delete(string $query, array $bindings = []) * @method static int transactionLevel() * @method static int update(string $query, array $bindings = []) * @method static mixed selectOne(string $query, array $bindings = [], bool $useReadPdo = true) * @method static mixed transaction(\Closure $callback, int $attempts = 1) * @method static string getDefaultConnection() * @method static void beginTransaction() * @method static void commit() * @method static void listen(\Closure $callback) * @method static void rollBack(int $toLevel = null) * @method static void setDefaultConnection(string $name) * * @see \Illuminate\Database\DatabaseManager * @see \Illuminate\Database\Connection */ class DB extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'db'; } } support/Facades/Hash.php 0000644 00000001111 14736103231 0011174 0 ustar 00 <?php namespace Illuminate\Support\Facades; /** * @method static array info(string $hashedValue) * @method static bool check(string $value, string $hashedValue, array $options = []) * @method static bool needsRehash(string $hashedValue, array $options = []) * @method static string make(string $value, array $options = []) * * @see \Illuminate\Hashing\HashManager */ class Hash extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'hash'; } } support/Facades/Password.php 0000644 00000002155 14736103231 0012124 0 ustar 00 <?php namespace Illuminate\Support\Facades; use Illuminate\Contracts\Auth\PasswordBroker; /** * @method static mixed reset(array $credentials, \Closure $callback) * @method static string sendResetLink(array $credentials) * * @see \Illuminate\Auth\Passwords\PasswordBroker */ class Password extends Facade { /** * Constant representing a successfully sent reminder. * * @var string */ const RESET_LINK_SENT = PasswordBroker::RESET_LINK_SENT; /** * Constant representing a successfully reset password. * * @var string */ const PASSWORD_RESET = PasswordBroker::PASSWORD_RESET; /** * Constant representing the user not found response. * * @var string */ const INVALID_USER = PasswordBroker::INVALID_USER; /** * Constant representing an invalid token. * * @var string */ const INVALID_TOKEN = PasswordBroker::INVALID_TOKEN; /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'auth.password'; } } support/Facades/Event.php 0000644 00000005035 14736103231 0011403 0 ustar 00 <?php namespace Illuminate\Support\Facades; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Testing\Fakes\EventFake; /** * @method static \Closure createClassListener(string $listener, bool $wildcard = false) * @method static \Closure makeListener(\Closure|string $listener, bool $wildcard = false) * @method static \Illuminate\Events\Dispatcher setQueueResolver(callable $resolver) * @method static array getListeners(string $eventName) * @method static array|null dispatch(string|object $event, mixed $payload = [], bool $halt = false) * @method static array|null until(string|object $event, mixed $payload = []) * @method static bool hasListeners(string $eventName) * @method static void assertDispatched(string $event, callable|int $callback = null) * @method static void assertDispatchedTimes(string $event, int $times = 1) * @method static void assertNotDispatched(string $event, callable|int $callback = null) * @method static void flush(string $event) * @method static void forget(string $event) * @method static void forgetPushed() * @method static void listen(string|array $events, \Closure|string $listener) * @method static void push(string $event, array $payload = []) * @method static void subscribe(object|string $subscriber) * * @see \Illuminate\Events\Dispatcher */ class Event extends Facade { /** * Replace the bound instance with a fake. * * @param array|string $eventsToFake * @return \Illuminate\Support\Testing\Fakes\EventFake */ public static function fake($eventsToFake = []) { static::swap($fake = new EventFake(static::getFacadeRoot(), $eventsToFake)); Model::setEventDispatcher($fake); Cache::refreshEventDispatcher(); return $fake; } /** * Replace the bound instance with a fake during the given callable's execution. * * @param callable $callable * @param array $eventsToFake * @return callable */ public static function fakeFor(callable $callable, array $eventsToFake = []) { $originalDispatcher = static::getFacadeRoot(); static::fake($eventsToFake); return tap($callable(), function () use ($originalDispatcher) { static::swap($originalDispatcher); Model::setEventDispatcher($originalDispatcher); Cache::refreshEventDispatcher(); }); } /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'events'; } } support/Facades/Route.php 0000644 00000006306 14736103231 0011422 0 ustar 00 <?php namespace Illuminate\Support\Facades; /** * @method static \Illuminate\Routing\PendingResourceRegistration apiResource(string $name, string $controller, array $options = []) * @method static \Illuminate\Routing\PendingResourceRegistration resource(string $name, string $controller, array $options = []) * @method static \Illuminate\Routing\Route any(string $uri, array|string|callable|null $action = null) * @method static \Illuminate\Routing\Route current() * @method static \Illuminate\Routing\Route delete(string $uri, array|string|callable|null $action = null) * @method static \Illuminate\Routing\Route fallback(array|string|callable|null $action = null) * @method static \Illuminate\Routing\Route get(string $uri, array|string|callable|null $action = null) * @method static \Illuminate\Routing\Route getCurrentRoute() * @method static \Illuminate\Routing\Route match(array|string $methods, string $uri, array|string|callable|null $action = null) * @method static \Illuminate\Routing\Route options(string $uri, array|string|callable|null $action = null) * @method static \Illuminate\Routing\Route patch(string $uri, array|string|callable|null $action = null) * @method static \Illuminate\Routing\Route permanentRedirect(string $uri, string $destination) * @method static \Illuminate\Routing\Route post(string $uri, array|string|callable|null $action = null) * @method static \Illuminate\Routing\Route put(string $uri, array|string|callable|null $action = null) * @method static \Illuminate\Routing\Route redirect(string $uri, string $destination, int $status = 302) * @method static \Illuminate\Routing\Route substituteBindings(\Illuminate\Support\Facades\Route $route) * @method static \Illuminate\Routing\Route view(string $uri, string $view, array $data = []) * @method static \Illuminate\Routing\RouteRegistrar as(string $value) * @method static \Illuminate\Routing\RouteRegistrar domain(string $value) * @method static \Illuminate\Routing\RouteRegistrar middleware(array|string|null $middleware) * @method static \Illuminate\Routing\RouteRegistrar name(string $value) * @method static \Illuminate\Routing\RouteRegistrar namespace(string $value) * @method static \Illuminate\Routing\RouteRegistrar prefix(string $prefix) * @method static \Illuminate\Routing\RouteRegistrar where(array $where) * @method static \Illuminate\Routing\Router|\Illuminate\Routing\RouteRegistrar group(\Closure|string|array $attributes, \Closure|string $routes) * @method static string|null currentRouteAction() * @method static string|null currentRouteName() * @method static void apiResources(array $resources, array $options = []) * @method static void bind(string $key, string|callable $binder) * @method static void model(string $key, string $class, \Closure|null $callback = null) * @method static void pattern(string $key, string $pattern) * @method static void resources(array $resources) * @method static void substituteImplicitBindings(\Illuminate\Support\Facades\Route $route) * * @see \Illuminate\Routing\Router */ class Route extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'router'; } } support/Facades/Response.php 0000644 00000004553 14736103231 0012124 0 ustar 00 <?php namespace Illuminate\Support\Facades; use Illuminate\Contracts\Routing\ResponseFactory as ResponseFactoryContract; /** * @method static \Illuminate\Http\JsonResponse json(string|array $data = [], int $status = 200, array $headers = [], int $options = 0) * @method static \Illuminate\Http\JsonResponse jsonp(string $callback, string|array $data = [], int $status = 200, array $headers = [], int $options = 0) * @method static \Illuminate\Http\RedirectResponse redirectGuest(string $path, int $status = 302, array $headers = [], bool|null $secure = null) * @method static \Illuminate\Http\RedirectResponse redirectTo(string $path, int $status = 302, array $headers = [], bool|null $secure = null) * @method static \Illuminate\Http\RedirectResponse redirectToAction(string $action, mixed $parameters = [], int $status = 302, array $headers = []) * @method static \Illuminate\Http\RedirectResponse redirectToIntended(string $default = '/', int $status = 302, array $headers = [], bool|null $secure = null) * @method static \Illuminate\Http\RedirectResponse redirectToRoute(string $route, mixed $parameters = [], int $status = 302, array $headers = []) * @method static \Illuminate\Http\Response make(string $content = '', int $status = 200, array $headers = []) * @method static \Illuminate\Http\Response noContent($status = 204, array $headers = []) * @method static \Illuminate\Http\Response view(string $view, array $data = [], int $status = 200, array $headers = []) * @method static \Symfony\Component\HttpFoundation\BinaryFileResponse download(\SplFileInfo|string $file, string|null $name = null, array $headers = [], string|null $disposition = 'attachment') * @method static \Symfony\Component\HttpFoundation\BinaryFileResponse file($file, array $headers = []) * @method static \Symfony\Component\HttpFoundation\StreamedResponse stream(\Closure $callback, int $status = 200, array $headers = []) * @method static \Symfony\Component\HttpFoundation\StreamedResponse streamDownload(\Closure $callback, string|null $name = null, array $headers = [], string|null $disposition = 'attachment') * * @see \Illuminate\Contracts\Routing\ResponseFactory */ class Response extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return ResponseFactoryContract::class; } } support/Facades/Date.php 0000644 00000012727 14736103231 0011205 0 ustar 00 <?php namespace Illuminate\Support\Facades; use Illuminate\Support\DateFactory; /** * @see https://carbon.nesbot.com/docs/ * @see https://github.com/briannesbitt/Carbon/blob/master/src/Carbon/Factory.php * * @method static \Illuminate\Support\Carbon create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $tz = null) * @method static \Illuminate\Support\Carbon createFromDate($year = null, $month = null, $day = null, $tz = null) * @method static \Illuminate\Support\Carbon createFromTime($hour = 0, $minute = 0, $second = 0, $tz = null) * @method static \Illuminate\Support\Carbon createFromTimeString($time, $tz = null) * @method static \Illuminate\Support\Carbon createFromTimestamp($timestamp, $tz = null) * @method static \Illuminate\Support\Carbon createFromTimestampMs($timestamp, $tz = null) * @method static \Illuminate\Support\Carbon createFromTimestampUTC($timestamp) * @method static \Illuminate\Support\Carbon createMidnightDate($year = null, $month = null, $day = null, $tz = null) * @method static \Illuminate\Support\Carbon disableHumanDiffOption($humanDiffOption) * @method static \Illuminate\Support\Carbon enableHumanDiffOption($humanDiffOption) * @method static \Illuminate\Support\Carbon fromSerialized($value) * @method static \Illuminate\Support\Carbon getLastErrors() * @method static \Illuminate\Support\Carbon getTestNow() * @method static \Illuminate\Support\Carbon instance($date) * @method static \Illuminate\Support\Carbon isMutable() * @method static \Illuminate\Support\Carbon maxValue() * @method static \Illuminate\Support\Carbon minValue() * @method static \Illuminate\Support\Carbon now($tz = null) * @method static \Illuminate\Support\Carbon parse($time = null, $tz = null) * @method static \Illuminate\Support\Carbon setHumanDiffOptions($humanDiffOptions) * @method static \Illuminate\Support\Carbon setTestNow($testNow = null) * @method static \Illuminate\Support\Carbon setUtf8($utf8) * @method static \Illuminate\Support\Carbon today($tz = null) * @method static \Illuminate\Support\Carbon tomorrow($tz = null) * @method static \Illuminate\Support\Carbon useStrictMode($strictModeEnabled = true) * @method static \Illuminate\Support\Carbon yesterday($tz = null) * @method static \Illuminate\Support\Carbon|false createFromFormat($format, $time, $tz = null) * @method static \Illuminate\Support\Carbon|false createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $tz = null) * @method static \Illuminate\Support\Carbon|null make($var) * @method static \Symfony\Component\Translation\TranslatorInterface getTranslator() * @method static array getAvailableLocales() * @method static array getDays() * @method static array getIsoUnits() * @method static array getWeekendDays() * @method static bool hasFormat($date, $format) * @method static bool hasMacro($name) * @method static bool hasRelativeKeywords($time) * @method static bool hasTestNow() * @method static bool isImmutable() * @method static bool isModifiableUnit($unit) * @method static bool isStrictModeEnabled() * @method static bool localeHasDiffOneDayWords($locale) * @method static bool localeHasDiffSyntax($locale) * @method static bool localeHasDiffTwoDayWords($locale) * @method static bool localeHasPeriodSyntax($locale) * @method static bool localeHasShortUnits($locale) * @method static bool setLocale($locale) * @method static bool shouldOverflowMonths() * @method static bool shouldOverflowYears() * @method static int getHumanDiffOptions() * @method static int getMidDayAt() * @method static int getWeekEndsAt() * @method static int getWeekStartsAt() * @method static mixed executeWithLocale($locale, $func) * @method static mixed use(mixed $handler) * @method static string getLocale() * @method static string pluralUnit(string $unit) * @method static string singularUnit(string $unit) * @method static void macro($name, $macro) * @method static void mixin($mixin) * @method static void resetMonthsOverflow() * @method static void resetToStringFormat() * @method static void resetYearsOverflow() * @method static void serializeUsing($callback) * @method static void setMidDayAt($hour) * @method static void setToStringFormat($format) * @method static void setTranslator(\Symfony\Component\Translation\TranslatorInterface $translator) * @method static void setWeekEndsAt($day) * @method static void setWeekStartsAt($day) * @method static void setWeekendDays($days) * @method static void useCallable(callable $callable) * @method static void useClass(string $class) * @method static void useDefault() * @method static void useFactory(object $factory) * @method static void useMonthsOverflow($monthsOverflow = true) * @method static void useYearsOverflow($yearsOverflow = true) */ class Date extends Facade { const DEFAULT_FACADE = DateFactory::class; /** * Get the registered name of the component. * * @return string * * @throws \RuntimeException */ protected static function getFacadeAccessor() { return 'date'; } /** * Resolve the facade root instance from the container. * * @param string $name * @return mixed */ protected static function resolveFacadeInstance($name) { if (! isset(static::$resolvedInstance[$name]) && ! isset(static::$app, static::$app[$name])) { $class = static::DEFAULT_FACADE; static::swap(new $class); } return parent::resolveFacadeInstance($name); } } support/Facades/Bus.php 0000644 00000003433 14736103231 0011053 0 ustar 00 <?php namespace Illuminate\Support\Facades; use Illuminate\Contracts\Bus\Dispatcher as BusDispatcherContract; use Illuminate\Foundation\Bus\PendingChain; use Illuminate\Support\Testing\Fakes\BusFake; /** * @method static \Illuminate\Contracts\Bus\Dispatcher map(array $map) * @method static \Illuminate\Contracts\Bus\Dispatcher pipeThrough(array $pipes) * @method static bool hasCommandHandler($command) * @method static bool|mixed getCommandHandler($command) * @method static mixed dispatch($command) * @method static mixed dispatchNow($command, $handler = null) * @method static void assertDispatched(string $command, callable|int $callback = null) * @method static void assertDispatchedTimes(string $command, int $times = 1) * @method static void assertNotDispatched(string $command, callable|int $callback = null) * * @see \Illuminate\Contracts\Bus\Dispatcher */ class Bus extends Facade { /** * Replace the bound instance with a fake. * * @param array|string $jobsToFake * @return \Illuminate\Support\Testing\Fakes\BusFake */ public static function fake($jobsToFake = []) { static::swap($fake = new BusFake(static::getFacadeRoot(), $jobsToFake)); return $fake; } /** * Dispatch the given chain of jobs. * * @param array|mixed $jobs * @return \Illuminate\Foundation\Bus\PendingDispatch */ public static function dispatchChain($jobs) { $jobs = is_array($jobs) ? $jobs : func_get_args(); return (new PendingChain(array_shift($jobs), $jobs)) ->dispatch(); } /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return BusDispatcherContract::class; } } support/Facades/View.php 0000644 00000001754 14736103231 0011240 0 ustar 00 <?php namespace Illuminate\Support\Facades; /** * @method static \Illuminate\Contracts\View\Factory addNamespace(string $namespace, string|array $hints) * @method static \Illuminate\Contracts\View\Factory replaceNamespace(string $namespace, string|array $hints) * @method static \Illuminate\Contracts\View\View file(string $path, array $data = [], array $mergeData = []) * @method static \Illuminate\Contracts\View\View make(string $view, array $data = [], array $mergeData = []) * @method static array composer(array|string $views, \Closure|string $callback) * @method static array creator(array|string $views, \Closure|string $callback) * @method static bool exists(string $view) * @method static mixed share(array|string $key, $value = null) * * @see \Illuminate\View\Factory */ class View extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'view'; } } support/Facades/Input.php 0000644 00000001232 14736103231 0011414 0 ustar 00 <?php namespace Illuminate\Support\Facades; /** * @see \Illuminate\Http\Request */ class Input extends Facade { /** * Get an item from the input data. * * This method is used for all request verbs (GET, POST, PUT, and DELETE) * * @param string $key * @param mixed $default * @return mixed */ public static function get($key = null, $default = null) { return static::$app['request']->input($key, $default); } /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'request'; } } support/Facades/Storage.php 0000644 00000006341 14736103231 0011727 0 ustar 00 <?php namespace Illuminate\Support\Facades; use Illuminate\Filesystem\Filesystem; /** * @method static \Illuminate\Contracts\Filesystem\Filesystem assertExists(string|array $path) * @method static \Illuminate\Contracts\Filesystem\Filesystem assertMissing(string|array $path) * @method static \Illuminate\Contracts\Filesystem\Filesystem cloud() * @method static \Illuminate\Contracts\Filesystem\Filesystem disk(string $name = null) * @method static array allDirectories(string|null $directory = null) * @method static array allFiles(string|null $directory = null) * @method static array directories(string|null $directory = null, bool $recursive = false) * @method static array files(string|null $directory = null, bool $recursive = false) * @method static bool append(string $path, string $data) * @method static bool copy(string $from, string $to) * @method static bool delete(string|array $paths) * @method static bool deleteDirectory(string $directory) * @method static bool exists(string $path) * @method static bool makeDirectory(string $path) * @method static bool move(string $from, string $to) * @method static bool prepend(string $path, string $data) * @method static bool put(string $path, string|resource $contents, mixed $options = []) * @method static bool setVisibility(string $path, string $visibility) * @method static bool writeStream(string $path, resource $resource, array $options = []) * @method static int lastModified(string $path) * @method static int size(string $path) * @method static resource|null readStream(string $path) * @method static string get(string $path) * @method static string getVisibility(string $path) * @method static string temporaryUrl(string $path, \DateTimeInterface $expiration, array $options = []) * @method static string url(string $path) * * @see \Illuminate\Filesystem\FilesystemManager */ class Storage extends Facade { /** * Replace the given disk with a local testing disk. * * @param string|null $disk * @param array $config * @return \Illuminate\Contracts\Filesystem\Filesystem */ public static function fake($disk = null, array $config = []) { $disk = $disk ?: static::$app['config']->get('filesystems.default'); (new Filesystem)->cleanDirectory( $root = storage_path('framework/testing/disks/'.$disk) ); static::set($disk, $fake = static::createLocalDriver(array_merge($config, [ 'root' => $root, ]))); return $fake; } /** * Replace the given disk with a persistent local testing disk. * * @param string|null $disk * @param array $config * @return \Illuminate\Contracts\Filesystem\Filesystem */ public static function persistentFake($disk = null, array $config = []) { $disk = $disk ?: static::$app['config']->get('filesystems.default'); static::set($disk, $fake = static::createLocalDriver(array_merge($config, [ 'root' => storage_path('framework/testing/disks/'.$disk), ]))); return $fake; } /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'filesystem'; } } support/Facades/Cache.php 0000644 00000003042 14736103231 0011321 0 ustar 00 <?php namespace Illuminate\Support\Facades; /** * @method static \Illuminate\Contracts\Cache\Lock lock(string $name, int $seconds = 0, mixed $owner = null) * @method static \Illuminate\Contracts\Cache\Lock restoreLock(string $name, string $owner) * @method static \Illuminate\Contracts\Cache\Repository store(string|null $name = null) * @method static \Illuminate\Contracts\Cache\Store getStore() * @method static bool add(string $key, $value, \DateTimeInterface|\DateInterval|int $ttl = null) * @method static bool forever(string $key, $value) * @method static bool forget(string $key) * @method static bool has(string $key) * @method static bool missing(string $key) * @method static bool put(string $key, $value, \DateTimeInterface|\DateInterval|int $ttl = null) * @method static int|bool decrement(string $key, $value = 1) * @method static int|bool increment(string $key, $value = 1) * @method static mixed get(string $key, mixed $default = null) * @method static mixed pull(string $key, mixed $default = null) * @method static mixed remember(string $key, \DateTimeInterface|\DateInterval|int $ttl, \Closure $callback) * @method static mixed rememberForever(string $key, \Closure $callback) * @method static mixed sear(string $key, \Closure $callback) * * @see \Illuminate\Cache\CacheManager * @see \Illuminate\Cache\Repository */ class Cache extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'cache'; } } support/Facades/Crypt.php 0000644 00000001316 14736103231 0011421 0 ustar 00 <?php namespace Illuminate\Support\Facades; /** * @method static bool supported(string $key, string $cipher) * @method static mixed decrypt(string $payload, bool $unserialize = true) * @method static string decryptString(string $payload) * @method static string encrypt(mixed $value, bool $serialize = true) * @method static string encryptString(string $value) * @method static string generateKey(string $cipher) * @method static string getKey() * * @see \Illuminate\Encryption\Encrypter */ class Crypt extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'encrypter'; } } support/Facades/Request.php 0000644 00000011723 14736103231 0011753 0 ustar 00 <?php namespace Illuminate\Support\Facades; /** * @method static \Closure getRouteResolver() * @method static \Closure getUserResolver() * @method static \Illuminate\Http\Request capture() * @method static \Illuminate\Http\Request createFrom(\Illuminate\Http\Request $from, \Illuminate\Http\Request|null $to = null) * @method static \Illuminate\Http\Request createFromBase(\Symfony\Component\HttpFoundation\Request $request) * @method static \Illuminate\Http\Request duplicate(array|null $query = null, array|null $request = null, array|null $attributes = null, array|null $cookies = null, array|null $files = null, array|null $server = null) * @method static \Illuminate\Http\Request instance() * @method static \Illuminate\Http\Request merge(array $input) * @method static \Illuminate\Http\Request replace(array $input) * @method static \Illuminate\Http\Request setJson(\Symfony\Component\HttpFoundation\ParameterBag $json) * @method static \Illuminate\Http\Request setRouteResolver(\Closure $callback) * @method static \Illuminate\Http\Request setUserResolver(\Closure $callback) * @method static \Illuminate\Http\UploadedFile|\Illuminate\Http\UploadedFile[]|array|null file(string|null $key = null, mixed $default = null) * @method static \Illuminate\Routing\Route|object|string route(string|null $param = null, string|null $default = null) * @method static \Illuminate\Session\Store session() * @method static \Illuminate\Session\Store|null getSession() * @method static \Symfony\Component\HttpFoundation\ParameterBag|mixed json(string|null $key = null, mixed $default = null) * @method static array all(array|mixed|null $keys = null) * @method static array allFiles() * @method static array except(array|mixed $keys) * @method static array ips() * @method static array keys() * @method static array only(array|mixed $keys) * @method static array segments() * @method static array toArray() * @method static bool accepts(string|array $contentTypes) * @method static bool acceptsAnyContentType() * @method static bool acceptsHtml() * @method static bool acceptsJson() * @method static bool ajax() * @method static bool anyFilled(string|array $key) * @method static bool exists(string|array $key) * @method static bool expectsJson() * @method static bool filled(string|array $key) * @method static bool fullUrlIs(mixed ...$patterns) * @method static bool has(string|array $key) * @method static bool hasAny(string|array $key) * @method static bool hasCookie(string $key) * @method static bool hasFile(string $key) * @method static bool hasHeader(string $key) * @method static bool is(mixed ...$patterns) * @method static bool isJson() * @method static bool matchesType(string $actual, string $type) * @method static bool offsetExists(string $offset) * @method static bool pjax() * @method static bool prefers(string|array $contentTypes) * @method static bool prefetch() * @method static bool routeIs(mixed ...$patterns) * @method static bool secure() * @method static bool wantsJson() * @method static mixed filterFiles(mixed $files) * @method static mixed offsetGet(string $offset) * @method static mixed user(string|null $guard = null) * @method static string decodedPath() * @method static string fingerprint() * @method static string format($default = 'html') * @method static string fullUrl() * @method static string fullUrlWithQuery(array $query) * @method static string method() * @method static string path() * @method static string root() * @method static string url() * @method static string userAgent() * @method static string|array old(string|null $key = null, string|array|null $default = null) * @method static string|array|null cookie(string|null $key = null, string|array|null $default = null) * @method static string|array|null header(string|null $key = null, string|array|null $default = null) * @method static string|array|null input(string|null $key = null, string|array|null $default = null) * @method static string|array|null post(string|null $key = null, string|array|null $default = null) * @method static string|array|null query(string|null $key = null, string|array|null $default = null) * @method static string|array|null server(string|null $key = null, string|array|null $default = null) * @method static string|null bearerToken() * @method static string|null ip() * @method static string|null segment(int $index, string|null $default = null) * @method static void flash() * @method static void flashExcept(array|mixed $keys) * @method static void flashOnly(array|mixed $keys) * @method static void flush() * @method static void offsetSet(string $offset, mixed $value) * @method static void offsetUnset(string $offset) * @method static void setLaravelSession(\Illuminate\Contracts\Session\Session $session) * * @see \Illuminate\Http\Request */ class Request extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'request'; } } support/Facades/Config.php 0000644 00000001055 14736103231 0011525 0 ustar 00 <?php namespace Illuminate\Support\Facades; /** * @method static array all() * @method static bool has($key) * @method static mixed get($key, $default = null) * @method static void prepend($key, $value) * @method static void push($key, $value) * @method static void set($key, $value = null) * * @see \Illuminate\Config\Repository */ class Config extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'config'; } } support/Facades/Gate.php 0000644 00000003261 14736103231 0011201 0 ustar 00 <?php namespace Illuminate\Support\Facades; use Illuminate\Contracts\Auth\Access\Gate as GateContract; /** * @method static \Illuminate\Auth\Access\Gate guessPolicyNamesUsing(callable $callback) * @method static \Illuminate\Auth\Access\Response authorize(string $ability, array|mixed $arguments = []) * @method static \Illuminate\Auth\Access\Response inspect(string $ability, array|mixed $arguments = []) * @method static \Illuminate\Contracts\Auth\Access\Gate after(callable $callback) * @method static \Illuminate\Contracts\Auth\Access\Gate before(callable $callback) * @method static \Illuminate\Contracts\Auth\Access\Gate define(string $ability, callable|string $callback) * @method static \Illuminate\Contracts\Auth\Access\Gate forUser(\Illuminate\Contracts\Auth\Authenticatable|mixed $user) * @method static \Illuminate\Contracts\Auth\Access\Gate policy(string $class, string $policy) * @method static array abilities() * @method static bool allows(string $ability, array|mixed $arguments = []) * @method static bool any(iterable|string $abilities, array|mixed $arguments = []) * @method static bool check(iterable|string $abilities, array|mixed $arguments = []) * @method static bool denies(string $ability, array|mixed $arguments = []) * @method static bool has(string $ability) * @method static mixed getPolicyFor(object|string $class) * @method static mixed raw(string $ability, array|mixed $arguments = []) * * @see \Illuminate\Contracts\Auth\Access\Gate */ class Gate extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return GateContract::class; } } support/Facades/Log.php 0000644 00000002066 14736103231 0011044 0 ustar 00 <?php namespace Illuminate\Support\Facades; /** * @method static \Psr\Log\LoggerInterface channel(string $channel = null) * @method static \Psr\Log\LoggerInterface stack(array $channels, string $channel = null) * @method static void alert(string $message, array $context = []) * @method static void critical(string $message, array $context = []) * @method static void debug(string $message, array $context = []) * @method static void emergency(string $message, array $context = []) * @method static void error(string $message, array $context = []) * @method static void info(string $message, array $context = []) * @method static void log($level, string $message, array $context = []) * @method static void notice(string $message, array $context = []) * @method static void warning(string $message, array $context = []) * * @see \Illuminate\Log\Logger */ class Log extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'log'; } } support/Facades/Facade.php 0000644 00000013734 14736103231 0011472 0 ustar 00 <?php namespace Illuminate\Support\Facades; use Closure; use Mockery; use Mockery\MockInterface; use RuntimeException; abstract class Facade { /** * The application instance being facaded. * * @var \Illuminate\Contracts\Foundation\Application */ protected static $app; /** * The resolved object instances. * * @var array */ protected static $resolvedInstance; /** * Run a Closure when the facade has been resolved. * * @param \Closure $callback * @return void */ public static function resolved(Closure $callback) { $accessor = static::getFacadeAccessor(); if (static::$app->resolved($accessor) === true) { $callback(static::getFacadeRoot()); } static::$app->afterResolving($accessor, function ($service) use ($callback) { $callback($service); }); } /** * Convert the facade into a Mockery spy. * * @return \Mockery\MockInterface */ public static function spy() { if (! static::isMock()) { $class = static::getMockableClass(); return tap($class ? Mockery::spy($class) : Mockery::spy(), function ($spy) { static::swap($spy); }); } } /** * Initiate a partial mock on the facade. * * @return \Mockery\MockInterface */ public static function partialMock() { $name = static::getFacadeAccessor(); $mock = static::isMock() ? static::$resolvedInstance[$name] : static::createFreshMockInstance(); return $mock->makePartial(); } /** * Initiate a mock expectation on the facade. * * @return \Mockery\Expectation */ public static function shouldReceive() { $name = static::getFacadeAccessor(); $mock = static::isMock() ? static::$resolvedInstance[$name] : static::createFreshMockInstance(); return $mock->shouldReceive(...func_get_args()); } /** * Create a fresh mock instance for the given class. * * @return \Mockery\MockInterface */ protected static function createFreshMockInstance() { return tap(static::createMock(), function ($mock) { static::swap($mock); $mock->shouldAllowMockingProtectedMethods(); }); } /** * Create a fresh mock instance for the given class. * * @return \Mockery\MockInterface */ protected static function createMock() { $class = static::getMockableClass(); return $class ? Mockery::mock($class) : Mockery::mock(); } /** * Determines whether a mock is set as the instance of the facade. * * @return bool */ protected static function isMock() { $name = static::getFacadeAccessor(); return isset(static::$resolvedInstance[$name]) && static::$resolvedInstance[$name] instanceof MockInterface; } /** * Get the mockable class for the bound instance. * * @return string|null */ protected static function getMockableClass() { if ($root = static::getFacadeRoot()) { return get_class($root); } } /** * Hotswap the underlying instance behind the facade. * * @param mixed $instance * @return void */ public static function swap($instance) { static::$resolvedInstance[static::getFacadeAccessor()] = $instance; if (isset(static::$app)) { static::$app->instance(static::getFacadeAccessor(), $instance); } } /** * Get the root object behind the facade. * * @return mixed */ public static function getFacadeRoot() { return static::resolveFacadeInstance(static::getFacadeAccessor()); } /** * Get the registered name of the component. * * @return string * * @throws \RuntimeException */ protected static function getFacadeAccessor() { throw new RuntimeException('Facade does not implement getFacadeAccessor method.'); } /** * Resolve the facade root instance from the container. * * @param object|string $name * @return mixed */ protected static function resolveFacadeInstance($name) { if (is_object($name)) { return $name; } if (isset(static::$resolvedInstance[$name])) { return static::$resolvedInstance[$name]; } if (static::$app) { return static::$resolvedInstance[$name] = static::$app[$name]; } } /** * Clear a resolved facade instance. * * @param string $name * @return void */ public static function clearResolvedInstance($name) { unset(static::$resolvedInstance[$name]); } /** * Clear all of the resolved instances. * * @return void */ public static function clearResolvedInstances() { static::$resolvedInstance = []; } /** * Get the application instance behind the facade. * * @return \Illuminate\Contracts\Foundation\Application */ public static function getFacadeApplication() { return static::$app; } /** * Set the application instance. * * @param \Illuminate\Contracts\Foundation\Application $app * @return void */ public static function setFacadeApplication($app) { static::$app = $app; } /** * Handle dynamic, static calls to the object. * * @param string $method * @param array $args * @return mixed * * @throws \RuntimeException */ public static function __callStatic($method, $args) { $instance = static::getFacadeRoot(); if (! $instance) { throw new RuntimeException('A facade root has not been set.'); } return $instance->$method(...$args); } } support/Facades/App.php 0000644 00000004534 14736103231 0011045 0 ustar 00 <?php namespace Illuminate\Support\Facades; /** * @method static \Illuminate\Contracts\Foundation\Application loadEnvironmentFrom(string $file) * @method static \Illuminate\Support\ServiceProvider register(\Illuminate\Support\ServiceProvider|string $provider, bool $force = false) * @method static \Illuminate\Support\ServiceProvider resolveProvider(string $provider) * @method static array getProviders(\Illuminate\Support\ServiceProvider|string $provider) * @method static bool configurationIsCached() * @method static bool hasBeenBootstrapped() * @method static bool isDownForMaintenance() * @method static bool routesAreCached() * @method static bool runningInConsole() * @method static bool runningUnitTests() * @method static bool shouldSkipMiddleware() * @method static string basePath() * @method static string bootstrapPath(string $path = '') * @method static string configPath(string $path = '') * @method static string databasePath(string $path = '') * @method static string detectEnvironment(callable $callback) * @method static string environmentFile() * @method static string environmentFilePath() * @method static string environmentPath() * @method static string getCachedConfigPath() * @method static string getCachedPackagesPath() * @method static string getCachedRoutesPath() * @method static string getCachedServicesPath() * @method static string getLocale() * @method static string getNamespace() * @method static string resourcePath(string $path = '') * @method static string storagePath(string $path = '') * @method static string version() * @method static string|bool environment(string|array ...$environments) * @method static void boot() * @method static void booted(callable $callback) * @method static void booting(callable $callback) * @method static void bootstrapWith(array $bootstrappers) * @method static void loadDeferredProviders() * @method static void registerConfiguredProviders() * @method static void registerDeferredProvider(string $provider, string $service = null) * @method static void setLocale(string $locale) * @method static void terminate() * * @see \Illuminate\Contracts\Foundation\Application */ class App extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'app'; } } support/Facades/File.php 0000644 00000005152 14736103231 0011201 0 ustar 00 <?php namespace Illuminate\Support\Facades; /** * @method static \Symfony\Component\Finder\SplFileInfo[] allFiles(string $directory, bool $hidden = false) * @method static \Symfony\Component\Finder\SplFileInfo[] files(string $directory, bool $hidden = false) * @method static array directories(string $directory) * @method static array glob(string $pattern, int $flags = 0) * @method static bool cleanDirectory(string $directory) * @method static bool copy(string $path, string $target) * @method static bool copyDirectory(string $directory, string $destination, int|null $options = null) * @method static bool delete(string|array $paths) * @method static bool deleteDirectories(string $directory) * @method static bool deleteDirectory(string $directory, bool $preserve = false) * @method static bool exists(string $path) * @method static bool isDirectory(string $directory) * @method static bool isFile(string $file) * @method static bool isReadable(string $path) * @method static bool isWritable(string $path) * @method static bool makeDirectory(string $path, int $mode = 0755, bool $recursive = false, bool $force = false) * @method static bool move(string $path, string $target) * @method static bool moveDirectory(string $from, string $to, bool $overwrite = false) * @method static int append(string $path, string $data) * @method static int lastModified(string $path) * @method static int prepend(string $path, string $data) * @method static int size(string $path) * @method static int|bool put(string $path, string $contents, bool $lock = false) * @method static mixed chmod(string $path, int|null $mode = null) * @method static mixed getRequire(string $path) * @method static mixed requireOnce(string $file) * @method static string basename(string $path) * @method static string dirname(string $path) * @method static string extension(string $path) * @method static string get(string $path, bool $lock = false) * @method static string hash(string $path) * @method static string name(string $path) * @method static string sharedGet(string $path) * @method static string type(string $path) * @method static string|false mimeType(string $path) * @method static void ensureDirectoryExists(string $path, int $mode = 0755, bool $recursive = true) * @method static void link(string $target, string $link) * @method static void replace(string $path, string $content) * * @see \Illuminate\Filesystem\Filesystem */ class File extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'files'; } } support/LICENSE.md 0000644 00000002063 14736103231 0007665 0 ustar 00 The MIT License (MIT) Copyright (c) Taylor Otwell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. support/Manager.php 0000644 00000007754 14736103231 0010360 0 ustar 00 <?php namespace Illuminate\Support; use Closure; use Illuminate\Contracts\Container\Container; use InvalidArgumentException; abstract class Manager { /** * The container instance. * * @var \Illuminate\Contracts\Container\Container */ protected $container; /** * The container instance. * * @var \Illuminate\Contracts\Container\Container * * @deprecated Use the $container property instead. */ protected $app; /** * The configuration repository instance. * * @var \Illuminate\Contracts\Config\Repository */ protected $config; /** * The registered custom driver creators. * * @var array */ protected $customCreators = []; /** * The array of created "drivers". * * @var array */ protected $drivers = []; /** * Create a new manager instance. * * @param \Illuminate\Contracts\Container\Container $container * @return void */ public function __construct(Container $container) { $this->app = $container; $this->container = $container; $this->config = $container->make('config'); } /** * Get the default driver name. * * @return string */ abstract public function getDefaultDriver(); /** * Get a driver instance. * * @param string|null $driver * @return mixed * * @throws \InvalidArgumentException */ public function driver($driver = null) { $driver = $driver ?: $this->getDefaultDriver(); if (is_null($driver)) { throw new InvalidArgumentException(sprintf( 'Unable to resolve NULL driver for [%s].', static::class )); } // If the given driver has not been created before, we will create the instances // here and cache it so we can return it next time very quickly. If there is // already a driver created by this name, we'll just return that instance. if (! isset($this->drivers[$driver])) { $this->drivers[$driver] = $this->createDriver($driver); } return $this->drivers[$driver]; } /** * Create a new driver instance. * * @param string $driver * @return mixed * * @throws \InvalidArgumentException */ protected function createDriver($driver) { // First, we will determine if a custom driver creator exists for the given driver and // if it does not we will check for a creator method for the driver. Custom creator // callbacks allow developers to build their own "drivers" easily using Closures. if (isset($this->customCreators[$driver])) { return $this->callCustomCreator($driver); } else { $method = 'create'.Str::studly($driver).'Driver'; if (method_exists($this, $method)) { return $this->$method(); } } throw new InvalidArgumentException("Driver [$driver] not supported."); } /** * Call a custom driver creator. * * @param string $driver * @return mixed */ protected function callCustomCreator($driver) { return $this->customCreators[$driver]($this->container); } /** * Register a custom driver creator Closure. * * @param string $driver * @param \Closure $callback * @return $this */ public function extend($driver, Closure $callback) { $this->customCreators[$driver] = $callback; return $this; } /** * Get all of the created "drivers". * * @return array */ public function getDrivers() { return $this->drivers; } /** * Dynamically call the default driver instance. * * @param string $method * @param array $parameters * @return mixed */ public function __call($method, $parameters) { return $this->driver()->$method(...$parameters); } } support/Traits/Localizable.php 0000644 00000001165 14736103231 0012463 0 ustar 00 <?php namespace Illuminate\Support\Traits; use Illuminate\Container\Container; trait Localizable { /** * Run the callback with the given locale. * * @param string $locale * @param \Closure $callback * @return mixed */ public function withLocale($locale, $callback) { if (! $locale) { return $callback(); } $app = Container::getInstance(); $original = $app->getLocale(); try { $app->setLocale($locale); return $callback(); } finally { $app->setLocale($original); } } } support/Traits/Tappable.php 0000644 00000000473 14736103231 0011773 0 ustar 00 <?php namespace Illuminate\Support\Traits; trait Tappable { /** * Call the given Closure with this instance then return the instance. * * @param callable|null $callback * @return mixed */ public function tap($callback = null) { return tap($this, $callback); } } support/Traits/ForwardsCalls.php 0000644 00000002531 14736103231 0013006 0 ustar 00 <?php namespace Illuminate\Support\Traits; use BadMethodCallException; use Error; trait ForwardsCalls { /** * Forward a method call to the given object. * * @param mixed $object * @param string $method * @param array $parameters * @return mixed * * @throws \BadMethodCallException */ protected function forwardCallTo($object, $method, $parameters) { try { return $object->{$method}(...$parameters); } catch (Error | BadMethodCallException $e) { $pattern = '~^Call to undefined method (?P<class>[^:]+)::(?P<method>[^\(]+)\(\)$~'; if (! preg_match($pattern, $e->getMessage(), $matches)) { throw $e; } if ($matches['class'] != get_class($object) || $matches['method'] != $method) { throw $e; } static::throwBadMethodCallException($method); } } /** * Throw a bad method call exception for the given method. * * @param string $method * @return void * * @throws \BadMethodCallException */ protected static function throwBadMethodCallException($method) { throw new BadMethodCallException(sprintf( 'Call to undefined method %s::%s()', static::class, $method )); } } support/Traits/Macroable.php 0000644 00000005313 14736103231 0012126 0 ustar 00 <?php namespace Illuminate\Support\Traits; use BadMethodCallException; use Closure; use ReflectionClass; use ReflectionMethod; trait Macroable { /** * The registered string macros. * * @var array */ protected static $macros = []; /** * Register a custom macro. * * @param string $name * @param object|callable $macro * @return void */ public static function macro($name, $macro) { static::$macros[$name] = $macro; } /** * Mix another object into the class. * * @param object $mixin * @param bool $replace * @return void * * @throws \ReflectionException */ public static function mixin($mixin, $replace = true) { $methods = (new ReflectionClass($mixin))->getMethods( ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED ); foreach ($methods as $method) { if ($replace || ! static::hasMacro($method->name)) { $method->setAccessible(true); static::macro($method->name, $method->invoke($mixin)); } } } /** * Checks if macro is registered. * * @param string $name * @return bool */ public static function hasMacro($name) { return isset(static::$macros[$name]); } /** * Dynamically handle calls to the class. * * @param string $method * @param array $parameters * @return mixed * * @throws \BadMethodCallException */ public static function __callStatic($method, $parameters) { if (! static::hasMacro($method)) { throw new BadMethodCallException(sprintf( 'Method %s::%s does not exist.', static::class, $method )); } $macro = static::$macros[$method]; if ($macro instanceof Closure) { return call_user_func_array(Closure::bind($macro, null, static::class), $parameters); } return $macro(...$parameters); } /** * Dynamically handle calls to the class. * * @param string $method * @param array $parameters * @return mixed * * @throws \BadMethodCallException */ public function __call($method, $parameters) { if (! static::hasMacro($method)) { throw new BadMethodCallException(sprintf( 'Method %s::%s does not exist.', static::class, $method )); } $macro = static::$macros[$method]; if ($macro instanceof Closure) { return call_user_func_array($macro->bindTo($this, static::class), $parameters); } return $macro(...$parameters); } } support/Traits/EnumeratesValues.php 0000644 00000061137 14736103231 0013537 0 ustar 00 <?php namespace Illuminate\Support\Traits; use CachingIterator; use Closure; use Exception; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Contracts\Support\Jsonable; use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\Enumerable; use Illuminate\Support\HigherOrderCollectionProxy; use Illuminate\Support\HigherOrderWhenProxy; use JsonSerializable; use Symfony\Component\VarDumper\VarDumper; use Traversable; /** * @property-read HigherOrderCollectionProxy $average * @property-read HigherOrderCollectionProxy $avg * @property-read HigherOrderCollectionProxy $contains * @property-read HigherOrderCollectionProxy $each * @property-read HigherOrderCollectionProxy $every * @property-read HigherOrderCollectionProxy $filter * @property-read HigherOrderCollectionProxy $first * @property-read HigherOrderCollectionProxy $flatMap * @property-read HigherOrderCollectionProxy $groupBy * @property-read HigherOrderCollectionProxy $keyBy * @property-read HigherOrderCollectionProxy $map * @property-read HigherOrderCollectionProxy $max * @property-read HigherOrderCollectionProxy $min * @property-read HigherOrderCollectionProxy $partition * @property-read HigherOrderCollectionProxy $reject * @property-read HigherOrderCollectionProxy $some * @property-read HigherOrderCollectionProxy $sortBy * @property-read HigherOrderCollectionProxy $sortByDesc * @property-read HigherOrderCollectionProxy $sum * @property-read HigherOrderCollectionProxy $unique * @property-read HigherOrderCollectionProxy $until */ trait EnumeratesValues { /** * The methods that can be proxied. * * @var array */ protected static $proxies = [ 'average', 'avg', 'contains', 'each', 'every', 'filter', 'first', 'flatMap', 'groupBy', 'keyBy', 'map', 'max', 'min', 'partition', 'reject', 'skipUntil', 'skipWhile', 'some', 'sortBy', 'sortByDesc', 'sum', 'takeUntil', 'takeWhile', 'unique', 'until', ]; /** * Create a new collection instance if the value isn't one already. * * @param mixed $items * @return static */ public static function make($items = []) { return new static($items); } /** * Wrap the given value in a collection if applicable. * * @param mixed $value * @return static */ public static function wrap($value) { return $value instanceof Enumerable ? new static($value) : new static(Arr::wrap($value)); } /** * Get the underlying items from the given collection if applicable. * * @param array|static $value * @return array */ public static function unwrap($value) { return $value instanceof Enumerable ? $value->all() : $value; } /** * Alias for the "avg" method. * * @param callable|string|null $callback * @return mixed */ public function average($callback = null) { return $this->avg($callback); } /** * Alias for the "contains" method. * * @param mixed $key * @param mixed $operator * @param mixed $value * @return bool */ public function some($key, $operator = null, $value = null) { return $this->contains(...func_get_args()); } /** * Determine if an item exists, using strict comparison. * * @param mixed $key * @param mixed $value * @return bool */ public function containsStrict($key, $value = null) { if (func_num_args() === 2) { return $this->contains(function ($item) use ($key, $value) { return data_get($item, $key) === $value; }); } if ($this->useAsCallable($key)) { return ! is_null($this->first($key)); } foreach ($this as $item) { if ($item === $key) { return true; } } return false; } /** * Dump the items and end the script. * * @param mixed ...$args * @return void */ public function dd(...$args) { call_user_func_array([$this, 'dump'], $args); die(1); } /** * Dump the items. * * @return $this */ public function dump() { (new static(func_get_args())) ->push($this) ->each(function ($item) { VarDumper::dump($item); }); return $this; } /** * Execute a callback over each item. * * @param callable $callback * @return $this */ public function each(callable $callback) { foreach ($this as $key => $item) { if ($callback($item, $key) === false) { break; } } return $this; } /** * Execute a callback over each nested chunk of items. * * @param callable $callback * @return static */ public function eachSpread(callable $callback) { return $this->each(function ($chunk, $key) use ($callback) { $chunk[] = $key; return $callback(...$chunk); }); } /** * Determine if all items pass the given truth test. * * @param string|callable $key * @param mixed $operator * @param mixed $value * @return bool */ public function every($key, $operator = null, $value = null) { if (func_num_args() === 1) { $callback = $this->valueRetriever($key); foreach ($this as $k => $v) { if (! $callback($v, $k)) { return false; } } return true; } return $this->every($this->operatorForWhere(...func_get_args())); } /** * Get the first item by the given key value pair. * * @param string $key * @param mixed $operator * @param mixed $value * @return mixed */ public function firstWhere($key, $operator = null, $value = null) { return $this->first($this->operatorForWhere(...func_get_args())); } /** * Determine if the collection is not empty. * * @return bool */ public function isNotEmpty() { return ! $this->isEmpty(); } /** * Run a map over each nested chunk of items. * * @param callable $callback * @return static */ public function mapSpread(callable $callback) { return $this->map(function ($chunk, $key) use ($callback) { $chunk[] = $key; return $callback(...$chunk); }); } /** * Run a grouping map over the items. * * The callback should return an associative array with a single key/value pair. * * @param callable $callback * @return static */ public function mapToGroups(callable $callback) { $groups = $this->mapToDictionary($callback); return $groups->map([$this, 'make']); } /** * Map a collection and flatten the result by a single level. * * @param callable $callback * @return static */ public function flatMap(callable $callback) { return $this->map($callback)->collapse(); } /** * Map the values into a new class. * * @param string $class * @return static */ public function mapInto($class) { return $this->map(function ($value, $key) use ($class) { return new $class($value, $key); }); } /** * Get the min value of a given key. * * @param callable|string|null $callback * @return mixed */ public function min($callback = null) { $callback = $this->valueRetriever($callback); return $this->map(function ($value) use ($callback) { return $callback($value); })->filter(function ($value) { return ! is_null($value); })->reduce(function ($result, $value) { return is_null($result) || $value < $result ? $value : $result; }); } /** * Get the max value of a given key. * * @param callable|string|null $callback * @return mixed */ public function max($callback = null) { $callback = $this->valueRetriever($callback); return $this->filter(function ($value) { return ! is_null($value); })->reduce(function ($result, $item) use ($callback) { $value = $callback($item); return is_null($result) || $value > $result ? $value : $result; }); } /** * "Paginate" the collection by slicing it into a smaller collection. * * @param int $page * @param int $perPage * @return static */ public function forPage($page, $perPage) { $offset = max(0, ($page - 1) * $perPage); return $this->slice($offset, $perPage); } /** * Partition the collection into two arrays using the given callback or key. * * @param callable|string $key * @param mixed $operator * @param mixed $value * @return static */ public function partition($key, $operator = null, $value = null) { $passed = []; $failed = []; $callback = func_num_args() === 1 ? $this->valueRetriever($key) : $this->operatorForWhere(...func_get_args()); foreach ($this as $key => $item) { if ($callback($item, $key)) { $passed[$key] = $item; } else { $failed[$key] = $item; } } return new static([new static($passed), new static($failed)]); } /** * Get the sum of the given values. * * @param callable|string|null $callback * @return mixed */ public function sum($callback = null) { if (is_null($callback)) { $callback = function ($value) { return $value; }; } else { $callback = $this->valueRetriever($callback); } return $this->reduce(function ($result, $item) use ($callback) { return $result + $callback($item); }, 0); } /** * Apply the callback if the value is truthy. * * @param bool|mixed $value * @param callable|null $callback * @param callable|null $default * @return static|mixed */ public function when($value, callable $callback = null, callable $default = null) { if (! $callback) { return new HigherOrderWhenProxy($this, $value); } if ($value) { return $callback($this, $value); } elseif ($default) { return $default($this, $value); } return $this; } /** * Apply the callback if the collection is empty. * * @param callable $callback * @param callable|null $default * @return static|mixed */ public function whenEmpty(callable $callback, callable $default = null) { return $this->when($this->isEmpty(), $callback, $default); } /** * Apply the callback if the collection is not empty. * * @param callable $callback * @param callable|null $default * @return static|mixed */ public function whenNotEmpty(callable $callback, callable $default = null) { return $this->when($this->isNotEmpty(), $callback, $default); } /** * Apply the callback if the value is falsy. * * @param bool $value * @param callable $callback * @param callable|null $default * @return static|mixed */ public function unless($value, callable $callback, callable $default = null) { return $this->when(! $value, $callback, $default); } /** * Apply the callback unless the collection is empty. * * @param callable $callback * @param callable|null $default * @return static|mixed */ public function unlessEmpty(callable $callback, callable $default = null) { return $this->whenNotEmpty($callback, $default); } /** * Apply the callback unless the collection is not empty. * * @param callable $callback * @param callable|null $default * @return static|mixed */ public function unlessNotEmpty(callable $callback, callable $default = null) { return $this->whenEmpty($callback, $default); } /** * Filter items by the given key value pair. * * @param string $key * @param mixed $operator * @param mixed $value * @return static */ public function where($key, $operator = null, $value = null) { return $this->filter($this->operatorForWhere(...func_get_args())); } /** * Filter items where the given key is not null. * * @param string|null $key * @return static */ public function whereNull($key = null) { return $this->whereStrict($key, null); } /** * Filter items where the given key is null. * * @param string|null $key * @return static */ public function whereNotNull($key = null) { return $this->where($key, '!==', null); } /** * Filter items by the given key value pair using strict comparison. * * @param string $key * @param mixed $value * @return static */ public function whereStrict($key, $value) { return $this->where($key, '===', $value); } /** * Filter items by the given key value pair. * * @param string $key * @param mixed $values * @param bool $strict * @return static */ public function whereIn($key, $values, $strict = false) { $values = $this->getArrayableItems($values); return $this->filter(function ($item) use ($key, $values, $strict) { return in_array(data_get($item, $key), $values, $strict); }); } /** * Filter items by the given key value pair using strict comparison. * * @param string $key * @param mixed $values * @return static */ public function whereInStrict($key, $values) { return $this->whereIn($key, $values, true); } /** * Filter items such that the value of the given key is between the given values. * * @param string $key * @param array $values * @return static */ public function whereBetween($key, $values) { return $this->where($key, '>=', reset($values))->where($key, '<=', end($values)); } /** * Filter items such that the value of the given key is not between the given values. * * @param string $key * @param array $values * @return static */ public function whereNotBetween($key, $values) { return $this->filter(function ($item) use ($key, $values) { return data_get($item, $key) < reset($values) || data_get($item, $key) > end($values); }); } /** * Filter items by the given key value pair. * * @param string $key * @param mixed $values * @param bool $strict * @return static */ public function whereNotIn($key, $values, $strict = false) { $values = $this->getArrayableItems($values); return $this->reject(function ($item) use ($key, $values, $strict) { return in_array(data_get($item, $key), $values, $strict); }); } /** * Filter items by the given key value pair using strict comparison. * * @param string $key * @param mixed $values * @return static */ public function whereNotInStrict($key, $values) { return $this->whereNotIn($key, $values, true); } /** * Filter the items, removing any items that don't match the given type. * * @param string $type * @return static */ public function whereInstanceOf($type) { return $this->filter(function ($value) use ($type) { return $value instanceof $type; }); } /** * Pass the collection to the given callback and return the result. * * @param callable $callback * @return mixed */ public function pipe(callable $callback) { return $callback($this); } /** * Pass the collection to the given callback and then return it. * * @param callable $callback * @return $this */ public function tap(callable $callback) { $callback(clone $this); return $this; } /** * Create a collection of all elements that do not pass a given truth test. * * @param callable|mixed $callback * @return static */ public function reject($callback = true) { $useAsCallable = $this->useAsCallable($callback); return $this->filter(function ($value, $key) use ($callback, $useAsCallable) { return $useAsCallable ? ! $callback($value, $key) : $value != $callback; }); } /** * Return only unique items from the collection array. * * @param string|callable|null $key * @param bool $strict * @return static */ public function unique($key = null, $strict = false) { $callback = $this->valueRetriever($key); $exists = []; return $this->reject(function ($item, $key) use ($callback, $strict, &$exists) { if (in_array($id = $callback($item, $key), $exists, $strict)) { return true; } $exists[] = $id; }); } /** * Return only unique items from the collection array using strict comparison. * * @param string|callable|null $key * @return static */ public function uniqueStrict($key = null) { return $this->unique($key, true); } /** * Take items in the collection until the given condition is met. * * This is an alias to the "takeUntil" method. * * @param mixed $key * @return static * * @deprecated Use the "takeUntil" method directly. */ public function until($value) { return $this->takeUntil($value); } /** * Collect the values into a collection. * * @return \Illuminate\Support\Collection */ public function collect() { return new Collection($this->all()); } /** * Get the collection of items as a plain array. * * @return array */ public function toArray() { return $this->map(function ($value) { return $value instanceof Arrayable ? $value->toArray() : $value; })->all(); } /** * Convert the object into something JSON serializable. * * @return array */ public function jsonSerialize() { return array_map(function ($value) { if ($value instanceof JsonSerializable) { return $value->jsonSerialize(); } elseif ($value instanceof Jsonable) { return json_decode($value->toJson(), true); } elseif ($value instanceof Arrayable) { return $value->toArray(); } return $value; }, $this->all()); } /** * Get the collection of items as JSON. * * @param int $options * @return string */ public function toJson($options = 0) { return json_encode($this->jsonSerialize(), $options); } /** * Get a CachingIterator instance. * * @param int $flags * @return \CachingIterator */ public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING) { return new CachingIterator($this->getIterator(), $flags); } /** * Count the number of items in the collection using a given truth test. * * @param callable|null $callback * @return static */ public function countBy($callback = null) { if (is_null($callback)) { $callback = function ($value) { return $value; }; } return new static($this->groupBy($callback)->map(function ($value) { return $value->count(); })); } /** * Convert the collection to its string representation. * * @return string */ public function __toString() { return $this->toJson(); } /** * Add a method to the list of proxied methods. * * @param string $method * @return void */ public static function proxy($method) { static::$proxies[] = $method; } /** * Dynamically access collection proxies. * * @param string $key * @return mixed * * @throws \Exception */ public function __get($key) { if (! in_array($key, static::$proxies)) { throw new Exception("Property [{$key}] does not exist on this collection instance."); } return new HigherOrderCollectionProxy($this, $key); } /** * Results array of items from Collection or Arrayable. * * @param mixed $items * @return array */ protected function getArrayableItems($items) { if (is_array($items)) { return $items; } elseif ($items instanceof Enumerable) { return $items->all(); } elseif ($items instanceof Arrayable) { return $items->toArray(); } elseif ($items instanceof Jsonable) { return json_decode($items->toJson(), true); } elseif ($items instanceof JsonSerializable) { return (array) $items->jsonSerialize(); } elseif ($items instanceof Traversable) { return iterator_to_array($items); } return (array) $items; } /** * Get an operator checker callback. * * @param string $key * @param string|null $operator * @param mixed $value * @return \Closure */ protected function operatorForWhere($key, $operator = null, $value = null) { if (func_num_args() === 1) { $value = true; $operator = '='; } if (func_num_args() === 2) { $value = $operator; $operator = '='; } return function ($item) use ($key, $operator, $value) { $retrieved = data_get($item, $key); $strings = array_filter([$retrieved, $value], function ($value) { return is_string($value) || (is_object($value) && method_exists($value, '__toString')); }); if (count($strings) < 2 && count(array_filter([$retrieved, $value], 'is_object')) == 1) { return in_array($operator, ['!=', '<>', '!==']); } switch ($operator) { default: case '=': case '==': return $retrieved == $value; case '!=': case '<>': return $retrieved != $value; case '<': return $retrieved < $value; case '>': return $retrieved > $value; case '<=': return $retrieved <= $value; case '>=': return $retrieved >= $value; case '===': return $retrieved === $value; case '!==': return $retrieved !== $value; } }; } /** * Determine if the given value is callable, but not a string. * * @param mixed $value * @return bool */ protected function useAsCallable($value) { return ! is_string($value) && is_callable($value); } /** * Get a value retrieving callback. * * @param callable|string|null $value * @return callable */ protected function valueRetriever($value) { if ($this->useAsCallable($value)) { return $value; } return function ($item) use ($value) { return data_get($item, $value); }; } /** * Make a function to check an item's equality. * * @param mixed $value * @return \Closure */ protected function equality($value) { return function ($item) use ($value) { return $item === $value; }; } /** * Make a function using another function, by negating its result. * * @param \Closure $callback * @return \Closure */ protected function negate(Closure $callback) { return function (...$params) use ($callback) { return ! $callback(...$params); }; } } support/Traits/ReflectsClosures.php 0000644 00000002621 14736103231 0013527 0 ustar 00 <?php namespace Illuminate\Support\Traits; use Closure; use ReflectionFunction; use RuntimeException; trait ReflectsClosures { /** * Get the class names / types of the parameters of the given Closure. * * @param \Closure $closure * @return array * * @throws \ReflectionException */ protected function closureParameterTypes(Closure $closure) { $reflection = new ReflectionFunction($closure); return collect($reflection->getParameters())->mapWithKeys(function ($parameter) { if ($parameter->isVariadic()) { return [$parameter->getName() => null]; } return [$parameter->getName() => $parameter->getClass()->name ?? null]; })->all(); } /** * Get the class name of the first parameter of the given Closure. * * @param \Closure $closure * @return string * * @throws \ReflectionException|\RuntimeException */ protected function firstClosureParameterType(Closure $closure) { $types = array_values($this->closureParameterTypes($closure)); if (! $types) { throw new RuntimeException('The given Closure has no parameters.'); } if ($types[0] === null) { throw new RuntimeException('The first parameter of the given Closure is missing a type hint.'); } return $types[0]; } } support/Traits/CapsuleManagerTrait.php 0000644 00000002627 14736103231 0014141 0 ustar 00 <?php namespace Illuminate\Support\Traits; use Illuminate\Contracts\Container\Container; use Illuminate\Support\Fluent; trait CapsuleManagerTrait { /** * The current globally used instance. * * @var object */ protected static $instance; /** * The container instance. * * @var \Illuminate\Contracts\Container\Container */ protected $container; /** * Setup the IoC container instance. * * @param \Illuminate\Contracts\Container\Container $container * @return void */ protected function setupContainer(Container $container) { $this->container = $container; if (! $this->container->bound('config')) { $this->container->instance('config', new Fluent); } } /** * Make this capsule instance available globally. * * @return void */ public function setAsGlobal() { static::$instance = $this; } /** * Get the IoC container instance. * * @return \Illuminate\Contracts\Container\Container */ public function getContainer() { return $this->container; } /** * Set the IoC container instance. * * @param \Illuminate\Contracts\Container\Container $container * @return void */ public function setContainer(Container $container) { $this->container = $container; } } support/Stringable.php 0000644 00000035211 14736103231 0011065 0 ustar 00 <?php namespace Illuminate\Support; use Closure; use Illuminate\Support\Traits\Macroable; use Symfony\Component\VarDumper\VarDumper; class Stringable { use Macroable; /** * The underlying string value. * * @var string */ protected $value; /** * Create a new instance of the class. * * @param string $value * @return void */ public function __construct($value = '') { $this->value = (string) $value; } /** * Return the remainder of a string after the first occurrence of a given value. * * @param string $search * @return static */ public function after($search) { return new static(Str::after($this->value, $search)); } /** * Return the remainder of a string after the last occurrence of a given value. * * @param string $search * @return static */ public function afterLast($search) { return new static(Str::afterLast($this->value, $search)); } /** * Append the given values to the string. * * @param array $values * @return static */ public function append(...$values) { return new static($this->value.implode('', $values)); } /** * Transliterate a UTF-8 value to ASCII. * * @param string $language * @return static */ public function ascii($language = 'en') { return new static(Str::ascii($this->value, $language)); } /** * Get the trailing name component of the path. * * @param string $suffix * @return static */ public function basename($suffix = '') { return new static(basename($this->value, $suffix)); } /** * Get the portion of a string before the first occurrence of a given value. * * @param string $search * @return static */ public function before($search) { return new static(Str::before($this->value, $search)); } /** * Get the portion of a string before the last occurrence of a given value. * * @param string $search * @return static */ public function beforeLast($search) { return new static(Str::beforeLast($this->value, $search)); } /** * Get the portion of a string between two given values. * * @param string $from * @param string $to * @return static */ public function between($from, $to) { return new static(Str::between($this->value, $from, $to)); } /** * Convert a value to camel case. * * @return static */ public function camel() { return new static(Str::camel($this->value)); } /** * Determine if a given string contains a given substring. * * @param string|array $needles * @return bool */ public function contains($needles) { return Str::contains($this->value, $needles); } /** * Determine if a given string contains all array values. * * @param array $needles * @return bool */ public function containsAll(array $needles) { return Str::containsAll($this->value, $needles); } /** * Get the parent directory's path. * * @param int $levels * @return static */ public function dirname($levels = 1) { return new static(dirname($this->value, $levels)); } /** * Determine if a given string ends with a given substring. * * @param string|array $needles * @return bool */ public function endsWith($needles) { return Str::endsWith($this->value, $needles); } /** * Determine if the string is an exact match with the given value. * * @param string $value * @return bool */ public function exactly($value) { return $this->value === $value; } /** * Explode the string into an array. * * @param string $delimiter * @param int $limit * @return \Illuminate\Support\Collection */ public function explode($delimiter, $limit = PHP_INT_MAX) { return collect(explode($delimiter, $this->value, $limit)); } /** * Split a string using a regular expression. * * @param string $pattern * @param int $limit * @param int $flags * @return \Illuminate\Support\Collection */ public function split($pattern, $limit = -1, $flags = 0) { $segments = preg_split($pattern, $this->value, $limit, $flags); return ! empty($segments) ? collect($segments) : collect(); } /** * Cap a string with a single instance of a given value. * * @param string $cap * @return static */ public function finish($cap) { return new static(Str::finish($this->value, $cap)); } /** * Determine if a given string matches a given pattern. * * @param string|array $pattern * @return bool */ public function is($pattern) { return Str::is($pattern, $this->value); } /** * Determine if a given string is 7 bit ASCII. * * @return bool */ public function isAscii() { return Str::isAscii($this->value); } /** * Determine if the given string is empty. * * @return bool */ public function isEmpty() { return $this->value === ''; } /** * Determine if the given string is not empty. * * @return bool */ public function isNotEmpty() { return ! $this->isEmpty(); } /** * Convert a string to kebab case. * * @return static */ public function kebab() { return new static(Str::kebab($this->value)); } /** * Return the length of the given string. * * @param string $encoding * @return int */ public function length($encoding = null) { return Str::length($this->value, $encoding); } /** * Limit the number of characters in a string. * * @param int $limit * @param string $end * @return static */ public function limit($limit = 100, $end = '...') { return new static(Str::limit($this->value, $limit, $end)); } /** * Convert the given string to lower-case. * * @return static */ public function lower() { return new static(Str::lower($this->value)); } /** * Get the string matching the given pattern. * * @param string $pattern * @return static|null */ public function match($pattern) { preg_match($pattern, $this->value, $matches); if (! $matches) { return new static; } return new static($matches[1] ?? $matches[0]); } /** * Get the string matching the given pattern. * * @param string $pattern * @return \Illuminate\Support\Collection */ public function matchAll($pattern) { preg_match_all($pattern, $this->value, $matches); if (empty($matches[0])) { return collect(); } return collect($matches[1] ?? $matches[0]); } /** * Parse a Class@method style callback into class and method. * * @param string|null $default * @return array */ public function parseCallback($default = null) { return Str::parseCallback($this->value, $default); } /** * Get the plural form of an English word. * * @param int $count * @return static */ public function plural($count = 2) { return new static(Str::plural($this->value, $count)); } /** * Pluralize the last word of an English, studly caps case string. * * @param int $count * @return static */ public function pluralStudly($count = 2) { return new static(Str::pluralStudly($this->value, $count)); } /** * Prepend the given values to the string. * * @param array $values * @return static */ public function prepend(...$values) { return new static(implode('', $values).$this->value); } /** * Replace the given value in the given string. * * @param string|string[] $search * @param string|string[] $replace * @return static */ public function replace($search, $replace) { return new static(str_replace($search, $replace, $this->value)); } /** * Replace a given value in the string sequentially with an array. * * @param string $search * @param array $replace * @return static */ public function replaceArray($search, array $replace) { return new static(Str::replaceArray($search, $replace, $this->value)); } /** * Replace the first occurrence of a given value in the string. * * @param string $search * @param string $replace * @return static */ public function replaceFirst($search, $replace) { return new static(Str::replaceFirst($search, $replace, $this->value)); } /** * Replace the last occurrence of a given value in the string. * * @param string $search * @param string $replace * @return static */ public function replaceLast($search, $replace) { return new static(Str::replaceLast($search, $replace, $this->value)); } /** * Replace the patterns matching the given regular expression. * * @param string $pattern * @param \Closure|string $replace * @param int $limit * @return static */ public function replaceMatches($pattern, $replace, $limit = -1) { if ($replace instanceof Closure) { return new static(preg_replace_callback($pattern, $replace, $this->value, $limit)); } return new static(preg_replace($pattern, $replace, $this->value, $limit)); } /** * Begin a string with a single instance of a given value. * * @param string $prefix * @return static */ public function start($prefix) { return new static(Str::start($this->value, $prefix)); } /** * Convert the given string to upper-case. * * @return static */ public function upper() { return new static(Str::upper($this->value)); } /** * Convert the given string to title case. * * @return static */ public function title() { return new static(Str::title($this->value)); } /** * Get the singular form of an English word. * * @return static */ public function singular() { return new static(Str::singular($this->value)); } /** * Generate a URL friendly "slug" from a given string. * * @param string $separator * @param string|null $language * @return static */ public function slug($separator = '-', $language = 'en') { return new static(Str::slug($this->value, $separator, $language)); } /** * Convert a string to snake case. * * @param string $delimiter * @return static */ public function snake($delimiter = '_') { return new static(Str::snake($this->value, $delimiter)); } /** * Determine if a given string starts with a given substring. * * @param string|array $needles * @return bool */ public function startsWith($needles) { return Str::startsWith($this->value, $needles); } /** * Convert a value to studly caps case. * * @return static */ public function studly() { return new static(Str::studly($this->value)); } /** * Returns the portion of string specified by the start and length parameters. * * @param int $start * @param int|null $length * @return static */ public function substr($start, $length = null) { return new static(Str::substr($this->value, $start, $length)); } /** * Returns the number of substring occurrences. * * @param string $needle * @param int|null $offset * @param int|null $length * @return int */ public function substrCount($needle, $offset = null, $length = null) { return Str::substrCount($this->value, $needle, $offset, $length); } /** * Trim the string of the given characters. * * @param string $characters * @return static */ public function trim($characters = null) { return new static(trim(...array_merge([$this->value], func_get_args()))); } /** * Left trim the string of the given characters. * * @param string $characters * @return static */ public function ltrim($characters = null) { return new static(ltrim(...array_merge([$this->value], func_get_args()))); } /** * Right trim the string of the given characters. * * @param string $characters * @return static */ public function rtrim($characters = null) { return new static(rtrim(...array_merge([$this->value], func_get_args()))); } /** * Make a string's first character uppercase. * * @return static */ public function ucfirst() { return new static(Str::ucfirst($this->value)); } /** * Execute the given callback if the string is empty. * * @param callable $callback * @return static */ public function whenEmpty($callback) { if ($this->isEmpty()) { $result = $callback($this); return is_null($result) ? $this : $result; } return $this; } /** * Limit the number of words in a string. * * @param int $words * @param string $end * @return static */ public function words($words = 100, $end = '...') { return new static(Str::words($this->value, $words, $end)); } /** * Dump the string. * * @return $this */ public function dump() { VarDumper::dump($this->value); return $this; } /** * Dump the string and end the script. * * @return void */ public function dd() { $this->dump(); die(1); } /** * Proxy dynamic properties onto methods. * * @param string $key * @return mixed */ public function __get($key) { return $this->{$key}(); } /** * Get the raw string value. * * @return string */ public function __toString() { return (string) $this->value; } } support/Collection.php 0000644 00000077077 14736103231 0011106 0 ustar 00 <?php namespace Illuminate\Support; use ArrayAccess; use ArrayIterator; use Illuminate\Support\Traits\EnumeratesValues; use Illuminate\Support\Traits\Macroable; use stdClass; class Collection implements ArrayAccess, Enumerable { use EnumeratesValues, Macroable; /** * The items contained in the collection. * * @var array */ protected $items = []; /** * Create a new collection. * * @param mixed $items * @return void */ public function __construct($items = []) { $this->items = $this->getArrayableItems($items); } /** * Create a new collection by invoking the callback a given amount of times. * * @param int $number * @param callable|null $callback * @return static */ public static function times($number, callable $callback = null) { if ($number < 1) { return new static; } if (is_null($callback)) { return new static(range(1, $number)); } return (new static(range(1, $number)))->map($callback); } /** * Get all of the items in the collection. * * @return array */ public function all() { return $this->items; } /** * Get a lazy collection for the items in this collection. * * @return \Illuminate\Support\LazyCollection */ public function lazy() { return new LazyCollection($this->items); } /** * Get the average value of a given key. * * @param callable|string|null $callback * @return mixed */ public function avg($callback = null) { $callback = $this->valueRetriever($callback); $items = $this->map(function ($value) use ($callback) { return $callback($value); })->filter(function ($value) { return ! is_null($value); }); if ($count = $items->count()) { return $items->sum() / $count; } } /** * Get the median of a given key. * * @param string|array|null $key * @return mixed */ public function median($key = null) { $values = (isset($key) ? $this->pluck($key) : $this) ->filter(function ($item) { return ! is_null($item); })->sort()->values(); $count = $values->count(); if ($count === 0) { return; } $middle = (int) ($count / 2); if ($count % 2) { return $values->get($middle); } return (new static([ $values->get($middle - 1), $values->get($middle), ]))->average(); } /** * Get the mode of a given key. * * @param string|array|null $key * @return array|null */ public function mode($key = null) { if ($this->count() === 0) { return; } $collection = isset($key) ? $this->pluck($key) : $this; $counts = new self; $collection->each(function ($value) use ($counts) { $counts[$value] = isset($counts[$value]) ? $counts[$value] + 1 : 1; }); $sorted = $counts->sort(); $highestValue = $sorted->last(); return $sorted->filter(function ($value) use ($highestValue) { return $value == $highestValue; })->sort()->keys()->all(); } /** * Collapse the collection of items into a single array. * * @return static */ public function collapse() { return new static(Arr::collapse($this->items)); } /** * Determine if an item exists in the collection. * * @param mixed $key * @param mixed $operator * @param mixed $value * @return bool */ public function contains($key, $operator = null, $value = null) { if (func_num_args() === 1) { if ($this->useAsCallable($key)) { $placeholder = new stdClass; return $this->first($key, $placeholder) !== $placeholder; } return in_array($key, $this->items); } return $this->contains($this->operatorForWhere(...func_get_args())); } /** * Cross join with the given lists, returning all possible permutations. * * @param mixed ...$lists * @return static */ public function crossJoin(...$lists) { return new static(Arr::crossJoin( $this->items, ...array_map([$this, 'getArrayableItems'], $lists) )); } /** * Get the items in the collection that are not present in the given items. * * @param mixed $items * @return static */ public function diff($items) { return new static(array_diff($this->items, $this->getArrayableItems($items))); } /** * Get the items in the collection that are not present in the given items, using the callback. * * @param mixed $items * @param callable $callback * @return static */ public function diffUsing($items, callable $callback) { return new static(array_udiff($this->items, $this->getArrayableItems($items), $callback)); } /** * Get the items in the collection whose keys and values are not present in the given items. * * @param mixed $items * @return static */ public function diffAssoc($items) { return new static(array_diff_assoc($this->items, $this->getArrayableItems($items))); } /** * Get the items in the collection whose keys and values are not present in the given items, using the callback. * * @param mixed $items * @param callable $callback * @return static */ public function diffAssocUsing($items, callable $callback) { return new static(array_diff_uassoc($this->items, $this->getArrayableItems($items), $callback)); } /** * Get the items in the collection whose keys are not present in the given items. * * @param mixed $items * @return static */ public function diffKeys($items) { return new static(array_diff_key($this->items, $this->getArrayableItems($items))); } /** * Get the items in the collection whose keys are not present in the given items, using the callback. * * @param mixed $items * @param callable $callback * @return static */ public function diffKeysUsing($items, callable $callback) { return new static(array_diff_ukey($this->items, $this->getArrayableItems($items), $callback)); } /** * Retrieve duplicate items from the collection. * * @param callable|null $callback * @param bool $strict * @return static */ public function duplicates($callback = null, $strict = false) { $items = $this->map($this->valueRetriever($callback)); $uniqueItems = $items->unique(null, $strict); $compare = $this->duplicateComparator($strict); $duplicates = new static; foreach ($items as $key => $value) { if ($uniqueItems->isNotEmpty() && $compare($value, $uniqueItems->first())) { $uniqueItems->shift(); } else { $duplicates[$key] = $value; } } return $duplicates; } /** * Retrieve duplicate items from the collection using strict comparison. * * @param callable|null $callback * @return static */ public function duplicatesStrict($callback = null) { return $this->duplicates($callback, true); } /** * Get the comparison function to detect duplicates. * * @param bool $strict * @return \Closure */ protected function duplicateComparator($strict) { if ($strict) { return function ($a, $b) { return $a === $b; }; } return function ($a, $b) { return $a == $b; }; } /** * Get all items except for those with the specified keys. * * @param \Illuminate\Support\Collection|mixed $keys * @return static */ public function except($keys) { if ($keys instanceof Enumerable) { $keys = $keys->all(); } elseif (! is_array($keys)) { $keys = func_get_args(); } return new static(Arr::except($this->items, $keys)); } /** * Run a filter over each of the items. * * @param callable|null $callback * @return static */ public function filter(callable $callback = null) { if ($callback) { return new static(Arr::where($this->items, $callback)); } return new static(array_filter($this->items)); } /** * Get the first item from the collection passing the given truth test. * * @param callable|null $callback * @param mixed $default * @return mixed */ public function first(callable $callback = null, $default = null) { return Arr::first($this->items, $callback, $default); } /** * Get a flattened array of the items in the collection. * * @param int $depth * @return static */ public function flatten($depth = INF) { return new static(Arr::flatten($this->items, $depth)); } /** * Flip the items in the collection. * * @return static */ public function flip() { return new static(array_flip($this->items)); } /** * Remove an item from the collection by key. * * @param string|array $keys * @return $this */ public function forget($keys) { foreach ((array) $keys as $key) { $this->offsetUnset($key); } return $this; } /** * Get an item from the collection by key. * * @param mixed $key * @param mixed $default * @return mixed */ public function get($key, $default = null) { if ($this->offsetExists($key)) { return $this->items[$key]; } return value($default); } /** * Group an associative array by a field or using a callback. * * @param array|callable|string $groupBy * @param bool $preserveKeys * @return static */ public function groupBy($groupBy, $preserveKeys = false) { if (! $this->useAsCallable($groupBy) && is_array($groupBy)) { $nextGroups = $groupBy; $groupBy = array_shift($nextGroups); } $groupBy = $this->valueRetriever($groupBy); $results = []; foreach ($this->items as $key => $value) { $groupKeys = $groupBy($value, $key); if (! is_array($groupKeys)) { $groupKeys = [$groupKeys]; } foreach ($groupKeys as $groupKey) { $groupKey = is_bool($groupKey) ? (int) $groupKey : $groupKey; if (! array_key_exists($groupKey, $results)) { $results[$groupKey] = new static; } $results[$groupKey]->offsetSet($preserveKeys ? $key : null, $value); } } $result = new static($results); if (! empty($nextGroups)) { return $result->map->groupBy($nextGroups, $preserveKeys); } return $result; } /** * Key an associative array by a field or using a callback. * * @param callable|string $keyBy * @return static */ public function keyBy($keyBy) { $keyBy = $this->valueRetriever($keyBy); $results = []; foreach ($this->items as $key => $item) { $resolvedKey = $keyBy($item, $key); if (is_object($resolvedKey)) { $resolvedKey = (string) $resolvedKey; } $results[$resolvedKey] = $item; } return new static($results); } /** * Determine if an item exists in the collection by key. * * @param mixed $key * @return bool */ public function has($key) { $keys = is_array($key) ? $key : func_get_args(); foreach ($keys as $value) { if (! $this->offsetExists($value)) { return false; } } return true; } /** * Concatenate values of a given key as a string. * * @param string $value * @param string|null $glue * @return string */ public function implode($value, $glue = null) { $first = $this->first(); if (is_array($first) || is_object($first)) { return implode($glue, $this->pluck($value)->all()); } return implode($value, $this->items); } /** * Intersect the collection with the given items. * * @param mixed $items * @return static */ public function intersect($items) { return new static(array_intersect($this->items, $this->getArrayableItems($items))); } /** * Intersect the collection with the given items by key. * * @param mixed $items * @return static */ public function intersectByKeys($items) { return new static(array_intersect_key( $this->items, $this->getArrayableItems($items) )); } /** * Determine if the collection is empty or not. * * @return bool */ public function isEmpty() { return empty($this->items); } /** * Join all items from the collection using a string. The final items can use a separate glue string. * * @param string $glue * @param string $finalGlue * @return string */ public function join($glue, $finalGlue = '') { if ($finalGlue === '') { return $this->implode($glue); } $count = $this->count(); if ($count === 0) { return ''; } if ($count === 1) { return $this->last(); } $collection = new static($this->items); $finalItem = $collection->pop(); return $collection->implode($glue).$finalGlue.$finalItem; } /** * Get the keys of the collection items. * * @return static */ public function keys() { return new static(array_keys($this->items)); } /** * Get the last item from the collection. * * @param callable|null $callback * @param mixed $default * @return mixed */ public function last(callable $callback = null, $default = null) { return Arr::last($this->items, $callback, $default); } /** * Get the values of a given key. * * @param string|array $value * @param string|null $key * @return static */ public function pluck($value, $key = null) { return new static(Arr::pluck($this->items, $value, $key)); } /** * Run a map over each of the items. * * @param callable $callback * @return static */ public function map(callable $callback) { $keys = array_keys($this->items); $items = array_map($callback, $this->items, $keys); return new static(array_combine($keys, $items)); } /** * Run a dictionary map over the items. * * The callback should return an associative array with a single key/value pair. * * @param callable $callback * @return static */ public function mapToDictionary(callable $callback) { $dictionary = []; foreach ($this->items as $key => $item) { $pair = $callback($item, $key); $key = key($pair); $value = reset($pair); if (! isset($dictionary[$key])) { $dictionary[$key] = []; } $dictionary[$key][] = $value; } return new static($dictionary); } /** * Run an associative map over each of the items. * * The callback should return an associative array with a single key/value pair. * * @param callable $callback * @return static */ public function mapWithKeys(callable $callback) { $result = []; foreach ($this->items as $key => $value) { $assoc = $callback($value, $key); foreach ($assoc as $mapKey => $mapValue) { $result[$mapKey] = $mapValue; } } return new static($result); } /** * Merge the collection with the given items. * * @param mixed $items * @return static */ public function merge($items) { return new static(array_merge($this->items, $this->getArrayableItems($items))); } /** * Recursively merge the collection with the given items. * * @param mixed $items * @return static */ public function mergeRecursive($items) { return new static(array_merge_recursive($this->items, $this->getArrayableItems($items))); } /** * Create a collection by using this collection for keys and another for its values. * * @param mixed $values * @return static */ public function combine($values) { return new static(array_combine($this->all(), $this->getArrayableItems($values))); } /** * Union the collection with the given items. * * @param mixed $items * @return static */ public function union($items) { return new static($this->items + $this->getArrayableItems($items)); } /** * Create a new collection consisting of every n-th element. * * @param int $step * @param int $offset * @return static */ public function nth($step, $offset = 0) { $new = []; $position = 0; foreach ($this->items as $item) { if ($position % $step === $offset) { $new[] = $item; } $position++; } return new static($new); } /** * Get the items with the specified keys. * * @param mixed $keys * @return static */ public function only($keys) { if (is_null($keys)) { return new static($this->items); } if ($keys instanceof Enumerable) { $keys = $keys->all(); } $keys = is_array($keys) ? $keys : func_get_args(); return new static(Arr::only($this->items, $keys)); } /** * Get and remove the last item from the collection. * * @return mixed */ public function pop() { return array_pop($this->items); } /** * Push an item onto the beginning of the collection. * * @param mixed $value * @param mixed $key * @return $this */ public function prepend($value, $key = null) { $this->items = Arr::prepend($this->items, $value, $key); return $this; } /** * Push one or more items onto the end of the collection. * * @param mixed $values [optional] * @return $this */ public function push(...$values) { foreach ($values as $value) { $this->items[] = $value; } return $this; } /** * Push all of the given items onto the collection. * * @param iterable $source * @return static */ public function concat($source) { $result = new static($this); foreach ($source as $item) { $result->push($item); } return $result; } /** * Get and remove an item from the collection. * * @param mixed $key * @param mixed $default * @return mixed */ public function pull($key, $default = null) { return Arr::pull($this->items, $key, $default); } /** * Put an item in the collection by key. * * @param mixed $key * @param mixed $value * @return $this */ public function put($key, $value) { $this->offsetSet($key, $value); return $this; } /** * Get one or a specified number of items randomly from the collection. * * @param int|null $number * @return static|mixed * * @throws \InvalidArgumentException */ public function random($number = null) { if (is_null($number)) { return Arr::random($this->items); } return new static(Arr::random($this->items, $number)); } /** * Reduce the collection to a single value. * * @param callable $callback * @param mixed $initial * @return mixed */ public function reduce(callable $callback, $initial = null) { return array_reduce($this->items, $callback, $initial); } /** * Replace the collection items with the given items. * * @param mixed $items * @return static */ public function replace($items) { return new static(array_replace($this->items, $this->getArrayableItems($items))); } /** * Recursively replace the collection items with the given items. * * @param mixed $items * @return static */ public function replaceRecursive($items) { return new static(array_replace_recursive($this->items, $this->getArrayableItems($items))); } /** * Reverse items order. * * @return static */ public function reverse() { return new static(array_reverse($this->items, true)); } /** * Search the collection for a given value and return the corresponding key if successful. * * @param mixed $value * @param bool $strict * @return mixed */ public function search($value, $strict = false) { if (! $this->useAsCallable($value)) { return array_search($value, $this->items, $strict); } foreach ($this->items as $key => $item) { if ($value($item, $key)) { return $key; } } return false; } /** * Get and remove the first item from the collection. * * @return mixed */ public function shift() { return array_shift($this->items); } /** * Shuffle the items in the collection. * * @param int|null $seed * @return static */ public function shuffle($seed = null) { return new static(Arr::shuffle($this->items, $seed)); } /** * Skip the first {$count} items. * * @param int $count * @return static */ public function skip($count) { return $this->slice($count); } /** * Skip items in the collection until the given condition is met. * * @param mixed $value * @return static */ public function skipUntil($value) { return new static($this->lazy()->skipUntil($value)->all()); } /** * Skip items in the collection while the given condition is met. * * @param mixed $value * @return static */ public function skipWhile($value) { return new static($this->lazy()->skipWhile($value)->all()); } /** * Slice the underlying collection array. * * @param int $offset * @param int|null $length * @return static */ public function slice($offset, $length = null) { return new static(array_slice($this->items, $offset, $length, true)); } /** * Split a collection into a certain number of groups. * * @param int $numberOfGroups * @return static */ public function split($numberOfGroups) { if ($this->isEmpty()) { return new static; } $groups = new static; $groupSize = floor($this->count() / $numberOfGroups); $remain = $this->count() % $numberOfGroups; $start = 0; for ($i = 0; $i < $numberOfGroups; $i++) { $size = $groupSize; if ($i < $remain) { $size++; } if ($size) { $groups->push(new static(array_slice($this->items, $start, $size))); $start += $size; } } return $groups; } /** * Chunk the collection into chunks of the given size. * * @param int $size * @return static */ public function chunk($size) { if ($size <= 0) { return new static; } $chunks = []; foreach (array_chunk($this->items, $size, true) as $chunk) { $chunks[] = new static($chunk); } return new static($chunks); } /** * Sort through each item with a callback. * * @param callable|null $callback * @return static */ public function sort($callback = null) { $items = $this->items; $callback && is_callable($callback) ? uasort($items, $callback) : asort($items, $callback); return new static($items); } /** * Sort items in descending order. * * @param int $options * @return static */ public function sortDesc($options = SORT_REGULAR) { $items = $this->items; arsort($items, $options); return new static($items); } /** * Sort the collection using the given callback. * * @param callable|string $callback * @param int $options * @param bool $descending * @return static */ public function sortBy($callback, $options = SORT_REGULAR, $descending = false) { $results = []; $callback = $this->valueRetriever($callback); // First we will loop through the items and get the comparator from a callback // function which we were given. Then, we will sort the returned values and // and grab the corresponding values for the sorted keys from this array. foreach ($this->items as $key => $value) { $results[$key] = $callback($value, $key); } $descending ? arsort($results, $options) : asort($results, $options); // Once we have sorted all of the keys in the array, we will loop through them // and grab the corresponding model so we can set the underlying items list // to the sorted version. Then we'll just return the collection instance. foreach (array_keys($results) as $key) { $results[$key] = $this->items[$key]; } return new static($results); } /** * Sort the collection in descending order using the given callback. * * @param callable|string $callback * @param int $options * @return static */ public function sortByDesc($callback, $options = SORT_REGULAR) { return $this->sortBy($callback, $options, true); } /** * Sort the collection keys. * * @param int $options * @param bool $descending * @return static */ public function sortKeys($options = SORT_REGULAR, $descending = false) { $items = $this->items; $descending ? krsort($items, $options) : ksort($items, $options); return new static($items); } /** * Sort the collection keys in descending order. * * @param int $options * @return static */ public function sortKeysDesc($options = SORT_REGULAR) { return $this->sortKeys($options, true); } /** * Splice a portion of the underlying collection array. * * @param int $offset * @param int|null $length * @param mixed $replacement * @return static */ public function splice($offset, $length = null, $replacement = []) { if (func_num_args() === 1) { return new static(array_splice($this->items, $offset)); } return new static(array_splice($this->items, $offset, $length, $replacement)); } /** * Take the first or last {$limit} items. * * @param int $limit * @return static */ public function take($limit) { if ($limit < 0) { return $this->slice($limit, abs($limit)); } return $this->slice(0, $limit); } /** * Take items in the collection until the given condition is met. * * @param mixed $key * @return static */ public function takeUntil($value) { return new static($this->lazy()->takeUntil($value)->all()); } /** * Take items in the collection while the given condition is met. * * @param mixed $key * @return static */ public function takeWhile($value) { return new static($this->lazy()->takeWhile($value)->all()); } /** * Transform each item in the collection using a callback. * * @param callable $callback * @return $this */ public function transform(callable $callback) { $this->items = $this->map($callback)->all(); return $this; } /** * Reset the keys on the underlying array. * * @return static */ public function values() { return new static(array_values($this->items)); } /** * Zip the collection together with one or more arrays. * * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]); * => [[1, 4], [2, 5], [3, 6]] * * @param mixed ...$items * @return static */ public function zip($items) { $arrayableItems = array_map(function ($items) { return $this->getArrayableItems($items); }, func_get_args()); $params = array_merge([function () { return new static(func_get_args()); }, $this->items], $arrayableItems); return new static(call_user_func_array('array_map', $params)); } /** * Pad collection to the specified length with a value. * * @param int $size * @param mixed $value * @return static */ public function pad($size, $value) { return new static(array_pad($this->items, $size, $value)); } /** * Get an iterator for the items. * * @return \ArrayIterator */ public function getIterator() { return new ArrayIterator($this->items); } /** * Count the number of items in the collection. * * @return int */ public function count() { return count($this->items); } /** * Add an item to the collection. * * @param mixed $item * @return $this */ public function add($item) { $this->items[] = $item; return $this; } /** * Get a base Support collection instance from this collection. * * @return \Illuminate\Support\Collection */ public function toBase() { return new self($this); } /** * Determine if an item exists at an offset. * * @param mixed $key * @return bool */ public function offsetExists($key) { return array_key_exists($key, $this->items); } /** * Get an item at a given offset. * * @param mixed $key * @return mixed */ public function offsetGet($key) { return $this->items[$key]; } /** * Set the item at a given offset. * * @param mixed $key * @param mixed $value * @return void */ public function offsetSet($key, $value) { if (is_null($key)) { $this->items[] = $value; } else { $this->items[$key] = $value; } } /** * Unset the item at a given offset. * * @param string $key * @return void */ public function offsetUnset($key) { unset($this->items[$key]); } } support/Optional.php 0000644 00000005121 14736103231 0010555 0 ustar 00 <?php namespace Illuminate\Support; use ArrayAccess; use ArrayObject; class Optional implements ArrayAccess { use Traits\Macroable { __call as macroCall; } /** * The underlying object. * * @var mixed */ protected $value; /** * Create a new optional instance. * * @param mixed $value * @return void */ public function __construct($value) { $this->value = $value; } /** * Dynamically access a property on the underlying object. * * @param string $key * @return mixed */ public function __get($key) { if (is_object($this->value)) { return $this->value->{$key} ?? null; } } /** * Dynamically check a property exists on the underlying object. * * @param mixed $name * @return bool */ public function __isset($name) { if (is_object($this->value)) { return isset($this->value->{$name}); } if (is_array($this->value) || $this->value instanceof ArrayObject) { return isset($this->value[$name]); } return false; } /** * Determine if an item exists at an offset. * * @param mixed $key * @return bool */ public function offsetExists($key) { return Arr::accessible($this->value) && Arr::exists($this->value, $key); } /** * Get an item at a given offset. * * @param mixed $key * @return mixed */ public function offsetGet($key) { return Arr::get($this->value, $key); } /** * Set the item at a given offset. * * @param mixed $key * @param mixed $value * @return void */ public function offsetSet($key, $value) { if (Arr::accessible($this->value)) { $this->value[$key] = $value; } } /** * Unset the item at a given offset. * * @param string $key * @return void */ public function offsetUnset($key) { if (Arr::accessible($this->value)) { unset($this->value[$key]); } } /** * Dynamically pass a method to the underlying object. * * @param string $method * @param array $parameters * @return mixed */ public function __call($method, $parameters) { if (static::hasMacro($method)) { return $this->macroCall($method, $parameters); } if (is_object($this->value)) { return $this->value->{$method}(...$parameters); } } } support/InteractsWithTime.php 0000644 00000003064 14736103231 0012403 0 ustar 00 <?php namespace Illuminate\Support; use DateInterval; use DateTimeInterface; trait InteractsWithTime { /** * Get the number of seconds until the given DateTime. * * @param \DateTimeInterface|\DateInterval|int $delay * @return int */ protected function secondsUntil($delay) { $delay = $this->parseDateInterval($delay); return $delay instanceof DateTimeInterface ? max(0, $delay->getTimestamp() - $this->currentTime()) : (int) $delay; } /** * Get the "available at" UNIX timestamp. * * @param \DateTimeInterface|\DateInterval|int $delay * @return int */ protected function availableAt($delay = 0) { $delay = $this->parseDateInterval($delay); return $delay instanceof DateTimeInterface ? $delay->getTimestamp() : Carbon::now()->addRealSeconds($delay)->getTimestamp(); } /** * If the given value is an interval, convert it to a DateTime instance. * * @param \DateTimeInterface|\DateInterval|int $delay * @return \DateTimeInterface|int */ protected function parseDateInterval($delay) { if ($delay instanceof DateInterval) { $delay = Carbon::now()->add($delay); } return $delay; } /** * Get the current system time as a UNIX timestamp. * * @return int */ protected function currentTime() { return Carbon::now()->getTimestamp(); } } support/LazyCollection.php 0000644 00000077522 14736103231 0011741 0 ustar 00 <?php namespace Illuminate\Support; use ArrayIterator; use Closure; use Illuminate\Support\Traits\EnumeratesValues; use Illuminate\Support\Traits\Macroable; use IteratorAggregate; use stdClass; class LazyCollection implements Enumerable { use EnumeratesValues, Macroable; /** * The source from which to generate items. * * @var callable|static */ public $source; /** * Create a new lazy collection instance. * * @param mixed $source * @return void */ public function __construct($source = null) { if ($source instanceof Closure || $source instanceof self) { $this->source = $source; } elseif (is_null($source)) { $this->source = static::empty(); } else { $this->source = $this->getArrayableItems($source); } } /** * Create a new instance with no items. * * @return static */ public static function empty() { return new static([]); } /** * Create a new instance by invoking the callback a given amount of times. * * @param int $number * @param callable|null $callback * @return static */ public static function times($number, callable $callback = null) { if ($number < 1) { return new static; } $instance = new static(function () use ($number) { for ($current = 1; $current <= $number; $current++) { yield $current; } }); return is_null($callback) ? $instance : $instance->map($callback); } /** * Create an enumerable with the given range. * * @param int $from * @param int $to * @return static */ public static function range($from, $to) { return new static(function () use ($from, $to) { for (; $from <= $to; $from++) { yield $from; } }); } /** * Get all items in the enumerable. * * @return array */ public function all() { if (is_array($this->source)) { return $this->source; } return iterator_to_array($this->getIterator()); } /** * Eager load all items into a new lazy collection backed by an array. * * @return static */ public function eager() { return new static($this->all()); } /** * Cache values as they're enumerated. * * @return static */ public function remember() { $iterator = $this->getIterator(); $iteratorIndex = 0; $cache = []; return new static(function () use ($iterator, &$iteratorIndex, &$cache) { for ($index = 0; true; $index++) { if (array_key_exists($index, $cache)) { yield $cache[$index][0] => $cache[$index][1]; continue; } if ($iteratorIndex < $index) { $iterator->next(); $iteratorIndex++; } if (! $iterator->valid()) { break; } $cache[$index] = [$iterator->key(), $iterator->current()]; yield $cache[$index][0] => $cache[$index][1]; } }); } /** * Get the average value of a given key. * * @param callable|string|null $callback * @return mixed */ public function avg($callback = null) { return $this->collect()->avg($callback); } /** * Get the median of a given key. * * @param string|array|null $key * @return mixed */ public function median($key = null) { return $this->collect()->median($key); } /** * Get the mode of a given key. * * @param string|array|null $key * @return array|null */ public function mode($key = null) { return $this->collect()->mode($key); } /** * Collapse the collection of items into a single array. * * @return static */ public function collapse() { return new static(function () { foreach ($this as $values) { if (is_array($values) || $values instanceof Enumerable) { foreach ($values as $value) { yield $value; } } } }); } /** * Determine if an item exists in the enumerable. * * @param mixed $key * @param mixed $operator * @param mixed $value * @return bool */ public function contains($key, $operator = null, $value = null) { if (func_num_args() === 1 && $this->useAsCallable($key)) { $placeholder = new stdClass; return $this->first($key, $placeholder) !== $placeholder; } if (func_num_args() === 1) { $needle = $key; foreach ($this as $value) { if ($value == $needle) { return true; } } return false; } return $this->contains($this->operatorForWhere(...func_get_args())); } /** * Cross join the given iterables, returning all possible permutations. * * @param array ...$arrays * @return static */ public function crossJoin(...$arrays) { return $this->passthru('crossJoin', func_get_args()); } /** * Get the items that are not present in the given items. * * @param mixed $items * @return static */ public function diff($items) { return $this->passthru('diff', func_get_args()); } /** * Get the items that are not present in the given items, using the callback. * * @param mixed $items * @param callable $callback * @return static */ public function diffUsing($items, callable $callback) { return $this->passthru('diffUsing', func_get_args()); } /** * Get the items whose keys and values are not present in the given items. * * @param mixed $items * @return static */ public function diffAssoc($items) { return $this->passthru('diffAssoc', func_get_args()); } /** * Get the items whose keys and values are not present in the given items, using the callback. * * @param mixed $items * @param callable $callback * @return static */ public function diffAssocUsing($items, callable $callback) { return $this->passthru('diffAssocUsing', func_get_args()); } /** * Get the items whose keys are not present in the given items. * * @param mixed $items * @return static */ public function diffKeys($items) { return $this->passthru('diffKeys', func_get_args()); } /** * Get the items whose keys are not present in the given items, using the callback. * * @param mixed $items * @param callable $callback * @return static */ public function diffKeysUsing($items, callable $callback) { return $this->passthru('diffKeysUsing', func_get_args()); } /** * Retrieve duplicate items. * * @param callable|null $callback * @param bool $strict * @return static */ public function duplicates($callback = null, $strict = false) { return $this->passthru('duplicates', func_get_args()); } /** * Retrieve duplicate items using strict comparison. * * @param callable|null $callback * @return static */ public function duplicatesStrict($callback = null) { return $this->passthru('duplicatesStrict', func_get_args()); } /** * Get all items except for those with the specified keys. * * @param mixed $keys * @return static */ public function except($keys) { return $this->passthru('except', func_get_args()); } /** * Run a filter over each of the items. * * @param callable|null $callback * @return static */ public function filter(callable $callback = null) { if (is_null($callback)) { $callback = function ($value) { return (bool) $value; }; } return new static(function () use ($callback) { foreach ($this as $key => $value) { if ($callback($value, $key)) { yield $key => $value; } } }); } /** * Get the first item from the enumerable passing the given truth test. * * @param callable|null $callback * @param mixed $default * @return mixed */ public function first(callable $callback = null, $default = null) { $iterator = $this->getIterator(); if (is_null($callback)) { if (! $iterator->valid()) { return value($default); } return $iterator->current(); } foreach ($iterator as $key => $value) { if ($callback($value, $key)) { return $value; } } return value($default); } /** * Get a flattened list of the items in the collection. * * @param int $depth * @return static */ public function flatten($depth = INF) { $instance = new static(function () use ($depth) { foreach ($this as $item) { if (! is_array($item) && ! $item instanceof Enumerable) { yield $item; } elseif ($depth === 1) { yield from $item; } else { yield from (new static($item))->flatten($depth - 1); } } }); return $instance->values(); } /** * Flip the items in the collection. * * @return static */ public function flip() { return new static(function () { foreach ($this as $key => $value) { yield $value => $key; } }); } /** * Get an item by key. * * @param mixed $key * @param mixed $default * @return mixed */ public function get($key, $default = null) { if (is_null($key)) { return; } foreach ($this as $outerKey => $outerValue) { if ($outerKey == $key) { return $outerValue; } } return value($default); } /** * Group an associative array by a field or using a callback. * * @param array|callable|string $groupBy * @param bool $preserveKeys * @return static */ public function groupBy($groupBy, $preserveKeys = false) { return $this->passthru('groupBy', func_get_args()); } /** * Key an associative array by a field or using a callback. * * @param callable|string $keyBy * @return static */ public function keyBy($keyBy) { return new static(function () use ($keyBy) { $keyBy = $this->valueRetriever($keyBy); foreach ($this as $key => $item) { $resolvedKey = $keyBy($item, $key); if (is_object($resolvedKey)) { $resolvedKey = (string) $resolvedKey; } yield $resolvedKey => $item; } }); } /** * Determine if an item exists in the collection by key. * * @param mixed $key * @return bool */ public function has($key) { $keys = array_flip(is_array($key) ? $key : func_get_args()); $count = count($keys); foreach ($this as $key => $value) { if (array_key_exists($key, $keys) && --$count == 0) { return true; } } return false; } /** * Concatenate values of a given key as a string. * * @param string $value * @param string|null $glue * @return string */ public function implode($value, $glue = null) { return $this->collect()->implode(...func_get_args()); } /** * Intersect the collection with the given items. * * @param mixed $items * @return static */ public function intersect($items) { return $this->passthru('intersect', func_get_args()); } /** * Intersect the collection with the given items by key. * * @param mixed $items * @return static */ public function intersectByKeys($items) { return $this->passthru('intersectByKeys', func_get_args()); } /** * Determine if the items is empty or not. * * @return bool */ public function isEmpty() { return ! $this->getIterator()->valid(); } /** * Join all items from the collection using a string. The final items can use a separate glue string. * * @param string $glue * @param string $finalGlue * @return string */ public function join($glue, $finalGlue = '') { return $this->collect()->join(...func_get_args()); } /** * Get the keys of the collection items. * * @return static */ public function keys() { return new static(function () { foreach ($this as $key => $value) { yield $key; } }); } /** * Get the last item from the collection. * * @param callable|null $callback * @param mixed $default * @return mixed */ public function last(callable $callback = null, $default = null) { $needle = $placeholder = new stdClass; foreach ($this as $key => $value) { if (is_null($callback) || $callback($value, $key)) { $needle = $value; } } return $needle === $placeholder ? value($default) : $needle; } /** * Get the values of a given key. * * @param string|array $value * @param string|null $key * @return static */ public function pluck($value, $key = null) { return new static(function () use ($value, $key) { [$value, $key] = $this->explodePluckParameters($value, $key); foreach ($this as $item) { $itemValue = data_get($item, $value); if (is_null($key)) { yield $itemValue; } else { $itemKey = data_get($item, $key); if (is_object($itemKey) && method_exists($itemKey, '__toString')) { $itemKey = (string) $itemKey; } yield $itemKey => $itemValue; } } }); } /** * Run a map over each of the items. * * @param callable $callback * @return static */ public function map(callable $callback) { return new static(function () use ($callback) { foreach ($this as $key => $value) { yield $key => $callback($value, $key); } }); } /** * Run a dictionary map over the items. * * The callback should return an associative array with a single key/value pair. * * @param callable $callback * @return static */ public function mapToDictionary(callable $callback) { return $this->passthru('mapToDictionary', func_get_args()); } /** * Run an associative map over each of the items. * * The callback should return an associative array with a single key/value pair. * * @param callable $callback * @return static */ public function mapWithKeys(callable $callback) { return new static(function () use ($callback) { foreach ($this as $key => $value) { yield from $callback($value, $key); } }); } /** * Merge the collection with the given items. * * @param mixed $items * @return static */ public function merge($items) { return $this->passthru('merge', func_get_args()); } /** * Recursively merge the collection with the given items. * * @param mixed $items * @return static */ public function mergeRecursive($items) { return $this->passthru('mergeRecursive', func_get_args()); } /** * Create a collection by using this collection for keys and another for its values. * * @param mixed $values * @return static */ public function combine($values) { return new static(function () use ($values) { $values = $this->makeIterator($values); $errorMessage = 'Both parameters should have an equal number of elements'; foreach ($this as $key) { if (! $values->valid()) { trigger_error($errorMessage, E_USER_WARNING); break; } yield $key => $values->current(); $values->next(); } if ($values->valid()) { trigger_error($errorMessage, E_USER_WARNING); } }); } /** * Union the collection with the given items. * * @param mixed $items * @return static */ public function union($items) { return $this->passthru('union', func_get_args()); } /** * Create a new collection consisting of every n-th element. * * @param int $step * @param int $offset * @return static */ public function nth($step, $offset = 0) { return new static(function () use ($step, $offset) { $position = 0; foreach ($this as $item) { if ($position % $step === $offset) { yield $item; } $position++; } }); } /** * Get the items with the specified keys. * * @param mixed $keys * @return static */ public function only($keys) { if ($keys instanceof Enumerable) { $keys = $keys->all(); } elseif (! is_null($keys)) { $keys = is_array($keys) ? $keys : func_get_args(); } return new static(function () use ($keys) { if (is_null($keys)) { yield from $this; } else { $keys = array_flip($keys); foreach ($this as $key => $value) { if (array_key_exists($key, $keys)) { yield $key => $value; unset($keys[$key]); if (empty($keys)) { break; } } } } }); } /** * Push all of the given items onto the collection. * * @param iterable $source * @return static */ public function concat($source) { return (new static(function () use ($source) { yield from $this; yield from $source; }))->values(); } /** * Get one or a specified number of items randomly from the collection. * * @param int|null $number * @return static|mixed * * @throws \InvalidArgumentException */ public function random($number = null) { $result = $this->collect()->random(...func_get_args()); return is_null($number) ? $result : new static($result); } /** * Reduce the collection to a single value. * * @param callable $callback * @param mixed $initial * @return mixed */ public function reduce(callable $callback, $initial = null) { $result = $initial; foreach ($this as $value) { $result = $callback($result, $value); } return $result; } /** * Replace the collection items with the given items. * * @param mixed $items * @return static */ public function replace($items) { return new static(function () use ($items) { $items = $this->getArrayableItems($items); foreach ($this as $key => $value) { if (array_key_exists($key, $items)) { yield $key => $items[$key]; unset($items[$key]); } else { yield $key => $value; } } foreach ($items as $key => $value) { yield $key => $value; } }); } /** * Recursively replace the collection items with the given items. * * @param mixed $items * @return static */ public function replaceRecursive($items) { return $this->passthru('replaceRecursive', func_get_args()); } /** * Reverse items order. * * @return static */ public function reverse() { return $this->passthru('reverse', func_get_args()); } /** * Search the collection for a given value and return the corresponding key if successful. * * @param mixed $value * @param bool $strict * @return mixed */ public function search($value, $strict = false) { $predicate = $this->useAsCallable($value) ? $value : function ($item) use ($value, $strict) { return $strict ? $item === $value : $item == $value; }; foreach ($this as $key => $item) { if ($predicate($item, $key)) { return $key; } } return false; } /** * Shuffle the items in the collection. * * @param int|null $seed * @return static */ public function shuffle($seed = null) { return $this->passthru('shuffle', func_get_args()); } /** * Skip the first {$count} items. * * @param int $count * @return static */ public function skip($count) { return new static(function () use ($count) { $iterator = $this->getIterator(); while ($iterator->valid() && $count--) { $iterator->next(); } while ($iterator->valid()) { yield $iterator->key() => $iterator->current(); $iterator->next(); } }); } /** * Skip items in the collection until the given condition is met. * * @param mixed $value * @return static */ public function skipUntil($value) { $callback = $this->useAsCallable($value) ? $value : $this->equality($value); return $this->skipWhile($this->negate($callback)); } /** * Skip items in the collection while the given condition is met. * * @param mixed $value * @return static */ public function skipWhile($value) { $callback = $this->useAsCallable($value) ? $value : $this->equality($value); return new static(function () use ($callback) { $iterator = $this->getIterator(); while ($iterator->valid() && $callback($iterator->current(), $iterator->key())) { $iterator->next(); } while ($iterator->valid()) { yield $iterator->key() => $iterator->current(); $iterator->next(); } }); } /** * Get a slice of items from the enumerable. * * @param int $offset * @param int|null $length * @return static */ public function slice($offset, $length = null) { if ($offset < 0 || $length < 0) { return $this->passthru('slice', func_get_args()); } $instance = $this->skip($offset); return is_null($length) ? $instance : $instance->take($length); } /** * Split a collection into a certain number of groups. * * @param int $numberOfGroups * @return static */ public function split($numberOfGroups) { return $this->passthru('split', func_get_args()); } /** * Chunk the collection into chunks of the given size. * * @param int $size * @return static */ public function chunk($size) { if ($size <= 0) { return static::empty(); } return new static(function () use ($size) { $iterator = $this->getIterator(); while ($iterator->valid()) { $chunk = []; while (true) { $chunk[$iterator->key()] = $iterator->current(); if (count($chunk) < $size) { $iterator->next(); if (! $iterator->valid()) { break; } } else { break; } } yield new static($chunk); $iterator->next(); } }); } /** * Sort through each item with a callback. * * @param callable|null|int $callback * @return static */ public function sort($callback = null) { return $this->passthru('sort', func_get_args()); } /** * Sort items in descending order. * * @param int $options * @return static */ public function sortDesc($options = SORT_REGULAR) { return $this->passthru('sortDesc', func_get_args()); } /** * Sort the collection using the given callback. * * @param callable|string $callback * @param int $options * @param bool $descending * @return static */ public function sortBy($callback, $options = SORT_REGULAR, $descending = false) { return $this->passthru('sortBy', func_get_args()); } /** * Sort the collection in descending order using the given callback. * * @param callable|string $callback * @param int $options * @return static */ public function sortByDesc($callback, $options = SORT_REGULAR) { return $this->passthru('sortByDesc', func_get_args()); } /** * Sort the collection keys. * * @param int $options * @param bool $descending * @return static */ public function sortKeys($options = SORT_REGULAR, $descending = false) { return $this->passthru('sortKeys', func_get_args()); } /** * Sort the collection keys in descending order. * * @param int $options * @return static */ public function sortKeysDesc($options = SORT_REGULAR) { return $this->passthru('sortKeysDesc', func_get_args()); } /** * Take the first or last {$limit} items. * * @param int $limit * @return static */ public function take($limit) { if ($limit < 0) { return $this->passthru('take', func_get_args()); } return new static(function () use ($limit) { $iterator = $this->getIterator(); while ($limit--) { if (! $iterator->valid()) { break; } yield $iterator->key() => $iterator->current(); if ($limit) { $iterator->next(); } } }); } /** * Take items in the collection until the given condition is met. * * @param mixed $key * @return static */ public function takeUntil($value) { $callback = $this->useAsCallable($value) ? $value : $this->equality($value); return new static(function () use ($callback) { foreach ($this as $key => $item) { if ($callback($item, $key)) { break; } yield $key => $item; } }); } /** * Take items in the collection while the given condition is met. * * @param mixed $key * @return static */ public function takeWhile($value) { $callback = $this->useAsCallable($value) ? $value : $this->equality($value); return $this->takeUntil($this->negate($callback)); } /** * Pass each item in the collection to the given callback, lazily. * * @param callable $callback * @return static */ public function tapEach(callable $callback) { return new static(function () use ($callback) { foreach ($this as $key => $value) { $callback($value, $key); yield $key => $value; } }); } /** * Reset the keys on the underlying array. * * @return static */ public function values() { return new static(function () { foreach ($this as $item) { yield $item; } }); } /** * Zip the collection together with one or more arrays. * * e.g. new LazyCollection([1, 2, 3])->zip([4, 5, 6]); * => [[1, 4], [2, 5], [3, 6]] * * @param mixed ...$items * @return static */ public function zip($items) { $iterables = func_get_args(); return new static(function () use ($iterables) { $iterators = Collection::make($iterables)->map(function ($iterable) { return $this->makeIterator($iterable); })->prepend($this->getIterator()); while ($iterators->contains->valid()) { yield new static($iterators->map->current()); $iterators->each->next(); } }); } /** * Pad collection to the specified length with a value. * * @param int $size * @param mixed $value * @return static */ public function pad($size, $value) { if ($size < 0) { return $this->passthru('pad', func_get_args()); } return new static(function () use ($size, $value) { $yielded = 0; foreach ($this as $index => $item) { yield $index => $item; $yielded++; } while ($yielded++ < $size) { yield $value; } }); } /** * Get the values iterator. * * @return \Traversable */ public function getIterator() { return $this->makeIterator($this->source); } /** * Count the number of items in the collection. * * @return int */ public function count() { if (is_array($this->source)) { return count($this->source); } return iterator_count($this->getIterator()); } /** * Make an iterator from the given source. * * @param mixed $source * @return \Traversable */ protected function makeIterator($source) { if ($source instanceof IteratorAggregate) { return $source->getIterator(); } if (is_array($source)) { return new ArrayIterator($source); } return $source(); } /** * Explode the "value" and "key" arguments passed to "pluck". * * @param string|array $value * @param string|array|null $key * @return array */ protected function explodePluckParameters($value, $key) { $value = is_string($value) ? explode('.', $value) : $value; $key = is_null($key) || is_array($key) ? $key : explode('.', $key); return [$value, $key]; } /** * Pass this lazy collection through a method on the collection class. * * @param string $method * @param array $params * @return static */ protected function passthru($method, array $params) { return new static(function () use ($method, $params) { yield from $this->collect()->$method(...$params); }); } } support/Composer.php 0000644 00000004526 14736103231 0010567 0 ustar 00 <?php namespace Illuminate\Support; use Illuminate\Filesystem\Filesystem; use Symfony\Component\Process\PhpExecutableFinder; use Symfony\Component\Process\Process; class Composer { /** * The filesystem instance. * * @var \Illuminate\Filesystem\Filesystem */ protected $files; /** * The working path to regenerate from. * * @var string|null */ protected $workingPath; /** * Create a new Composer manager instance. * * @param \Illuminate\Filesystem\Filesystem $files * @param string|null $workingPath * @return void */ public function __construct(Filesystem $files, $workingPath = null) { $this->files = $files; $this->workingPath = $workingPath; } /** * Regenerate the Composer autoloader files. * * @param string|array $extra * @return void */ public function dumpAutoloads($extra = '') { $extra = $extra ? (array) $extra : []; $command = array_merge($this->findComposer(), ['dump-autoload'], $extra); $this->getProcess($command)->run(); } /** * Regenerate the optimized Composer autoloader files. * * @return void */ public function dumpOptimized() { $this->dumpAutoloads('--optimize'); } /** * Get the composer command for the environment. * * @return array */ protected function findComposer() { if ($this->files->exists($this->workingPath.'/composer.phar')) { return [$this->phpBinary(), 'composer.phar']; } return ['composer']; } /** * Get the PHP binary. * * @return string */ protected function phpBinary() { return ProcessUtils::escapeArgument((new PhpExecutableFinder)->find(false)); } /** * Get a new Symfony process instance. * * @param array $command * @return \Symfony\Component\Process\Process */ protected function getProcess(array $command) { return (new Process($command, $this->workingPath))->setTimeout(null); } /** * Set the working path used by the class. * * @param string $path * @return $this */ public function setWorkingPath($path) { $this->workingPath = realpath($path); return $this; } } support/ConfigurationUrlParser.php 0000644 00000010262 14736103231 0013441 0 ustar 00 <?php namespace Illuminate\Support; use InvalidArgumentException; class ConfigurationUrlParser { /** * The drivers aliases map. * * @var array */ protected static $driverAliases = [ 'mssql' => 'sqlsrv', 'mysql2' => 'mysql', // RDS 'postgres' => 'pgsql', 'postgresql' => 'pgsql', 'sqlite3' => 'sqlite', ]; /** * Parse the database configuration, hydrating options using a database configuration URL if possible. * * @param array|string $config * @return array */ public function parseConfiguration($config) { if (is_string($config)) { $config = ['url' => $config]; } $url = Arr::pull($config, 'url'); if (! $url) { return $config; } $parsedUrl = $this->parseUrl($url); return array_merge( $config, $this->getPrimaryOptions($parsedUrl), $this->getQueryOptions($parsedUrl) ); } /** * Get the primary database connection options. * * @param array $url * @return array */ protected function getPrimaryOptions($url) { return array_filter([ 'driver' => $this->getDriver($url), 'database' => $this->getDatabase($url), 'host' => $url['host'] ?? null, 'port' => $url['port'] ?? null, 'username' => $url['user'] ?? null, 'password' => $url['pass'] ?? null, ], function ($value) { return ! is_null($value); }); } /** * Get the database driver from the URL. * * @param array $url * @return string|null */ protected function getDriver($url) { $alias = $url['scheme'] ?? null; if (! $alias) { return; } return static::$driverAliases[$alias] ?? $alias; } /** * Get the database name from the URL. * * @param array $url * @return string|null */ protected function getDatabase($url) { $path = $url['path'] ?? null; return $path && $path !== '/' ? substr($path, 1) : null; } /** * Get all of the additional database options from the query string. * * @param array $url * @return array */ protected function getQueryOptions($url) { $queryString = $url['query'] ?? null; if (! $queryString) { return []; } $query = []; parse_str($queryString, $query); return $this->parseStringsToNativeTypes($query); } /** * Parse the string URL to an array of components. * * @param string $url * @return array * * @throws \InvalidArgumentException */ protected function parseUrl($url) { $url = preg_replace('#^(sqlite3?):///#', '$1://null/', $url); $parsedUrl = parse_url($url); if ($parsedUrl === false) { throw new InvalidArgumentException('The database configuration URL is malformed.'); } return $this->parseStringsToNativeTypes( array_map('rawurldecode', $parsedUrl) ); } /** * Convert string casted values to their native types. * * @param mixed $value * @return mixed */ protected function parseStringsToNativeTypes($value) { if (is_array($value)) { return array_map([$this, 'parseStringsToNativeTypes'], $value); } if (! is_string($value)) { return $value; } $parsedValue = json_decode($value, true); if (json_last_error() === JSON_ERROR_NONE) { return $parsedValue; } return $value; } /** * Get all of the current drivers aliases. * * @return array */ public static function getDriverAliases() { return static::$driverAliases; } /** * Add the given driver alias to the driver aliases array. * * @param string $alias * @param string $driver * @return void */ public static function addDriverAlias($alias, $driver) { static::$driverAliases[$alias] = $driver; } } support/Arr.php 0000644 00000037315 14736103231 0007526 0 ustar 00 <?php namespace Illuminate\Support; use ArrayAccess; use Illuminate\Support\Traits\Macroable; use InvalidArgumentException; class Arr { use Macroable; /** * Determine whether the given value is array accessible. * * @param mixed $value * @return bool */ public static function accessible($value) { return is_array($value) || $value instanceof ArrayAccess; } /** * Add an element to an array using "dot" notation if it doesn't exist. * * @param array $array * @param string $key * @param mixed $value * @return array */ public static function add($array, $key, $value) { if (is_null(static::get($array, $key))) { static::set($array, $key, $value); } return $array; } /** * Collapse an array of arrays into a single array. * * @param iterable $array * @return array */ public static function collapse($array) { $results = []; foreach ($array as $values) { if ($values instanceof Collection) { $values = $values->all(); } elseif (! is_array($values)) { continue; } $results[] = $values; } return array_merge([], ...$results); } /** * Cross join the given arrays, returning all possible permutations. * * @param iterable ...$arrays * @return array */ public static function crossJoin(...$arrays) { $results = [[]]; foreach ($arrays as $index => $array) { $append = []; foreach ($results as $product) { foreach ($array as $item) { $product[$index] = $item; $append[] = $product; } } $results = $append; } return $results; } /** * Divide an array into two arrays. One with keys and the other with values. * * @param array $array * @return array */ public static function divide($array) { return [array_keys($array), array_values($array)]; } /** * Flatten a multi-dimensional associative array with dots. * * @param iterable $array * @param string $prepend * @return array */ public static function dot($array, $prepend = '') { $results = []; foreach ($array as $key => $value) { if (is_array($value) && ! empty($value)) { $results = array_merge($results, static::dot($value, $prepend.$key.'.')); } else { $results[$prepend.$key] = $value; } } return $results; } /** * Get all of the given array except for a specified array of keys. * * @param array $array * @param array|string $keys * @return array */ public static function except($array, $keys) { static::forget($array, $keys); return $array; } /** * Determine if the given key exists in the provided array. * * @param \ArrayAccess|array $array * @param string|int $key * @return bool */ public static function exists($array, $key) { if ($array instanceof ArrayAccess) { return $array->offsetExists($key); } return array_key_exists($key, $array); } /** * Return the first element in an array passing a given truth test. * * @param iterable $array * @param callable|null $callback * @param mixed $default * @return mixed */ public static function first($array, callable $callback = null, $default = null) { if (is_null($callback)) { if (empty($array)) { return value($default); } foreach ($array as $item) { return $item; } } foreach ($array as $key => $value) { if ($callback($value, $key)) { return $value; } } return value($default); } /** * Return the last element in an array passing a given truth test. * * @param array $array * @param callable|null $callback * @param mixed $default * @return mixed */ public static function last($array, callable $callback = null, $default = null) { if (is_null($callback)) { return empty($array) ? value($default) : end($array); } return static::first(array_reverse($array, true), $callback, $default); } /** * Flatten a multi-dimensional array into a single level. * * @param iterable $array * @param int $depth * @return array */ public static function flatten($array, $depth = INF) { $result = []; foreach ($array as $item) { $item = $item instanceof Collection ? $item->all() : $item; if (! is_array($item)) { $result[] = $item; } else { $values = $depth === 1 ? array_values($item) : static::flatten($item, $depth - 1); foreach ($values as $value) { $result[] = $value; } } } return $result; } /** * Remove one or many array items from a given array using "dot" notation. * * @param array $array * @param array|string $keys * @return void */ public static function forget(&$array, $keys) { $original = &$array; $keys = (array) $keys; if (count($keys) === 0) { return; } foreach ($keys as $key) { // if the exact key exists in the top-level, remove it if (static::exists($array, $key)) { unset($array[$key]); continue; } $parts = explode('.', $key); // clean up before each pass $array = &$original; while (count($parts) > 1) { $part = array_shift($parts); if (isset($array[$part]) && is_array($array[$part])) { $array = &$array[$part]; } else { continue 2; } } unset($array[array_shift($parts)]); } } /** * Get an item from an array using "dot" notation. * * @param \ArrayAccess|array $array * @param string|int|null $key * @param mixed $default * @return mixed */ public static function get($array, $key, $default = null) { if (! static::accessible($array)) { return value($default); } if (is_null($key)) { return $array; } if (static::exists($array, $key)) { return $array[$key]; } if (strpos($key, '.') === false) { return $array[$key] ?? value($default); } foreach (explode('.', $key) as $segment) { if (static::accessible($array) && static::exists($array, $segment)) { $array = $array[$segment]; } else { return value($default); } } return $array; } /** * Check if an item or items exist in an array using "dot" notation. * * @param \ArrayAccess|array $array * @param string|array $keys * @return bool */ public static function has($array, $keys) { $keys = (array) $keys; if (! $array || $keys === []) { return false; } foreach ($keys as $key) { $subKeyArray = $array; if (static::exists($array, $key)) { continue; } foreach (explode('.', $key) as $segment) { if (static::accessible($subKeyArray) && static::exists($subKeyArray, $segment)) { $subKeyArray = $subKeyArray[$segment]; } else { return false; } } } return true; } /** * Determine if any of the keys exist in an array using "dot" notation. * * @param \ArrayAccess|array $array * @param string|array $keys * @return bool */ public static function hasAny($array, $keys) { if (is_null($keys)) { return false; } $keys = (array) $keys; if (! $array) { return false; } if ($keys === []) { return false; } foreach ($keys as $key) { if (static::has($array, $key)) { return true; } } return false; } /** * Determines if an array is associative. * * An array is "associative" if it doesn't have sequential numerical keys beginning with zero. * * @param array $array * @return bool */ public static function isAssoc(array $array) { $keys = array_keys($array); return array_keys($keys) !== $keys; } /** * Get a subset of the items from the given array. * * @param array $array * @param array|string $keys * @return array */ public static function only($array, $keys) { return array_intersect_key($array, array_flip((array) $keys)); } /** * Pluck an array of values from an array. * * @param iterable $array * @param string|array $value * @param string|array|null $key * @return array */ public static function pluck($array, $value, $key = null) { $results = []; [$value, $key] = static::explodePluckParameters($value, $key); foreach ($array as $item) { $itemValue = data_get($item, $value); // If the key is "null", we will just append the value to the array and keep // looping. Otherwise we will key the array using the value of the key we // received from the developer. Then we'll return the final array form. if (is_null($key)) { $results[] = $itemValue; } else { $itemKey = data_get($item, $key); if (is_object($itemKey) && method_exists($itemKey, '__toString')) { $itemKey = (string) $itemKey; } $results[$itemKey] = $itemValue; } } return $results; } /** * Explode the "value" and "key" arguments passed to "pluck". * * @param string|array $value * @param string|array|null $key * @return array */ protected static function explodePluckParameters($value, $key) { $value = is_string($value) ? explode('.', $value) : $value; $key = is_null($key) || is_array($key) ? $key : explode('.', $key); return [$value, $key]; } /** * Push an item onto the beginning of an array. * * @param array $array * @param mixed $value * @param mixed $key * @return array */ public static function prepend($array, $value, $key = null) { if (is_null($key)) { array_unshift($array, $value); } else { $array = [$key => $value] + $array; } return $array; } /** * Get a value from the array, and remove it. * * @param array $array * @param string $key * @param mixed $default * @return mixed */ public static function pull(&$array, $key, $default = null) { $value = static::get($array, $key, $default); static::forget($array, $key); return $value; } /** * Get one or a specified number of random values from an array. * * @param array $array * @param int|null $number * @return mixed * * @throws \InvalidArgumentException */ public static function random($array, $number = null) { $requested = is_null($number) ? 1 : $number; $count = count($array); if ($requested > $count) { throw new InvalidArgumentException( "You requested {$requested} items, but there are only {$count} items available." ); } if (is_null($number)) { return $array[array_rand($array)]; } if ((int) $number === 0) { return []; } $keys = array_rand($array, $number); $results = []; foreach ((array) $keys as $key) { $results[] = $array[$key]; } return $results; } /** * Set an array item to a given value using "dot" notation. * * If no key is given to the method, the entire array will be replaced. * * @param array $array * @param string|null $key * @param mixed $value * @return array */ public static function set(&$array, $key, $value) { if (is_null($key)) { return $array = $value; } $keys = explode('.', $key); foreach ($keys as $i => $key) { if (count($keys) === 1) { break; } unset($keys[$i]); // If the key doesn't exist at this depth, we will just create an empty array // to hold the next value, allowing us to create the arrays to hold final // values at the correct depth. Then we'll keep digging into the array. if (! isset($array[$key]) || ! is_array($array[$key])) { $array[$key] = []; } $array = &$array[$key]; } $array[array_shift($keys)] = $value; return $array; } /** * Shuffle the given array and return the result. * * @param array $array * @param int|null $seed * @return array */ public static function shuffle($array, $seed = null) { if (is_null($seed)) { shuffle($array); } else { mt_srand($seed); shuffle($array); mt_srand(); } return $array; } /** * Sort the array using the given callback or "dot" notation. * * @param array $array * @param callable|string|null $callback * @return array */ public static function sort($array, $callback = null) { return Collection::make($array)->sortBy($callback)->all(); } /** * Recursively sort an array by keys and values. * * @param array $array * @return array */ public static function sortRecursive($array) { foreach ($array as &$value) { if (is_array($value)) { $value = static::sortRecursive($value); } } if (static::isAssoc($array)) { ksort($array); } else { sort($array); } return $array; } /** * Convert the array into a query string. * * @param array $array * @return string */ public static function query($array) { return http_build_query($array, null, '&', PHP_QUERY_RFC3986); } /** * Filter the array using the given callback. * * @param array $array * @param callable $callback * @return array */ public static function where($array, callable $callback) { return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH); } /** * If the given value is not an array and not null, wrap it in one. * * @param mixed $value * @return array */ public static function wrap($value) { if (is_null($value)) { return []; } return is_array($value) ? $value : [$value]; } } support/HtmlString.php 0000644 00000001555 14736103231 0011072 0 ustar 00 <?php namespace Illuminate\Support; use Illuminate\Contracts\Support\Htmlable; class HtmlString implements Htmlable { /** * The HTML string. * * @var string */ protected $html; /** * Create a new HTML string instance. * * @param string $html * @return void */ public function __construct($html = '') { $this->html = $html; } /** * Get the HTML string. * * @return string */ public function toHtml() { return $this->html; } /** * Determine if the given HTML string is empty. * * @return bool */ public function isEmpty() { return $this->html === ''; } /** * Get the HTML string. * * @return string */ public function __toString() { return $this->toHtml(); } }