Skip to content

Commit

Permalink
Merge branch '8.x'
Browse files Browse the repository at this point in the history
  • Loading branch information
GrahamCampbell committed Dec 14, 2021
2 parents 94e846b + f1d8ed5 commit c7d6fe5
Show file tree
Hide file tree
Showing 19 changed files with 298 additions and 43 deletions.
2 changes: 1 addition & 1 deletion src/Illuminate/Console/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public static function phpBinary()
*/
public static function artisanBinary()
{
return defined('ARTISAN_BINARY') ? ProcessUtils::escapeArgument(ARTISAN_BINARY) : 'artisan';
return ProcessUtils::escapeArgument(defined('ARTISAN_BINARY') ? ARTISAN_BINARY : 'artisan');
}

/**
Expand Down
41 changes: 41 additions & 0 deletions src/Illuminate/Database/Eloquent/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,43 @@ class Builder implements BuilderContract
*/
protected $onDelete;

/**
* The properties that should be returned from query builder.
*
* @var string[]
*/
protected $propertyPassthru = [
'from',
];

/**
* The methods that should be returned from query builder.
*
* @var string[]
*/
protected $passthru = [
'aggregate',
'average',
'avg',
'count',
'dd',
'doesntExist',
'dump',
'exists',
'getBindings',
'getConnection',
'getGrammar',
'insert',
'insertGetId',
'insertOrIgnore',
'insertUsing',
'max',
'min',
'raw',
'sum',
'toSql',
];

/**
* Applied global scopes.
*
Expand Down Expand Up @@ -1572,6 +1609,10 @@ public function __get($key)
return new HigherOrderBuilderProxy($this, $key);
}

if (in_array($key, $this->propertyPassthru)) {
return $this->toBase()->{$key};
}

throw new Exception("Property [{$key}] does not exist on the Eloquent builder instance.");
}

Expand Down
6 changes: 3 additions & 3 deletions src/Illuminate/Database/Eloquent/SoftDeletes.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ public function forceDelete()
protected function performDeleteOnModel()
{
if ($this->forceDeleting) {
$this->exists = false;

return $this->setKeysForSaveQuery($this->newModelQuery())->forceDelete();
return tap($this->setKeysForSaveQuery($this->newModelQuery())->forceDelete(), function () {
$this->exists = false;
});
}

return $this->runSoftDelete();
Expand Down
1 change: 1 addition & 0 deletions src/Illuminate/Database/Schema/ColumnDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* @method $this from(int $startingValue) Set the starting value of an auto-incrementing field (MySQL / PostgreSQL)
* @method $this generatedAs(string|Expression $expression = null) Create a SQL compliant identity column (PostgreSQL)
* @method $this index(string $indexName = null) Add an index
* @method $this invisible() Specify that the column should be invisible to "SELECT *" (MySQL)
* @method $this nullable(bool $value = true) Allow NULL values to be inserted into the column
* @method $this persisted() Mark the computed generated column as persistent (SQL Server)
* @method $this primary() Add a primary index
Expand Down
16 changes: 15 additions & 1 deletion src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class MySqlGrammar extends Grammar
* @var string[]
*/
protected $modifiers = [
'Unsigned', 'Charset', 'Collate', 'VirtualAs', 'StoredAs', 'Nullable',
'Unsigned', 'Charset', 'Collate', 'VirtualAs', 'StoredAs', 'Nullable', 'Invisible',
'Srid', 'Default', 'Increment', 'Comment', 'After', 'First',
];

Expand Down Expand Up @@ -1057,6 +1057,20 @@ protected function modifyNullable(Blueprint $blueprint, Fluent $column)
}
}

/**
* Get the SQL for an invisible column modifier.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $column
* @return string|null
*/
protected function modifyInvisible(Blueprint $blueprint, Fluent $column)
{
if (! is_null($column->invisible)) {
return ' invisible';
}
}

