mirror of
https://gitee.com/hyperf/hyperf.git
synced 2024-11-29 18:27:44 +08:00
Added support for disallowing class morphs (#7110)
This commit is contained in:
parent
e42bc9676f
commit
a0be0cd6aa
@ -5,6 +5,7 @@
|
||||
- [#7063](https://github.com/hyperf/hyperf/pull/7063) Added methods `nullableUuidMorphs` `uuidMorphs` and `nullableNumericMorphs` to `Hyperf\Database\Schema\Blueprint`.
|
||||
- [#7070](https://github.com/hyperf/hyperf/pull/7070) Added `Blueprint::charset()` and `Blueprint::collation()`.
|
||||
- [#7071](https://github.com/hyperf/hyperf/pull/7071) Added `Hyperf\Database\Schema\Blueprint::tinyText()`.
|
||||
- [#7110](https://github.com/hyperf/hyperf/pull/7110) Added support for disallowing class morphs.
|
||||
|
||||
# v3.1.43 - 2024-10-10
|
||||
|
||||
|
35
src/database/src/Exception/ClassMorphViolationException.php
Normal file
35
src/database/src/Exception/ClassMorphViolationException.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
namespace Hyperf\Database\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class ClassMorphViolationException extends RuntimeException
|
||||
{
|
||||
/**
|
||||
* The name of the affected Eloquent model.
|
||||
*/
|
||||
public string $model;
|
||||
|
||||
/**
|
||||
* Create a new exception instance.
|
||||
*/
|
||||
public function __construct(object $model)
|
||||
{
|
||||
$class = get_class($model);
|
||||
|
||||
parent::__construct("No morph map defined for model [{$class}].");
|
||||
|
||||
$this->model = $class;
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ namespace Hyperf\Database\Model\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Hyperf\Collection\Arr;
|
||||
use Hyperf\Database\Exception\ClassMorphViolationException;
|
||||
use Hyperf\Database\Model\Builder;
|
||||
use Hyperf\Database\Model\Collection;
|
||||
use Hyperf\Database\Model\Model;
|
||||
@ -27,6 +28,7 @@ use Hyperf\Database\Model\Relations\MorphMany;
|
||||
use Hyperf\Database\Model\Relations\MorphOne;
|
||||
use Hyperf\Database\Model\Relations\MorphTo;
|
||||
use Hyperf\Database\Model\Relations\MorphToMany;
|
||||
use Hyperf\Database\Model\Relations\Pivot;
|
||||
use Hyperf\Database\Model\Relations\Relation;
|
||||
use Hyperf\Stringable\Str;
|
||||
use Hyperf\Stringable\StrCache;
|
||||
@ -564,6 +566,14 @@ trait HasRelationships
|
||||
return array_search(static::class, $morphMap, true);
|
||||
}
|
||||
|
||||
if (static::class === Pivot::class) {
|
||||
return static::class;
|
||||
}
|
||||
|
||||
if (Relation::requiresMorphMap()) {
|
||||
throw new ClassMorphViolationException($this);
|
||||
}
|
||||
|
||||
return static::class;
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,11 @@ abstract class Relation
|
||||
*/
|
||||
public static $morphMap = [];
|
||||
|
||||
/**
|
||||
* Prevents morph relationships without a morph map.
|
||||
*/
|
||||
protected static bool $requireMorphMap = false;
|
||||
|
||||
/**
|
||||
* The Model query builder instance.
|
||||
*
|
||||
@ -357,6 +362,32 @@ abstract class Relation
|
||||
return array_search($className, static::$morphMap, strict: true) ?: $className;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent polymorphic relationships from being used without model mappings.
|
||||
*/
|
||||
public static function requireMorphMap(bool $requireMorphMap = true): void
|
||||
{
|
||||
static::$requireMorphMap = $requireMorphMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if polymorphic relationships require explicit model mapping.
|
||||
*/
|
||||
public static function requiresMorphMap(): bool
|
||||
{
|
||||
return static::$requireMorphMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the morph map for polymorphic relations and require all morphed models to be explicitly mapped.
|
||||
*/
|
||||
public static function enforceMorphMap(?array $map, bool $merge = true): array
|
||||
{
|
||||
static::requireMorphMap();
|
||||
|
||||
return static::morphMap($map, $merge);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the primary keys for an array of models.
|
||||
*
|
||||
|
101
src/database/tests/DatabaseStrictMorphsTest.php
Normal file
101
src/database/tests/DatabaseStrictMorphsTest.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
namespace HyperfTest\Database;
|
||||
|
||||
use Hyperf\Database\Exception\ClassMorphViolationException;
|
||||
use Hyperf\Database\Model\Model;
|
||||
use Hyperf\Database\Model\Relations\Pivot;
|
||||
use Hyperf\Database\Model\Relations\Relation;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @coversNothing
|
||||
*/
|
||||
class DatabaseStrictMorphsTest extends TestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
Relation::requireMorphMap();
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
parent::tearDown();
|
||||
|
||||
Relation::morphMap([], false);
|
||||
Relation::requireMorphMap(false);
|
||||
}
|
||||
|
||||
public function testStrictModeThrowsAnExceptionOnClassMap()
|
||||
{
|
||||
$this->expectException(ClassMorphViolationException::class);
|
||||
|
||||
$model = new TestModel();
|
||||
|
||||
$model->getMorphClass();
|
||||
}
|
||||
|
||||
public function testStrictModeDoesNotThrowExceptionWhenMorphMap()
|
||||
{
|
||||
$model = new TestModel();
|
||||
|
||||
Relation::morphMap([
|
||||
'foo' => TestModel::class,
|
||||
]);
|
||||
|
||||
$morphName = $model->getMorphClass();
|
||||
$this->assertSame('foo', $morphName);
|
||||
}
|
||||
|
||||
public function testMapsCanBeEnforcedInOneMethod()
|
||||
{
|
||||
$model = new TestModel();
|
||||
|
||||
Relation::requireMorphMap(false);
|
||||
|
||||
Relation::enforceMorphMap([
|
||||
'test' => TestModel::class,
|
||||
]);
|
||||
|
||||
$morphName = $model->getMorphClass();
|
||||
$this->assertSame('test', $morphName);
|
||||
}
|
||||
|
||||
public function testMapIgnoreGenericPivotClass()
|
||||
{
|
||||
$this->expectNotToPerformAssertions();
|
||||
$pivotModel = new Pivot();
|
||||
|
||||
$pivotModel->getMorphClass();
|
||||
}
|
||||
|
||||
public function testMapCanBeEnforcedToCustomPivotClass()
|
||||
{
|
||||
$this->expectException(ClassMorphViolationException::class);
|
||||
|
||||
$pivotModel = new TestPivotModel();
|
||||
|
||||
$pivotModel->getMorphClass();
|
||||
}
|
||||
}
|
||||
|
||||
class TestModel extends Model
|
||||
{
|
||||
}
|
||||
|
||||
class TestPivotModel extends Pivot
|
||||
{
|
||||
}
|
Loading…
Reference in New Issue
Block a user