framework/tests/integration/extenders/ModelTest.php
Alexander Skvortsov 7794546845
Model extender: Fix inheritance (#2132)
This ensures that default values, date attributes and relationships are properly inherited, when we have deeper model class hierarchies.

This also adds test cases to ensure that inheritance order is honored for relationship and default attribute extender. As there's no way to remove date attributes, the order of evaluation there doesn't matter.
2020-04-24 21:17:31 +02:00

426 lines
10 KiB
PHP

<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Tests\integration\extenders;
use Carbon\Carbon;
use Flarum\Discussion\Discussion;
use Flarum\Extend;
use Flarum\Group\Group;
use Flarum\Post\AbstractEventPost;
use Flarum\Post\CommentPost;
use Flarum\Post\DiscussionRenamedPost;
use Flarum\Post\Post;
use Flarum\Tests\integration\RetrievesAuthorizedUsers;
use Flarum\Tests\integration\TestCase;
use Flarum\User\User;
class ModelTest extends TestCase
{
use RetrievesAuthorizedUsers;
protected function prepDb()
{
$this->prepareDatabase([
'users' => [
$this->adminUser(),
$this->normalUser(),
],
'discussions' => []
]);
}
protected function prepPostsHierarchy()
{
$this->prepareDatabase([
'users' => [
$this->normalUser(),
],
'discussions' => [
['id' => 1, 'title' => 'Discussion with post', 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2, 'first_post_id' => 1, 'comment_count' => 1, 'is_private' => 0],
],
'posts' => [
['id' => 1, 'discussion_id' => 1, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2, 'type' => 'discussionRenamed', 'content' => '<t><p>can i haz relationz?</p></t>'],
],
]);
}
/**
* @test
*/
public function custom_relationship_does_not_exist_by_default()
{
$this->prepDB();
$user = User::find(1);
$this->expectException(\BadMethodCallException::class);
$user->customRelation();
}
/**
* @test
*/
public function custom_hasOne_relationship_exists_if_added()
{
$this->extend(
(new Extend\Model(User::class))
->hasOne('customRelation', Discussion::class, 'user_id')
);
$this->prepDB();
$user = User::find(1);
$this->assertEquals([], $user->customRelation()->get()->toArray());
}
/**
* @test
*/
public function custom_hasMany_relationship_exists_if_added()
{
$this->extend(
(new Extend\Model(User::class))
->hasMany('customRelation', Discussion::class, 'user_id')
);
$this->prepDB();
$user = User::find(1);
$this->assertEquals([], $user->customRelation()->get()->toArray());
}
/**
* @test
*/
public function custom_belongsTo_relationship_exists_if_added()
{
$this->extend(
(new Extend\Model(User::class))
->belongsTo('customRelation', Discussion::class, 'user_id')
);
$this->prepDB();
$user = User::find(1);
$this->assertEquals([], $user->customRelation()->get()->toArray());
}
/**
* @test
*/
public function custom_relationship_exists_if_added()
{
$this->extend(
(new Extend\Model(User::class))
->relationship('customRelation', function (User $user) {
return $user->hasMany(Discussion::class, 'user_id');
})
);
$this->prepDB();
$user = User::find(1);
$this->assertEquals([], $user->customRelation()->get()->toArray());
}
/**
* @test
*/
public function custom_relationship_exists_and_can_return_instances_if_added()
{
$this->extend(
(new Extend\Model(User::class))
->relationship('customRelation', function (User $user) {
return $user->hasMany(Discussion::class, 'user_id');
})
);
$this->prepDB();
$this->prepareDatabase([
'discussions' => [
['id' => 1, 'title' => __CLASS__, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'first_post_id' => 1, 'comment_count' => 1]
]
]);
$user = User::find(1);
$this->assertNotEquals([], $user->customRelation()->get()->toArray());
$this->assertContains(json_encode(__CLASS__), json_encode($user->customRelation()->get()));
}
/**
* @test
*/
public function custom_relationship_is_inherited_to_child_classes()
{
$this->extend(
(new Extend\Model(Post::class))
->belongsTo('ancestor', Discussion::class, 'discussion_id')
);
$this->prepPostsHierarchy();
$post = CommentPost::find(1);
$this->assertInstanceOf(Discussion::class, $post->ancestor);
$this->assertEquals(1, $post->ancestor->id);
}
/**
* @test
*/
public function custom_relationship_prioritizes_child_classes_within_2_parent_classes()
{
$this->extend(
(new Extend\Model(Post::class))
->belongsTo('ancestor', User::class, 'user_id'),
(new Extend\Model(AbstractEventPost::class))
->belongsTo('ancestor', Discussion::class, 'discussion_id')
);
$this->prepPostsHierarchy();
$post = DiscussionRenamedPost::find(1);
$this->assertInstanceOf(Discussion::class, $post->ancestor);
$this->assertEquals(1, $post->ancestor->id);
}
/**
* @test
*/
public function custom_relationship_prioritizes_child_classes_within_child_class_and_immediate_parent()
{
$this->extend(
(new Extend\Model(AbstractEventPost::class))
->belongsTo('ancestor', Discussion::class, 'discussion_id'),
(new Extend\Model(DiscussionRenamedPost::class))
->belongsTo('ancestor', User::class, 'user_id')
);
$this->prepPostsHierarchy();
$post = DiscussionRenamedPost::find(1);
$this->assertInstanceOf(User::class, $post->ancestor);
$this->assertEquals(2, $post->ancestor->id);
}
/**
* @test
*/
public function custom_relationship_does_not_exist_if_added_to_unrelated_model()
{
$this->extend(
(new Extend\Model(User::class))
->relationship('customRelation', function (User $user) {
return $user->hasMany(Discussion::class, 'user_id');
})
);
$this->prepDB();
$this->prepareDatabase([
'groups' => [
$this->adminGroup()
]
]);
$group = Group::find(1);
$this->expectException(\BadMethodCallException::class);
$group->customRelation();
}
/**
* @test
*/
public function custom_default_attribute_doesnt_exist_if_not_set()
{
$group = new Group;
$this->app();
$this->assertNotEquals('Custom Default', $group->name_singular);
}
/**
* @test
*/
public function custom_default_attribute_works_if_set()
{
$this->extend(
(new Extend\Model(Group::class))
->default('name_singular', 'Custom Default')
);
$this->app();
$group = new Group;
$this->assertEquals('Custom Default', $group->name_singular);
}
/**
* @test
*/
public function custom_default_attribute_evaluated_at_runtime_if_callable()
{
$this->extend(
(new Extend\Model(Group::class))
->default('counter', function () {
static $counter = 0;
return ++$counter;
})
);
$this->app();
$group1 = new Group;
$group2 = new Group;
$this->assertEquals(1, $group1->counter);
$this->assertEquals(2, $group2->counter);
}
/**
* @test
*/
public function custom_default_attribute_is_inherited_to_child_classes()
{
$this->extend(
(new Extend\Model(Post::class))
->default('answer', 42)
);
$this->app();
$post = new CommentPost;
$this->assertEquals(42, $post->answer);
}
/**
* @test
*/
public function custom_default_attribute_inheritance_prioritizes_child_class()
{
$this->extend(
(new Extend\Model(Post::class))
->default('answer', 'dont do this'),
(new Extend\Model(AbstractEventPost::class))
->default('answer', 42),
(new Extend\Model(DiscussionRenamedPost::class))
->default('answer', 'ni!')
);
$this->app();
$post = new CustomPost;
$this->assertEquals(42, $post->answer);
$commentPost = new DiscussionRenamedPost;
$this->assertEquals('ni!', $commentPost->answer);
}
/**
* @test
*/
public function custom_default_attribute_doesnt_work_if_set_on_unrelated_model()
{
$this->extend(
(new Extend\Model(Group::class))
->default('name_singular', 'Custom Default')
);
$this->app();
$user = new User;
$this->assertNotEquals('Custom Default', $user->name_singular);
}
/**
* @test
*/
public function custom_date_attribute_doesnt_exist_by_default()
{
$post = new Post;
$this->app();
$this->assertNotContains('custom', $post->getDates());
}
/**
* @test
*/
public function custom_date_attribute_can_be_set()
{
$this->extend(
(new Extend\Model(Post::class))
->dateAttribute('custom')
);
$this->app();
$post = new Post;
$this->assertContains('custom', $post->getDates());
}
/**
* @test
*/
public function custom_date_attribute_is_inherited_to_child_classes()
{
$this->extend(
(new Extend\Model(Post::class))
->dateAttribute('custom')
);
$this->app();
$post = new CommentPost;
$this->assertContains('custom', $post->getDates());
}
/**
* @test
*/
public function custom_date_attribute_doesnt_work_if_set_on_unrelated_model()
{
$this->extend(
(new Extend\Model(Post::class))
->dateAttribute('custom')
);
$this->app();
$discussion = new Discussion;
$this->assertNotContains('custom', $discussion->getDates());
}
}
class CustomPost extends AbstractEventPost
{
/**
* {@inheritdoc}
*/
public static $type = 'customPost';
}