/**
* Get the SQL for a default column modifier.
*
Expand Down
2 changes: 1 addition & 1 deletion src/Illuminate/Foundation/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ public function bootstrapWith(array $bootstrappers)
*/
public function afterLoadingEnvironment(Closure $callback)
{
return $this->afterBootstrapping(
$this->afterBootstrapping(
LoadEnvironmentVariables::class, $callback
);
}
Expand Down
15 changes: 14 additions & 1 deletion src/Illuminate/Foundation/Console/ComponentMakeCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,20 @@ protected function getView()
*/
protected function getStub()
{
return __DIR__.'/stubs/view-component.stub';
return $this->resolveStubPath('/stubs/view-component.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;
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/Illuminate/Foundation/Console/StubPublishCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public function handle()
__DIR__.'/stubs/scope.stub' => $stubsPath.'/scope.stub',
__DIR__.'/stubs/test.stub' => $stubsPath.'/test.stub',
__DIR__.'/stubs/test.unit.stub' => $stubsPath.'/test.unit.stub',
__DIR__.'/stubs/view-component.stub' => $stubsPath.'/view-component.stub',
realpath(__DIR__.'/../../Database/Console/Factories/stubs/factory.stub') => $stubsPath.'/factory.stub',
realpath(__DIR__.'/../../Database/Console/Seeds/stubs/seeder.stub') => $stubsPath.'/seeder.stub',
realpath(__DIR__.'/../../Database/Migrations/stubs/migration.create.stub') => $stubsPath.'/migration.create.stub',
Expand Down
18 changes: 18 additions & 0 deletions src/Illuminate/Support/Str.php
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,24 @@ public static function substrCount($haystack, $needle, $offset = 0, $length = nu
}
}

/**
* Replace text within a portion of a string.
*
* @param string|array $string
* @param string|array $replace
* @param array|int $offset
* @param array|int|null $length
* @return string|array
*/
public static function substrReplace($string, $replace, $offset = 0, $length = null)
{
if ($length === null) {
$length = strlen($string);
}

return substr_replace($string, $replace, $offset, $length);
}

/**
* Make a string's first character uppercase.
*
Expand Down
13 changes: 13 additions & 0 deletions src/Illuminate/Support/Stringable.php
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,19 @@ public function substrCount($needle, $offset = null, $length = null)
return Str::substrCount($this->value, $needle, $offset ?? 0, $length);
}

/**
* Replace text within a portion of a string.
*
* @param string|array $replace
* @param array|int $offset
* @param array|int|null $length
* @return string|array
*/
public function substrReplace($replace, $offset = 0, $length = null)
{
return new static(Str::substrReplace($this->value, $replace, $offset, $length));
}

/**
* Trim the string of the given characters.
*
Expand Down
53 changes: 28 additions & 25 deletions src/Illuminate/Validation/Rules/Password.php
Original file line number Diff line number Diff line change
Expand Up @@ -270,36 +270,39 @@ public function passes($attribute, $value)
{
$this->messages = [];

$validator = Validator::make($this->data, [
$attribute => 'string|min:'.$this->min,
], $this->validator->customMessages, $this->validator->customAttributes);
$validator = Validator::make(
$this->data,
[$attribute => 'string|min:'.$this->min],
$this->validator->customMessages,
$this->validator->customAttributes
)->after(function ($validator) use ($attribute, $value) {
if (! is_string($value)) {
return;
}

$value = (string) $value;

if ($this->mixedCase && ! preg_match('/(\p{Ll}+.*\p{Lu})|(\p{Lu}+.*\p{Ll})/u', $value)) {
$validator->errors()->add($attribute, 'The :attribute must contain at least one uppercase and one lowercase letter.');
}

if ($this->letters && ! preg_match('/\pL/u', $value)) {
$validator->errors()->add($attribute, 'The :attribute must contain at least one letter.');
}

if ($this->symbols && ! preg_match('/\p{Z}|\p{S}|\p{P}/u', $value)) {
$validator->errors()->add($attribute, 'The :attribute must contain at least one symbol.');
}

if ($this->numbers && ! preg_match('/\pN/u', $value)) {
$validator->errors()->add($attribute, 'The :attribute must contain at least one number.');
}
});

if ($validator->fails()) {
return $this->fail($validator->messages()->all());
}

$value = (string) $value;

if ($this->mixedCase && ! preg_match('/(\p{Ll}+.*\p{Lu})|(\p{Lu}+.*\p{Ll})/u', $value)) {
$this->fail('The :attribute must contain at least one uppercase and one lowercase letter.');
}

if ($this->letters && ! preg_match('/\pL/u', $value)) {
$this->fail('The :attribute must contain at least one letter.');
}

if ($this->symbols && ! preg_match('/\p{Z}|\p{S}|\p{P}/u', $value)) {
$this->fail('The :attribute must contain at least one symbol.');
}

if ($this->numbers && ! preg_match('/\pN/u', $value)) {
$this->fail('The :attribute must contain at least one number.');
}

if (! empty($this->messages)) {
return false;
}

if ($this->uncompromised && ! Container::getInstance()->make(UncompromisedVerifier::class)->verify([
'value' => $value,
'threshold' => $this->compromisedThreshold,
Expand Down
10 changes: 6 additions & 4 deletions tests/Console/ConsoleEventSchedulerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,10 @@ public function testCommandCreatesNewArtisanCommand()

$events = $schedule->events();
$binary = $escape.PHP_BINARY.$escape;
$this->assertEquals($binary.' artisan queue:listen', $events[0]->command);
$this->assertEquals($binary.' artisan queue:listen --tries=3', $events[1]->command);
$this->assertEquals($binary.' artisan queue:listen --tries=3', $events[2]->command);
$artisan = $escape.'artisan'.$escape;
$this->assertEquals($binary.' '.$artisan.' queue:listen', $events[0]->command);
$this->assertEquals($binary.' '.$artisan.' queue:listen --tries=3', $events[1]->command);
$this->assertEquals($binary.' '.$artisan.' queue:listen --tries=3', $events[2]->command);
}

public function testCreateNewArtisanCommandUsingCommandClass()
Expand All @@ -115,7 +116,8 @@ public function testCreateNewArtisanCommandUsingCommandClass()

$events = $schedule->events();
$binary = $escape.PHP_BINARY.$escape;
$this->assertEquals($binary.' artisan foo:bar --force', $events[0]->command);
$artisan = $escape.'artisan'.$escape;
$this->assertEquals($binary.' '.$artisan.' foo:bar --force', $events[0]->command);
}

public function testCallCreatesNewJobWithTimezone()
Expand Down
2 changes: 1 addition & 1 deletion tests/Console/Scheduling/EventTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public function testBuildCommandInBackgroundUsingUnix()

$scheduleId = '"framework'.DIRECTORY_SEPARATOR.'schedule-eeb46c93d45e928d62aaf684d727e213b7094822"';

$this->assertSame("(php -i > '/dev/null' 2>&1 ; '".PHP_BINARY."' artisan schedule:finish {$scheduleId} \"$?\") > '/dev/null' 2>&1 &", $event->buildCommand());
$this->assertSame("(php -i > '/dev/null' 2>&1 ; '".PHP_BINARY."' 'artisan' schedule:finish {$scheduleId} \"$?\") > '/dev/null' 2>&1 &", $event->buildCommand());
}

/**
Expand Down
37 changes: 37 additions & 0 deletions tests/Database/DatabaseEloquentSoftDeletesIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Illuminate\Pagination\CursorPaginator;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Carbon;
use Mockery;
use PHPUnit\Framework\TestCase;

class DatabaseEloquentSoftDeletesIntegrationTest extends TestCase
Expand Down Expand Up @@ -189,6 +190,42 @@ public function testForceDeleteActuallyDeletesRecords()
$this->assertEquals(1, $users->first()->id);
}

public function testForceDeleteUpdateExistsProperty()
{
$this->createUsers();
$user = SoftDeletesTestUser::find(2);

$this->assertTrue($user->exists);

$user->forceDelete();

$this->assertFalse($user->exists);
}

public function testForceDeleteDoesntUpdateExistsPropertyIfFailed()
{
$user = new class() extends SoftDeletesTestUser
{
public $exists = true;

public function newModelQuery()
{
return Mockery::spy(parent::newModelQuery(), function (Mockery\MockInterface $mock) {
$mock->shouldReceive('forceDelete')->andThrow(new \Exception());
});
}
};

$this->assertTrue($user->exists);

try {
$user->forceDelete();
} catch (\Exception $exception) {
}

$this->assertTrue($user->exists);
}

public function testRestoreRestoresRecords()
{
$this->createUsers();
Expand Down
10 changes: 10 additions & 0 deletions tests/Database/DatabaseMySqlSchemaGrammarTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,16 @@ public function testAddingGeneratedColumnWithCharset()
$this->assertSame('alter table `links` add `url` varchar(2083) character set ascii not null, add `url_hash_virtual` varchar(64) character set ascii as (sha2(url, 256)), add `url_hash_stored` varchar(64) character set ascii as (sha2(url, 256)) stored', $statements[0]);
}

public function testAddingInvisibleColumn()
{
$blueprint = new Blueprint('users');
$blueprint->string('secret', 64)->nullable(false)->invisible();
$statements = $blueprint->toSql($this->getConnection(), $this->getGrammar());

$this->assertCount(1, $statements);
$this->assertSame('alter table `users` add `secret` varchar(64) not null invisible', $statements[0]);
}

public function testAddingString()
{
$blueprint = new Blueprint('users');
Expand Down
Loading

0 comments on commit c7d6fe5

Please sign in to comment.