@endsection
diff --git a/src/Illuminate/Foundation/Exceptions/views/503.blade.php b/src/Illuminate/Foundation/Exceptions/views/503.blade.php
index 8272e0e98ef0..d75ae7e7e473 100644
--- a/src/Illuminate/Foundation/Exceptions/views/503.blade.php
+++ b/src/Illuminate/Foundation/Exceptions/views/503.blade.php
@@ -4,7 +4,7 @@
@section('title', __('Service Unavailable'))
@section('image')
-
+
@endsection
diff --git a/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php b/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php
index 4c1c4920ac8e..9c30fdcccf1e 100644
--- a/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php
+++ b/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php
@@ -43,7 +43,7 @@ protected function clean($request)
if ($request->isJson()) {
$this->cleanParameterBag($request->json());
- } else {
+ } elseif ($request->request !== $request->query) {
$this->cleanParameterBag($request->request);
}
}
diff --git a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php
index b12c1799aed7..ce31986a51e9 100644
--- a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php
+++ b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php
@@ -49,8 +49,8 @@ public function registerRequestValidation()
*/
public function registerRequestSignatureValidation()
{
- Request::macro('hasValidSignature', function () {
- return URL::hasValidSignature($this);
+ Request::macro('hasValidSignature', function ($absolute = true) {
+ return URL::hasValidSignature($this, $absolute);
});
}
}
diff --git a/src/Illuminate/Foundation/Testing/Concerns/MocksApplicationServices.php b/src/Illuminate/Foundation/Testing/Concerns/MocksApplicationServices.php
index 1ad4be4d8ed0..a6e51d493e95 100644
--- a/src/Illuminate/Foundation/Testing/Concerns/MocksApplicationServices.php
+++ b/src/Illuminate/Foundation/Testing/Concerns/MocksApplicationServices.php
@@ -175,7 +175,7 @@ protected function doesntExpectJobs($jobs)
*/
protected function withoutJobs()
{
- $mock = Mockery::mock(BusDispatcherContract::class);
+ $mock = Mockery::mock(BusDispatcherContract::class)->shouldIgnoreMissing();
$mock->shouldReceive('dispatch', 'dispatchNow')->andReturnUsing(function ($dispatched) {
$this->dispatchedJobs[] = $dispatched;
diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php
index 1b200624a8ab..123df898f20d 100644
--- a/src/Illuminate/Foundation/helpers.php
+++ b/src/Illuminate/Foundation/helpers.php
@@ -609,10 +609,14 @@ function mix($path, $manifestDirectory = '')
$manifest = $manifests[$manifestPath];
if (! isset($manifest[$path])) {
- report(new Exception("Unable to locate Mix file: {$path}."));
+ $exception = new Exception("Unable to locate Mix file: {$path}.");
if (! app('config')->get('app.debug')) {
+ report($exception);
+
return $path;
+ } else {
+ throw $exception;
}
}
diff --git a/src/Illuminate/Log/LogManager.php b/src/Illuminate/Log/LogManager.php
index ac5942b22bb4..bd3718810279 100644
--- a/src/Illuminate/Log/LogManager.php
+++ b/src/Illuminate/Log/LogManager.php
@@ -270,8 +270,10 @@ protected function createSlackDriver(array $config)
$config['emoji'] ?? ':boom:',
$config['short'] ?? false,
$config['context'] ?? true,
- $this->level($config)
- )),
+ $this->level($config),
+ $config['bubble'] ?? true,
+ $config['exclude_fields'] ?? []
+ ), $config),
]);
}
diff --git a/src/Illuminate/Queue/Jobs/RedisJob.php b/src/Illuminate/Queue/Jobs/RedisJob.php
index d7059fd9753a..34e4fea0aef7 100644
--- a/src/Illuminate/Queue/Jobs/RedisJob.php
+++ b/src/Illuminate/Queue/Jobs/RedisJob.php
@@ -120,7 +120,7 @@ public function getJobId()
/**
* Get the underlying Redis factory implementation.
*
- * @return \Illuminate\Contracts\Redis\Factory
+ * @return \Illuminate\Queue\RedisQueue
*/
public function getRedisQueue()
{
diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php
index c3f08953405b..83dabfe4973e 100644
--- a/src/Illuminate/Routing/Router.php
+++ b/src/Illuminate/Routing/Router.php
@@ -1155,10 +1155,12 @@ public function auth(array $options = [])
}
// Password Reset Routes...
- $this->get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request');
- $this->post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email');
- $this->get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset');
- $this->post('password/reset', 'Auth\ResetPasswordController@reset')->name('password.update');
+ if ($options['reset'] ?? true) {
+ $this->get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request');
+ $this->post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email');
+ $this->get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset');
+ $this->post('password/reset', 'Auth\ResetPasswordController@reset')->name('password.update');
+ }
// Email Verification Routes...
if ($options['verify'] ?? false) {
diff --git a/src/Illuminate/Support/Collection.php b/src/Illuminate/Support/Collection.php
index 4f25bacc05ce..f3449cb83ac3 100644
--- a/src/Illuminate/Support/Collection.php
+++ b/src/Illuminate/Support/Collection.php
@@ -58,7 +58,7 @@ class Collection implements ArrayAccess, Arrayable, Countable, IteratorAggregate
protected static $proxies = [
'average', 'avg', 'contains', 'each', 'every', 'filter', 'first',
'flatMap', 'groupBy', 'keyBy', 'map', 'max', 'min', 'partition',
- 'reject', 'sortBy', 'sortByDesc', 'sum', 'unique',
+ 'reject', 'some', 'sortBy', 'sortByDesc', 'sum', 'unique',
];
/**
@@ -238,6 +238,19 @@ public function collapse()
return new static(Arr::collapse($this->items));
}
+ /**
+ * 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($key, $operator, $value);
+ }
+
/**
* Determine if an item exists in the collection.
*
@@ -501,6 +514,32 @@ public function when($value, callable $callback, callable $default = null)
return $this;
}
+ /**
+ * Apply the callback if the collection is empty.
+ *
+ * @param bool $value
+ * @param callable $callback
+ * @param callable $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 bool $value
+ * @param callable $callback
+ * @param callable $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.
*
@@ -514,6 +553,32 @@ public function unless($value, callable $callback, callable $default = null)
return $this->when(! $value, $callback, $default);
}
+ /**
+ * Apply the callback unless the collection is empty.
+ *
+ * @param bool $value
+ * @param callable $callback
+ * @param callable $default
+ * @return static|mixed
+ */
+ public function unlessEmpty(callable $callback, callable $default = null)
+ {
+ return $this->unless($this->isEmpty(), $callback, $default);
+ }
+
+ /**
+ * Apply the callback unless the collection is not empty.
+ *
+ * @param bool $value
+ * @param callable $callback
+ * @param callable $default
+ * @return static|mixed
+ */
+ public function unlessNotEmpty(callable $callback, callable $default = null)
+ {
+ return $this->unless($this->isNotEmpty(), $callback, $default);
+ }
+
/**
* Filter items by the given key value pair.
*
diff --git a/src/Illuminate/Support/Facades/Cache.php b/src/Illuminate/Support/Facades/Cache.php
index 6be6f13d52d6..67022817cf01 100755
--- a/src/Illuminate/Support/Facades/Cache.php
+++ b/src/Illuminate/Support/Facades/Cache.php
@@ -5,6 +5,7 @@
/**
* @method static \Illuminate\Contracts\Cache\Repository store(string|null $name = null)
* @method static bool has(string $key)
+ * @method static bool missing(string $key)
* @method static mixed get(string $key, mixed $default = null)
* @method static mixed pull(string $key, mixed $default = null)
* @method static void put(string $key, $value, \DateTimeInterface|\DateInterval|float|int $minutes)
diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php
index 911c0be2b819..21387d9908a2 100755
--- a/src/Illuminate/Validation/Validator.php
+++ b/src/Illuminate/Validation/Validator.php
@@ -547,9 +547,13 @@ protected function validateUsingCustomRule($attribute, $value, $rule)
if (! $rule->passes($attribute, $value)) {
$this->failedRules[$attribute][get_class($rule)] = [];
- $this->messages->add($attribute, $this->makeReplacements(
- $rule->message(), $attribute, get_class($rule), []
- ));
+ $messages = (array) $rule->message();
+
+ foreach ($messages as $message) {
+ $this->messages->add($attribute, $this->makeReplacements(
+ $message, $attribute, get_class($rule), []
+ ));
+ }
}
}
diff --git a/src/Illuminate/View/Factory.php b/src/Illuminate/View/Factory.php
index 7918155df30e..201486034ce6 100755
--- a/src/Illuminate/View/Factory.php
+++ b/src/Illuminate/View/Factory.php
@@ -5,6 +5,7 @@
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use InvalidArgumentException;
+use Illuminate\Support\Traits\Macroable;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\View\Engines\EngineResolver;
@@ -13,7 +14,8 @@
class Factory implements FactoryContract
{
- use Concerns\ManagesComponents,
+ use Macroable,
+ Concerns\ManagesComponents,
Concerns\ManagesEvents,
Concerns\ManagesLayouts,
Concerns\ManagesLoops,
diff --git a/tests/Auth/AuthAccessGateTest.php b/tests/Auth/AuthAccessGateTest.php
index 0a2cdd480846..f95b0b63400e 100644
--- a/tests/Auth/AuthAccessGateTest.php
+++ b/tests/Auth/AuthAccessGateTest.php
@@ -373,6 +373,24 @@ public function test_invokable_classes_can_be_defined()
$this->assertTrue($gate->check('foo'));
}
+ public function test_gates_can_be_defined_using_an_array_callback()
+ {
+ $gate = $this->getBasicGate();
+
+ $gate->define('foo', [new AccessGateTestStaticClass, 'foo']);
+
+ $this->assertTrue($gate->check('foo'));
+ }
+
+ public function test_gates_can_be_defined_using_an_array_callback_with_static_method()
+ {
+ $gate = $this->getBasicGate();
+
+ $gate->define('foo', [AccessGateTestStaticClass::class, 'foo']);
+
+ $this->assertTrue($gate->check('foo'));
+ }
+
public function test_policy_classes_can_be_defined_to_handle_checks_for_given_type()
{
$gate = $this->getBasicGate();
@@ -480,7 +498,7 @@ public function test_for_user_method_attaches_a_new_user_to_a_new_gate_instance(
* @dataProvider notCallableDataProvider
* @expectedException \InvalidArgumentException
*/
- public function test_define_second_parametter_should_be_string_or_callable($callback)
+ public function test_define_second_parameter_should_be_string_or_callable($callback)
{
$gate = $this->getBasicGate();
@@ -638,6 +656,14 @@ public function hasAbilitiesTestDataProvider()
}
}
+class AccessGateTestStaticClass
+{
+ public static function foo()
+ {
+ return true;
+ }
+}
+
class AccessGateTestClass
{
public function foo()
diff --git a/tests/Cache/CacheRepositoryTest.php b/tests/Cache/CacheRepositoryTest.php
index 4be76ad9bf59..b88cafec0f45 100755
--- a/tests/Cache/CacheRepositoryTest.php
+++ b/tests/Cache/CacheRepositoryTest.php
@@ -71,6 +71,16 @@ public function testHasMethod()
$this->assertFalse($repo->has('foo'));
}
+ public function testMissingMethod()
+ {
+ $repo = $this->getRepository();
+ $repo->getStore()->shouldReceive('get')->once()->with('foo')->andReturn(null);
+ $repo->getStore()->shouldReceive('get')->once()->with('bar')->andReturn('bar');
+
+ $this->assertTrue($repo->missing('foo'));
+ $this->assertFalse($repo->missing('bar'));
+ }
+
public function testRememberMethodCallsPutAndReturnsDefault()
{
$repo = $this->getRepository();
diff --git a/tests/Cookie/CookieTest.php b/tests/Cookie/CookieTest.php
index d37442e19f2b..8ee3bee5e716 100755
--- a/tests/Cookie/CookieTest.php
+++ b/tests/Cookie/CookieTest.php
@@ -88,6 +88,15 @@ public function testUnqueue()
$this->assertEmpty($cookie->getQueuedCookies());
}
+ public function testCookieJarIsMacroable()
+ {
+ $cookie = $this->getCreator();
+ $cookie->macro('foo', function () {
+ return 'bar';
+ });
+ $this->assertEquals('bar', $cookie->foo());
+ }
+
public function getCreator()
{
return new CookieJar(Request::create('/foo', 'GET'), [
diff --git a/tests/Database/DatabaseEloquentBelongsToTest.php b/tests/Database/DatabaseEloquentBelongsToTest.php
index 602aeaacea9d..0d3c64d3f8dd 100755
--- a/tests/Database/DatabaseEloquentBelongsToTest.php
+++ b/tests/Database/DatabaseEloquentBelongsToTest.php
@@ -79,7 +79,9 @@ public function testUpdateMethodRetrievesModelAndUpdates()
public function testEagerConstraintsAreProperlyAdded()
{
$relation = $this->getRelation();
- $relation->getQuery()->shouldReceive('whereIn')->once()->with('relation.id', ['foreign.value', 'foreign.value.two']);
+ $relation->getRelated()->shouldReceive('getKeyName')->andReturn('id');
+ $relation->getRelated()->shouldReceive('getKeyType')->andReturn('int');
+ $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('relation.id', ['foreign.value', 'foreign.value.two']);
$models = [new EloquentBelongsToModelStub, new EloquentBelongsToModelStub, new AnotherEloquentBelongsToModelStub];
$relation->addEagerConstraints($models);
}
@@ -87,7 +89,9 @@ public function testEagerConstraintsAreProperlyAdded()
public function testIdsInEagerConstraintsCanBeZero()
{
$relation = $this->getRelation();
- $relation->getQuery()->shouldReceive('whereIn')->once()->with('relation.id', ['foreign.value', 0]);
+ $relation->getRelated()->shouldReceive('getKeyName')->andReturn('id');
+ $relation->getRelated()->shouldReceive('getKeyType')->andReturn('int');
+ $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('relation.id', ['foreign.value', 0]);
$models = [new EloquentBelongsToModelStub, new EloquentBelongsToModelStubWithZeroId];
$relation->addEagerConstraints($models);
}
@@ -154,7 +158,9 @@ public function testAssociateMethodSetsForeignKeyOnModelById()
public function testDefaultEagerConstraintsWhenIncrementing()
{
$relation = $this->getRelation();
- $relation->getQuery()->shouldReceive('whereIn')->once()->with('relation.id', m::mustBe([null]));
+ $relation->getRelated()->shouldReceive('getKeyName')->andReturn('id');
+ $relation->getRelated()->shouldReceive('getKeyType')->andReturn('int');
+ $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('relation.id', m::mustBe([null]));
$models = [new MissingEloquentBelongsToModelStub, new MissingEloquentBelongsToModelStub];
$relation->addEagerConstraints($models);
}
@@ -170,7 +176,9 @@ public function testDefaultEagerConstraintsWhenIncrementingAndNonIntKeyType()
public function testDefaultEagerConstraintsWhenNotIncrementing()
{
$relation = $this->getRelation(null, false);
- $relation->getQuery()->shouldReceive('whereIn')->once()->with('relation.id', m::mustBe([null]));
+ $relation->getRelated()->shouldReceive('getKeyName')->andReturn('id');
+ $relation->getRelated()->shouldReceive('getKeyType')->andReturn('int');
+ $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('relation.id', m::mustBe([null]));
$models = [new MissingEloquentBelongsToModelStub, new MissingEloquentBelongsToModelStub];
$relation->addEagerConstraints($models);
}
diff --git a/tests/Database/DatabaseEloquentHasManyTest.php b/tests/Database/DatabaseEloquentHasManyTest.php
index f2ce97b81dbd..71a979b3fd86 100755
--- a/tests/Database/DatabaseEloquentHasManyTest.php
+++ b/tests/Database/DatabaseEloquentHasManyTest.php
@@ -200,6 +200,21 @@ public function testRelationIsProperlyInitialized()
public function testEagerConstraintsAreProperlyAdded()
{
$relation = $this->getRelation();
+ $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id');
+ $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int');
+ $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('table.foreign_key', [1, 2]);
+ $model1 = new EloquentHasManyModelStub;
+ $model1->id = 1;
+ $model2 = new EloquentHasManyModelStub;
+ $model2->id = 2;
+ $relation->addEagerConstraints([$model1, $model2]);
+ }
+
+ public function testEagerConstraintsAreProperlyAddedWithStringKey()
+ {
+ $relation = $this->getRelation();
+ $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id');
+ $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('string');
$relation->getQuery()->shouldReceive('whereIn')->once()->with('table.foreign_key', [1, 2]);
$model1 = new EloquentHasManyModelStub;
$model1->id = 1;
diff --git a/tests/Database/DatabaseEloquentHasOneTest.php b/tests/Database/DatabaseEloquentHasOneTest.php
index f7bc4d74533a..319919c26f7c 100755
--- a/tests/Database/DatabaseEloquentHasOneTest.php
+++ b/tests/Database/DatabaseEloquentHasOneTest.php
@@ -163,7 +163,9 @@ public function testRelationIsProperlyInitialized()
public function testEagerConstraintsAreProperlyAdded()
{
$relation = $this->getRelation();
- $relation->getQuery()->shouldReceive('whereIn')->once()->with('table.foreign_key', [1, 2]);
+ $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id');
+ $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int');
+ $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('table.foreign_key', [1, 2]);
$model1 = new EloquentHasOneModelStub;
$model1->id = 1;
$model2 = new EloquentHasOneModelStub;
diff --git a/tests/Database/DatabaseEloquentMorphTest.php b/tests/Database/DatabaseEloquentMorphTest.php
index 92999f432a81..ab84e85a890a 100755
--- a/tests/Database/DatabaseEloquentMorphTest.php
+++ b/tests/Database/DatabaseEloquentMorphTest.php
@@ -28,6 +28,8 @@ public function testMorphOneSetsProperConstraints()
public function testMorphOneEagerConstraintsAreProperlyAdded()
{
$relation = $this->getOneRelation();
+ $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id');
+ $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('string');
$relation->getQuery()->shouldReceive('whereIn')->once()->with('table.morph_id', [1, 2]);
$relation->getQuery()->shouldReceive('where')->once()->with('table.morph_type', get_class($relation->getParent()));
@@ -50,7 +52,9 @@ public function testMorphManySetsProperConstraints()
public function testMorphManyEagerConstraintsAreProperlyAdded()
{
$relation = $this->getManyRelation();
- $relation->getQuery()->shouldReceive('whereIn')->once()->with('table.morph_id', [1, 2]);
+ $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id');
+ $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int');
+ $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('table.morph_id', [1, 2]);
$relation->getQuery()->shouldReceive('where')->once()->with('table.morph_type', get_class($relation->getParent()));
$model1 = new EloquentMorphResetModelStub;
diff --git a/tests/Database/DatabaseEloquentMorphToManyTest.php b/tests/Database/DatabaseEloquentMorphToManyTest.php
index 761429aac6b4..95ab8a37c08e 100644
--- a/tests/Database/DatabaseEloquentMorphToManyTest.php
+++ b/tests/Database/DatabaseEloquentMorphToManyTest.php
@@ -18,7 +18,9 @@ public function tearDown()
public function testEagerConstraintsAreProperlyAdded()
{
$relation = $this->getRelation();
- $relation->getQuery()->shouldReceive('whereIn')->once()->with('taggables.taggable_id', [1, 2]);
+ $relation->getParent()->shouldReceive('getKeyName')->andReturn('id');
+ $relation->getParent()->shouldReceive('getKeyType')->andReturn('int');
+ $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('taggables.taggable_id', [1, 2]);
$relation->getQuery()->shouldReceive('where')->once()->with('taggables.taggable_type', get_class($relation->getParent()));
$model1 = new EloquentMorphToManyModelStub;
$model1->id = 1;
diff --git a/tests/Database/DatabaseMigrationMakeCommandTest.php b/tests/Database/DatabaseMigrationMakeCommandTest.php
index 3481c31d5f23..1e34388da41c 100755
--- a/tests/Database/DatabaseMigrationMakeCommandTest.php
+++ b/tests/Database/DatabaseMigrationMakeCommandTest.php
@@ -27,7 +27,7 @@ public function testBasicCreateDumpsAutoload()
$app = new Application;
$app->useDatabasePath(__DIR__);
$command->setLaravel($app);
- $creator->shouldReceive('create')->once()->with('create_foo', __DIR__.DIRECTORY_SEPARATOR.'migrations', null, false);
+ $creator->shouldReceive('create')->once()->with('create_foo', __DIR__.DIRECTORY_SEPARATOR.'migrations', 'foo', true);
$composer->shouldReceive('dumpAutoloads')->once();
$this->runCommand($command, ['name' => 'create_foo']);
@@ -42,7 +42,7 @@ public function testBasicCreateGivesCreatorProperArguments()
$app = new Application;
$app->useDatabasePath(__DIR__);
$command->setLaravel($app);
- $creator->shouldReceive('create')->once()->with('create_foo', __DIR__.DIRECTORY_SEPARATOR.'migrations', null, false);
+ $creator->shouldReceive('create')->once()->with('create_foo', __DIR__.DIRECTORY_SEPARATOR.'migrations', 'foo', true);
$this->runCommand($command, ['name' => 'create_foo']);
}
@@ -56,7 +56,7 @@ public function testBasicCreateGivesCreatorProperArgumentsWhenNameIsStudlyCase()
$app = new Application;
$app->useDatabasePath(__DIR__);
$command->setLaravel($app);
- $creator->shouldReceive('create')->once()->with('create_foo', __DIR__.DIRECTORY_SEPARATOR.'migrations', null, false);
+ $creator->shouldReceive('create')->once()->with('create_foo', __DIR__.DIRECTORY_SEPARATOR.'migrations', 'foo', true);
$this->runCommand($command, ['name' => 'CreateFoo']);
}
diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php
index 952eafd20d4f..70b462b1331c 100755
--- a/tests/Database/DatabaseQueryBuilderTest.php
+++ b/tests/Database/DatabaseQueryBuilderTest.php
@@ -693,6 +693,14 @@ public function testEmptyWhereNotIns()
$this->assertEquals([0 => 1], $builder->getBindings());
}
+ public function testWhereInRaw()
+ {
+ $builder = $this->getBuilder();
+ $builder->select('*')->from('users')->whereInRaw('id', ['1a', 2]);
+ $this->assertEquals('select * from "users" where "id" in (1, 2)', $builder->toSql());
+ $this->assertEquals([], $builder->getBindings());
+ }
+
public function testBasicWhereColumn()
{
$builder = $this->getBuilder();
@@ -827,6 +835,39 @@ public function testMySqlUnionLimitsAndOffsets()
$this->assertEquals('(select * from `users`) union (select * from `dogs`) limit 10 offset 5', $builder->toSql());
}
+ public function testUnionAggregate()
+ {
+ $expected = 'select count(*) as aggregate from ((select * from `posts`) union (select * from `videos`)) as `temp_table`';
+ $builder = $this->getMySqlBuilder();
+ $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true);
+ $builder->getProcessor()->shouldReceive('processSelect')->once();
+ $builder->from('posts')->union($this->getMySqlBuilder()->from('videos'))->count();
+
+ $expected = 'select count(*) as aggregate from ((select `id` from `posts`) union (select `id` from `videos`)) as `temp_table`';
+ $builder = $this->getMySqlBuilder();
+ $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true);
+ $builder->getProcessor()->shouldReceive('processSelect')->once();
+ $builder->from('posts')->select('id')->union($this->getMySqlBuilder()->from('videos')->select('id'))->count();
+
+ $expected = 'select count(*) as aggregate from (select * from "posts" union select * from "videos") as "temp_table"';
+ $builder = $this->getPostgresBuilder();
+ $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true);
+ $builder->getProcessor()->shouldReceive('processSelect')->once();
+ $builder->from('posts')->union($this->getPostgresBuilder()->from('videos'))->count();
+
+ $expected = 'select count(*) as aggregate from (select * from (select * from "posts") union select * from (select * from "videos")) as "temp_table"';
+ $builder = $this->getSQLiteBuilder();
+ $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true);
+ $builder->getProcessor()->shouldReceive('processSelect')->once();
+ $builder->from('posts')->union($this->getSQLiteBuilder()->from('videos'))->count();
+
+ $expected = 'select count(*) as aggregate from (select * from [posts] union select * from [videos]) as [temp_table]';
+ $builder = $this->getSqlServerBuilder();
+ $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true);
+ $builder->getProcessor()->shouldReceive('processSelect')->once();
+ $builder->from('posts')->union($this->getSqlServerBuilder()->from('videos'))->count();
+ }
+
public function testSubSelectWhereIns()
{
$builder = $this->getBuilder();
@@ -1060,6 +1101,20 @@ public function testGetCountForPaginationWithColumnAliases()
$this->assertEquals(1, $count);
}
+ public function testGetCountForPaginationWithUnion()
+ {
+ $builder = $this->getBuilder();
+ $builder->from('posts')->select('id')->union($this->getBuilder()->from('videos')->select('id'));
+
+ $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from (select "id" from "posts" union select "id" from "videos") as "temp_table"', [], true)->andReturn([['aggregate' => 1]]);
+ $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) {
+ return $results;
+ });
+
+ $count = $builder->getCountForPagination();
+ $this->assertEquals(1, $count);
+ }
+
public function testWhereShortcut()
{
$builder = $this->getBuilder();
diff --git a/tests/Database/TableGuesserTest.php b/tests/Database/TableGuesserTest.php
index 6a6aecaa97c2..0a8bd2434c91 100644
--- a/tests/Database/TableGuesserTest.php
+++ b/tests/Database/TableGuesserTest.php
@@ -17,8 +17,31 @@ public function test_migration_is_properly_parsed()
$this->assertEquals('users', $table);
$this->assertFalse($create);
+ [$table, $create] = TableGuesser::guess('change_status_column_in_users_table');
+ $this->assertEquals('users', $table);
+ $this->assertFalse($create);
+
[$table, $create] = TableGuesser::guess('drop_status_column_from_users_table');
$this->assertEquals('users', $table);
$this->assertFalse($create);
}
+
+ public function test_migration_is_properly_parsed_without_table_suffix()
+ {
+ [$table, $create] = TableGuesser::guess('create_users');
+ $this->assertEquals('users', $table);
+ $this->assertTrue($create);
+
+ [$table, $create] = TableGuesser::guess('add_status_column_to_users');
+ $this->assertEquals('users', $table);
+ $this->assertFalse($create);
+
+ [$table, $create] = TableGuesser::guess('change_status_column_in_users');
+ $this->assertEquals('users', $table);
+ $this->assertFalse($create);
+
+ [$table, $create] = TableGuesser::guess('drop_status_column_from_users');
+ $this->assertEquals('users', $table);
+ $this->assertFalse($create);
+ }
}
diff --git a/tests/Foundation/FoundationHelpersTest.php b/tests/Foundation/FoundationHelpersTest.php
index 441ccba4b3be..3539a5af4c21 100644
--- a/tests/Foundation/FoundationHelpersTest.php
+++ b/tests/Foundation/FoundationHelpersTest.php
@@ -65,22 +65,175 @@ public function testUnversionedElixir()
public function testMixDoesNotIncludeHost()
{
- $file = 'unversioned.css';
+ $manifest = $this->makeManifest();
+
+ $result = mix('/unversioned.css');
+
+ $this->assertSame('/versioned.css', $result->toHtml());
+
+ unlink($manifest);
+ }
+
+ public function testMixCachesManifestForSubsequentCalls()
+ {
+ $manifest = $this->makeManifest();
+ mix('unversioned.css');
+ unlink($manifest);
+
+ $result = mix('/unversioned.css');
+
+ $this->assertSame('/versioned.css', $result->toHtml());
+ }
+
+ public function testMixAssetMissingStartingSlashHaveItAdded()
+ {
+ $manifest = $this->makeManifest();
+
+ $result = mix('unversioned.css');
+
+ $this->assertSame('/versioned.css', $result->toHtml());
+
+ unlink($manifest);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage The Mix manifest does not exist.
+ */
+ public function testMixMissingManifestThrowsException()
+ {
+ mix('unversioned.css', 'missing');
+ }
+
+ public function testMixWithManifestDirectory()
+ {
+ mkdir($directory = __DIR__.'/mix');
+ $manifest = $this->makeManifest('mix');
+
+ $result = mix('unversioned.css', 'mix');
+
+ $this->assertSame('/mix/versioned.css', $result->toHtml());
+
+ unlink($manifest);
+ rmdir($directory);
+ }
+
+ public function testMixManifestDirectoryMissingStartingSlashHasItAdded()
+ {
+ mkdir($directory = __DIR__.'/mix');
+ $manifest = $this->makeManifest('/mix');
+
+ $result = mix('unversioned.css', 'mix');
+
+ $this->assertSame('/mix/versioned.css', $result->toHtml());
+
+ unlink($manifest);
+ rmdir($directory);
+ }
+
+ public function testMixHotModuleReloadingGetsUrlFromFileWithHttps()
+ {
+ $path = $this->makeHotModuleReloadFile('https://laravel.com/docs');
+
+ $result = mix('unversioned.css');
+
+ $this->assertSame('//laravel.com/docs/unversioned.css', $result->toHtml());
+
+ unlink($path);
+ }
+ public function testMixHotModuleReloadingGetsUrlFromFileWithHttp()
+ {
+ $path = $this->makeHotModuleReloadFile('http://laravel.com/docs');
+
+ $result = mix('unversioned.css');
+
+ $this->assertSame('//laravel.com/docs/unversioned.css', $result->toHtml());
+
+ unlink($path);
+ }
+
+ public function testMixHotModuleReloadingGetsUrlFromFileWithManifestDirectoryAndHttps()
+ {
+ mkdir($directory = __DIR__.'/mix');
+ $path = $this->makeHotModuleReloadFile('https://laravel.com/docs', 'mix');
+
+ $result = mix('unversioned.css', 'mix');
+
+ $this->assertSame('//laravel.com/docs/unversioned.css', $result->toHtml());
+
+ unlink($path);
+ rmdir($directory);
+ }
+
+ public function testMixHotModuleReloadingGetsUrlFromFileWithManifestDirectoryAndHttp()
+ {
+ mkdir($directory = __DIR__.'/mix');
+ $path = $this->makeHotModuleReloadFile('http://laravel.com/docs', 'mix');
+
+ $result = mix('unversioned.css', 'mix');
+
+ $this->assertSame('//laravel.com/docs/unversioned.css', $result->toHtml());
+
+ unlink($path);
+ rmdir($directory);
+ }
+
+ public function testMixHotModuleReloadingUsesLocalhostIfNoHttpScheme()
+ {
+ $path = $this->makeHotModuleReloadFile('');
+
+ $result = mix('unversioned.css');
+
+ $this->assertSame('//localhost:8080/unversioned.css', $result->toHtml());
+
+ unlink($path);
+ }
+
+ public function testMixHotModuleReloadingWithManifestDirectoryUsesLocalhostIfNoHttpScheme()
+ {
+ mkdir($directory = __DIR__.'/mix');
+ $path = $this->makeHotModuleReloadFile('', 'mix');
+
+ $result = mix('unversioned.css', 'mix');
+
+ $this->assertSame('//localhost:8080/unversioned.css', $result->toHtml());
+
+ unlink($path);
+ rmdir($directory);
+ }
+
+ protected function makeHotModuleReloadFile($url, $directory = '')
+ {
+ app()->singleton('path.public', function () {
+ return __DIR__;
+ });
+
+ $path = public_path(str_finish($directory, '/').'hot');
+
+ // Laravel mix when run 'hot' has a new line after the
+ // url, so for consistency this "\n" is added.
+ file_put_contents($path, "{$url}\n");
+
+ return $path;
+ }
+
+ protected function makeManifest($directory = '')
+ {
app()->singleton('path.public', function () {
return __DIR__;
});
- touch(public_path('mix-manifest.json'));
+ $path = public_path(str_finish($directory, '/').'mix-manifest.json');
- file_put_contents(public_path('mix-manifest.json'), json_encode([
- '/unversioned.css' => '/versioned.css',
- ]));
+ touch($path);
- $result = mix($file);
+ // Laravel mix prints JSON pretty and with escaped
+ // slashes, so we are doing that here for consistency.
+ $content = json_encode(['/unversioned.css' => '/versioned.css'], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
- $this->assertEquals('/versioned.css', $result);
+ file_put_contents($path, $content);
- unlink(public_path('mix-manifest.json'));
+ return $path;
}
}
diff --git a/tests/Foundation/Http/Middleware/TransformsRequestTest.php b/tests/Foundation/Http/Middleware/TransformsRequestTest.php
index 6bd555d314cb..f73dd7b8f8fd 100644
--- a/tests/Foundation/Http/Middleware/TransformsRequestTest.php
+++ b/tests/Foundation/Http/Middleware/TransformsRequestTest.php
@@ -5,19 +5,38 @@
use Illuminate\Http\Request;
use PHPUnit\Framework\TestCase;
use Illuminate\Foundation\Http\Middleware\TransformsRequest;
+use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
class TransformsRequestTest extends TestCase
{
- public function testLowerAgeAndAddBeer()
+ public function testTransformOncePerKeyWhenMethodIsGet()
+ {
+ $middleware = new TruncateInput;
+ $symfonyRequest = new SymfonyRequest([
+ 'bar' => '123',
+ 'baz' => 'abc',
+ ]);
+ $symfonyRequest->server->set('REQUEST_METHOD', 'GET');
+ $request = Request::createFromBase($symfonyRequest);
+
+ $middleware->handle($request, function (Request $request) {
+ $this->assertEquals('12', $request->get('bar'));
+ $this->assertEquals('ab', $request->get('baz'));
+ });
+ }
+
+ public function testTransformOncePerKeyWhenMethodIsPost()
{
$middleware = new ManipulateInput;
- $request = new Request(
+ $symfonyRequest = new SymfonyRequest(
[
'name' => 'Damian',
'beers' => 4,
],
['age' => 28]
);
+ $symfonyRequest->server->set('REQUEST_METHOD', 'POST');
+ $request = Request::createFromBase($symfonyRequest);
$middleware->handle($request, function (Request $request) {
$this->assertEquals('Damian', $request->get('name'));
@@ -26,10 +45,10 @@ public function testLowerAgeAndAddBeer()
});
}
- public function testAjaxLowerAgeAndAddBeer()
+ public function testTransformOncePerKeyWhenContentTypeIsJson()
{
$middleware = new ManipulateInput;
- $request = new Request(
+ $symfonyRequest = new SymfonyRequest(
[
'name' => 'Damian',
'beers' => 4,
@@ -41,6 +60,8 @@ public function testAjaxLowerAgeAndAddBeer()
['CONTENT_TYPE' => '/json'],
json_encode(['age' => 28])
);
+ $symfonyRequest->server->set('REQUEST_METHOD', 'GET');
+ $request = Request::createFromBase($symfonyRequest);
$middleware->handle($request, function (Request $request) {
$this->assertEquals('Damian', $request->input('name'));
@@ -64,3 +85,11 @@ protected function transform($key, $value)
return $value;
}
}
+
+class TruncateInput extends TransformsRequest
+{
+ protected function transform($key, $value)
+ {
+ return substr($value, 0, -1);
+ }
+}
diff --git a/tests/Integration/Foundation/FoundationHelpersTest.php b/tests/Integration/Foundation/FoundationHelpersTest.php
index 8ba83ad9ef59..a44d34e2bb1e 100644
--- a/tests/Integration/Foundation/FoundationHelpersTest.php
+++ b/tests/Integration/Foundation/FoundationHelpersTest.php
@@ -4,6 +4,8 @@
use Exception;
use Orchestra\Testbench\TestCase;
+use Illuminate\Support\Facades\Route;
+use Illuminate\Contracts\Debug\ExceptionHandler;
/**
* @group integration
@@ -37,4 +39,99 @@ public function test(int $a)
$testClass->test([]);
}, 'rescued!'), 'rescued!');
}
+
+ public function testMixReportsExceptionWhenAssetIsMissingFromManifest()
+ {
+ $handler = new FakeHandler;
+ $this->app->instance(ExceptionHandler::class, $handler);
+ $manifest = $this->makeManifest();
+
+ mix('missing.js');
+
+ $this->assertInstanceOf(Exception::class, $handler->reported[0]);
+ $this->assertSame('Unable to locate Mix file: /missing.js.', $handler->reported[0]->getMessage());
+
+ unlink($manifest);
+ }
+
+ public function testMixSilentlyFailsWhenAssetIsMissingFromManifestWhenNotInDebugMode()
+ {
+ $this->app['config']->set('app.debug', false);
+ $manifest = $this->makeManifest();
+
+ $path = mix('missing.js');
+
+ $this->assertSame('/missing.js', $path);
+
+ unlink($manifest);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage Unable to locate Mix file: /missing.js.
+ */
+ public function testMixThrowsExceptionWhenAssetIsMissingFromManifestWhenInDebugMode()
+ {
+ $this->app['config']->set('app.debug', true);
+ $manifest = $this->makeManifest();
+
+ try {
+ mix('missing.js');
+ } catch (\Exception $e) {
+ throw $e;
+ } finally { // make sure we can cleanup the file
+ unlink($manifest);
+ }
+ }
+
+ public function testMixOnlyThrowsAndReportsOneExceptionWhenAssetIsMissingFromManifestWhenInDebugMode()
+ {
+ $handler = new FakeHandler;
+ $this->app->instance(ExceptionHandler::class, $handler);
+ $this->app['config']->set('app.debug', true);
+ $manifest = $this->makeManifest();
+ Route::get('test-route', function () {
+ mix('missing.js');
+ });
+
+ $this->get('/test-route');
+
+ $this->assertCount(1, $handler->reported);
+
+ unlink($manifest);
+ }
+
+ protected function makeManifest($directory = '')
+ {
+ $this->app->singleton('path.public', function () {
+ return __DIR__;
+ });
+
+ $path = public_path(str_finish($directory, '/').'mix-manifest.json');
+
+ touch($path);
+
+ // Laravel mix prints JSON pretty and with escaped
+ // slashes, so we are doing that here for consistency.
+ $content = json_encode(['/unversioned.css' => '/versioned.css'], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
+
+ file_put_contents($path, $content);
+
+ return $path;
+ }
+}
+
+class FakeHandler
+{
+ public $reported = [];
+
+ public function report($exception)
+ {
+ $this->reported[] = $exception;
+ }
+
+ public function render($exception)
+ {
+ //
+ }
}
diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php
index 975cbd9045d6..06fff7a0e22b 100755
--- a/tests/Support/SupportCollectionTest.php
+++ b/tests/Support/SupportCollectionTest.php
@@ -2693,6 +2693,70 @@ public function testWhenDefault()
$this->assertSame(['michael', 'tom', 'taylor'], $collection->toArray());
}
+ public function testWhenEmpty()
+ {
+ $collection = new Collection(['michael', 'tom']);
+
+ $collection->whenEmpty(function ($collection) {
+ return $collection->push('adam');
+ });
+
+ $this->assertSame(['michael', 'tom'], $collection->toArray());
+
+ $collection = new Collection;
+
+ $collection->whenEmpty(function ($collection) {
+ return $collection->push('adam');
+ });
+
+ $this->assertSame(['adam'], $collection->toArray());
+ }
+
+ public function testWhenEmptyDefault()
+ {
+ $collection = new Collection(['michael', 'tom']);
+
+ $collection->whenEmpty(function ($collection) {
+ return $collection->push('adam');
+ }, function ($collection) {
+ return $collection->push('taylor');
+ });
+
+ $this->assertSame(['michael', 'tom', 'taylor'], $collection->toArray());
+ }
+
+ public function testWhenNotEmpty()
+ {
+ $collection = new Collection(['michael', 'tom']);
+
+ $collection->whenNotEmpty(function ($collection) {
+ return $collection->push('adam');
+ });
+
+ $this->assertSame(['michael', 'tom', 'adam'], $collection->toArray());
+
+ $collection = new Collection;
+
+ $collection->whenNotEmpty(function ($collection) {
+ return $collection->push('adam');
+ });
+
+ $this->assertSame([], $collection->toArray());
+ }
+
+ public function testWhenNotEmptyDefault()
+ {
+ $collection = new Collection(['michael', 'tom']);
+
+ $collection->whenNotEmpty(function ($collection) {
+ return $collection->push('adam');
+ }, function ($collection) {
+ return $collection->push('taylor');
+ });
+
+ $this->assertSame(['michael', 'tom', 'adam'], $collection->toArray());
+ }
+
public function testUnless()
{
$collection = new Collection(['michael', 'tom']);
@@ -2725,6 +2789,70 @@ public function testUnlessDefault()
$this->assertSame(['michael', 'tom', 'taylor'], $collection->toArray());
}
+ public function testUnlessEmpty()
+ {
+ $collection = new Collection(['michael', 'tom']);
+
+ $collection->unlessEmpty(function ($collection) {
+ return $collection->push('adam');
+ });
+
+ $this->assertSame(['michael', 'tom', 'adam'], $collection->toArray());
+
+ $collection = new Collection;
+
+ $collection->unlessEmpty(function ($collection) {
+ return $collection->push('adam');
+ });
+
+ $this->assertSame([], $collection->toArray());
+ }
+
+ public function testUnlessEmptyDefault()
+ {
+ $collection = new Collection(['michael', 'tom']);
+
+ $collection->unlessEmpty(function ($collection) {
+ return $collection->push('adam');
+ }, function ($collection) {
+ return $collection->push('taylor');
+ });
+
+ $this->assertSame(['michael', 'tom', 'adam'], $collection->toArray());
+ }
+
+ public function testUnlessNotEmpty()
+ {
+ $collection = new Collection(['michael', 'tom']);
+
+ $collection->unlessNotEmpty(function ($collection) {
+ return $collection->push('adam');
+ });
+
+ $this->assertSame(['michael', 'tom'], $collection->toArray());
+
+ $collection = new Collection;
+
+ $collection->unlessNotEmpty(function ($collection) {
+ return $collection->push('adam');
+ });
+
+ $this->assertSame(['adam'], $collection->toArray());
+ }
+
+ public function testUnlessNotEmptyDefault()
+ {
+ $collection = new Collection(['michael', 'tom']);
+
+ $collection->unlessNotEmpty(function ($collection) {
+ return $collection->push('adam');
+ }, function ($collection) {
+ return $collection->push('taylor');
+ });
+
+ $this->assertSame(['michael', 'tom', 'taylor'], $collection->toArray());
+ }
+
public function testHasReturnsValidResults()
{
$collection = new Collection(['foo' => 'one', 'bar' => 'two', 1 => 'three']);
diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php
index 06e36eeed6c4..501afa4eadf6 100755
--- a/tests/Validation/ValidationValidatorTest.php
+++ b/tests/Validation/ValidationValidatorTest.php
@@ -4128,6 +4128,49 @@ function ($attribute, $value, $fail) {
$this->assertEquals('states.0 must be AR or TX', $v->errors()->get('states.0')[0]);
$this->assertEquals('states.1 must be AR or TX', $v->errors()->get('states.1')[0]);
$this->assertEquals('number must be divisible by 4', $v->errors()->get('number')[0]);
+
+ // Test array of messages with failing case...
+ $v = new Validator(
+ $this->getIlluminateArrayTranslator(),
+ ['name' => 42],
+ ['name' => new class implements Rule {
+ public function passes($attribute, $value)
+ {
+ return $value === 'taylor';
+ }
+
+ public function message()
+ {
+ return [':attribute must be taylor', ':attribute must be a first name'];
+ }
+ }]
+ );
+
+ $this->assertTrue($v->fails());
+ $this->assertEquals('name must be taylor', $v->errors()->get('name')[0]);
+ $this->assertEquals('name must be a first name', $v->errors()->get('name')[1]);
+
+ // Test array of messages with multiple rules for one attribute case...
+ $v = new Validator(
+ $this->getIlluminateArrayTranslator(),
+ ['name' => 42],
+ ['name' => [new class implements Rule {
+ public function passes($attribute, $value)
+ {
+ return $value === 'taylor';
+ }
+
+ public function message()
+ {
+ return [':attribute must be taylor', ':attribute must be a first name'];
+ }
+ }, 'string']]
+ );
+
+ $this->assertTrue($v->fails());
+ $this->assertEquals('name must be taylor', $v->errors()->get('name')[0]);
+ $this->assertEquals('name must be a first name', $v->errors()->get('name')[1]);
+ $this->assertEquals('validation.string', $v->errors()->get('name')[2]);
}
public function testImplicitCustomValidationObjects()
diff --git a/tests/View/ViewFactoryTest.php b/tests/View/ViewFactoryTest.php
index c52bd7b72c13..bd717340da62 100755
--- a/tests/View/ViewFactoryTest.php
+++ b/tests/View/ViewFactoryTest.php
@@ -653,6 +653,15 @@ public function testIncrementingLoopIndicesOfUncountable()
$this->assertNull($factory->getLoopStack()[0]['last']);
}
+ public function testMacro()
+ {
+ $factory = $this->getFactory();
+ $factory->macro('getFoo', function () {
+ return 'Hello World';
+ });
+ $this->assertEquals('Hello World', $factory->getFoo());
+ }
+
protected function getFactory()
{
return new Factory(