Skip to content

Commit

Permalink
feat: Users ManyToMany WorkingGroups
Browse files Browse the repository at this point in the history
  • Loading branch information
r0mdau committed Mar 17, 2020
1 parent 5eff472 commit 8a7584f
Show file tree
Hide file tree
Showing 10 changed files with 163 additions and 30 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@ Phpmyadmin is available at http://localhost:8090

- A user has a name and email, both are mandatory.
- A user work in a company but not mandatory
- A user can belong to many working groups
- A working group can belong to many users
- We can retrieve user's working groups, but not the opposite
- A company has a name
- A working group has a name

## Folder structure

Expand Down Expand Up @@ -104,10 +108,11 @@ Mutliple composer scripts to help daily tasks.
- [ ] Add entities history change management
- [ ] Add flyway to automatically maintain database structure with new entities in other environments than local
- [ ] Add Doctrine Second Level Cache
- [ ] Mermaid class diagram
- [ ] Update README.md after all todos
Add more entities to show links using doctrine
- [x] ManyToOne
- [ ] OneToMany
- [ ] ManyToMany
- [x] ManyToMany
- [ ] Inheritance
10 changes: 8 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
"homepage": "https://github.com/r0mdau/fradoos",
"license": "Apache-2.0",
"authors": [
{"name": "Romain Dauby", "email": "romain.dauby@gmail.com"}
{
"name": "Romain Dauby",
"email": "romain.dauby@gmail.com"
}
],
"autoload": {
"psr-4": {
Expand Down Expand Up @@ -47,7 +50,10 @@
"generate-proxies": "doctrine orm:generate-proxies",
"phpcs": "phpcs -s src --standard=phpcs.xml --ignore=src/routes.php",
"phpcbf": "phpcbf src --ignore=src/routes.php",
"phpstan": "phpstan analyse src test",
"phpstan": [
"phpstan analyse -l5 src",
"phpstan analyse -l4 test"
],
"test": "phpunit",
"test-application": "phpunit --testsuite Application",
"test-domain": "phpunit --testsuite Domain",
Expand Down
3 changes: 3 additions & 0 deletions etc/database.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ ALTER TABLE user ADD company_id INT DEFAULT NULL;
ALTER TABLE user ADD CONSTRAINT FK_8D93D649979B1AD6 FOREIGN KEY (company_id) REFERENCES company (id) ON DELETE NO ACTION;
CREATE INDEX IDX_8D93D649979B1AD6 ON user (company_id);
CREATE TABLE working_group (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB;
CREATE TABLE user_working_group (user_id INT NOT NULL, working_group_id INT NOT NULL, INDEX IDX_DE788825A76ED395 (user_id), INDEX IDX_DE7888258856E875 (working_group_id), PRIMARY KEY(user_id, working_group_id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB;
ALTER TABLE user_working_group ADD CONSTRAINT FK_DE788825A76ED395 FOREIGN KEY (user_id) REFERENCES user (id);
ALTER TABLE user_working_group ADD CONSTRAINT FK_DE7888258856E875 FOREIGN KEY (working_group_id) REFERENCES working_group (id);
27 changes: 27 additions & 0 deletions src/Application/ApplicationUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Fradoos\Application;

use App\Domaine\Entrepot\Entrepots;
use Doctrine\Common\Collections\ArrayCollection;
use Fradoos\Domain\Helper\HelperParameter;
use Fradoos\Domain\Presentation\Presentations;
use Fradoos\Domain\Repository\Repositories;
Expand Down Expand Up @@ -75,6 +77,7 @@ public function getAll($req, $res, $args)
* @SWG\Parameter(name="name", in="formData", required=true, type="string", description="Name"),
* @SWG\Parameter(name="email", in="formData", required=true, type="string", description="Email"),
* @SWG\Parameter(name="company", in="formData", required=false, type="integer", description="Company"),
* @SWG\Parameter(name="workingGroups", in="formData", required=false, type="array", items="string", description="Working Groups"),
* @SWG\Response(response=201, description="")
* )
*/
Expand All @@ -85,6 +88,17 @@ public function post($req, $res, $args)
$company = $req->getParam("company");
$user->setCompany(empty($company) ? null : Repositories::instance()->forCompany()->get($req->getParam("company")));

if (!empty($req->getParam("workingGroups"))) {
$user->setWorkingGroups(
new ArrayCollection(
array_map(
function ($workingGroupId) {
return Repositories::instance()->forWorkingGroup()->get($workingGroupId);
}, $req->getParam("workingGroups")
)
)
);
}
Repositories::instance()->forUser()->add($user);

return $this->response(
Expand All @@ -100,6 +114,7 @@ public function post($req, $res, $args)
* @SWG\Parameter(name="name", in="formData", required=true, type="string", description="Name"),
* @SWG\Parameter(name="email", in="formData", required=true, type="string", description="Email"),
* @SWG\Parameter(name="company", in="formData", required=false, type="integer", description="Company"),
* @SWG\Parameter(name="workingGroups", in="formData", required=false, type="array", items="string", description="Working Groups"),
* @SWG\Response(response=201, description="")
* )
*/
Expand All @@ -116,6 +131,18 @@ public function put($req, $res, $args)
$company = $req->getParam("company");
$user->setCompany(empty($company) ? null : Repositories::instance()->forCompany()->get($req->getParam("company")));

if (!empty($req->getParam("workingGroups"))) {
$user->setWorkingGroups(
new ArrayCollection(
array_map(
function ($workingGroupId) {
return Repositories::instance()->forWorkingGroup()->get($workingGroupId);
}, $req->getParam("workingGroups")
)
)
);
}

Repositories::instance()->forUser()->edit($user);
$presentation = Presentations::instance()->forUser()->inJson($user);
$status = static::STATUS_CREATED;
Expand Down
5 changes: 5 additions & 0 deletions src/Application/Presentation/JsonPresentationUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class JsonPresentationUser extends SimpleJsonPresentation implements IPresentati
public static $name = 'name';
public static $email = 'email';
public static $company = 'company';
public static $workingGroups = 'workingGroups';

public function __construct()
{
Expand All @@ -25,6 +26,9 @@ public function __construct()
$this->mappings[JsonPresentationUser::$company] = function (User $object) {
return is_null($object->getCompany()) ? "" : Presentations::instance()->forCompany()->inJson($object->getCompany());
};
$this->mappings[JsonPresentationUser::$workingGroups] = function (User $object) {
return $object->getWorkingGroups()->isEmpty() ? "" : Presentations::instance()->forWorkingGroup()->allInJson($object->getWorkingGroups());
};
}

public function allDefaultProperties()
Expand All @@ -34,6 +38,7 @@ public function allDefaultProperties()
JsonPresentationUser::$name,
JsonPresentationUser::$email,
JsonPresentationUser::$company,
JsonPresentationUser::$workingGroups,
];
}
}
36 changes: 36 additions & 0 deletions src/Domain/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace Fradoos\Domain;

use Doctrine\Common\Collections\ArrayCollection;
use Fradoos\Domain\Helper\HelperParameter;
use PHPUnit\Framework\MockObject\MockObject;

/**
* Class User
Expand All @@ -25,6 +27,11 @@ class User extends Entity
*/
private $company;

/**
* @var $workingGroups null|ArrayCollection
*/
private $workingGroups;

/**
* User constructor.
* @param $name
Expand All @@ -35,6 +42,7 @@ public function __construct($name, $email)
{
$this->setName($name);
$this->setEmail($email);
$this->workingGroups = new ArrayCollection();
}

/**
Expand Down Expand Up @@ -95,4 +103,32 @@ public function setCompany(?Company $company)
$this->company = $company;
}
}

/**
* @return ArrayCollection|null
*/
public function getWorkingGroups()
{
return $this->workingGroups;
}

/**
* @param WorkingGroup|MockObject $workingGroup
*/
public function addWorkingGroup(WorkingGroup $workingGroup)
{
if (!$this->workingGroups->contains($workingGroup)) {
$this->workingGroups->add($workingGroup);
}
}

/**
* @param ArrayCollection $workingGroups
*/
public function setWorkingGroups(ArrayCollection $workingGroups)
{
if ($this->workingGroups != $workingGroups) {
$this->workingGroups = $workingGroups;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
$builder->addField("name", "string", ["length" => 255, "nullable" => false]);
$builder->addField("email", "string", ["length" => 255, "nullable" => false]);

$builder->createManyToOne('company', 'Company')->addJoinColumn('company_id', 'id', true, false, 'no action')->cascadePersist()->build();
$builder->createManyToOne('company', 'Company')->addJoinColumn('company_id', 'id', true, false, 'no action')->cascadePersist()->build();
$builder->createManyToMany('workingGroups', 'WorkingGroup')->setJoinTable('user_working_group')->addJoinColumn('user_id', 'id')->addInverseJoinColumn('working_group_id', 'id')->cascadePersist()->build();
41 changes: 16 additions & 25 deletions test/Application/ApplicationUserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Fradoos\Application;

use Doctrine\Common\Collections\ArrayCollection;
use Fradoos\Domain\Repository\IRepositoryUser;
use Fradoos\Domain\User;

Expand All @@ -16,6 +17,12 @@ public function setUp()
$this->userRepository = $this->getMockBuilder(IRepositoryUser::class)->getMock();
$this->repository->expects($this->any())->method("forUser")->willReturn($this->userRepository);
$this->userMock = $this->getMockBuilder(User::class)->disableOriginalConstructor()->getMock();
$this->userMock->expects($this->any())->method("setName")->with("Georges V");
$this->userMock->expects($this->any())->method("setEmail")->with("test@example.com");
$this->userMock->expects($this->any())->method("getId")->willReturn(1);
$this->userMock->expects($this->any())->method("getName")->willReturn("Georges V");
$this->userMock->expects($this->any())->method("getEmail")->willReturn("test@example.com");
$this->userMock->expects($this->any())->method("getWorkingGroups")->willReturn(new ArrayCollection());
}

public function testInstance()
Expand Down Expand Up @@ -68,51 +75,35 @@ public function testPost()
$this->client->post("/user", ["name" => "Georges V", "email" => "test@example.com"]);

$this->assertStatusEquals(201);
$this->assertResultEquals([
"id" => 1,
"name" => "Georges V",
"email" => "test@example.com",
"company" => ""
]);
$this->assertResultEquals($this->userPresentation());
}

public function testPut()
{
$user = $this->getMockBuilder(User::class)->disableOriginalConstructor()->getMock();
$user->expects($this->once())->method("setName")->with("Georges V");
$user->expects($this->once())->method("setEmail")->with("test@example.com");
$user->expects($this->once())->method("getId")->willReturn(1);
$user->expects($this->once())->method("getName")->willReturn("Georges V");
$user->expects($this->once())->method("getEmail")->willReturn("test@example.com");

$this->userRepository
->expects($this->once())
->method("get")
->with(1)
->willReturn($user);
->willReturn($this->userMock);
$this->userRepository
->expects($this->once())
->method("edit")
->with($user);
->with($this->userMock);

$this->client->put("/user/1", ["name" => "Georges V", "email" => "test@example.com"]);

$this->assertStatusEquals(201);
$this->assertResultEquals([
"id" => 1,
"name" => "Georges V",
"email" => "test@example.com",
"company" => ""
]);
$this->assertResultEquals($this->userPresentation());
}

private function userPresentation()
{
return [
"id" => null,
"name" => null,
"email" => null,
"company" => null,
"id" => 1,
"name" => "Georges V",
"email" => "test@example.com",
"company" => "",
"workingGroups" => ""
];
}
}
2 changes: 1 addition & 1 deletion test/Application/Presentation/JsonPresentationUserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public function testToutesLesProprietesParDefaut()
{
$presentationUser = new JsonPresentationUser();
$this->assertSame(
["id", "name", "email", "company"],
["id", "name", "email", "company", "workingGroups"],
$presentationUser->allDefaultProperties()
);
}
Expand Down
59 changes: 59 additions & 0 deletions test/Domain/UserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Fradoos\Domain;

use Doctrine\Common\Collections\ArrayCollection;

class UserTest extends \PHPUnit\Framework\TestCase
{
public function testConstruct()
Expand All @@ -11,6 +13,13 @@ public function testConstruct()
$this->assertEquals("Georges VI", $user->getName());
}

public function testConstructSetEmptyWorkingGroups()
{
$user = new User("Georges VI", "test@example.com");

$this->assertCount(0, $user->getWorkingGroups());
}

/**
* @expectedException \Fradoos\Domain\Error\ErrorParameter
* @expectedExceptionMessage The user name is mandatory.
Expand Down Expand Up @@ -66,4 +75,54 @@ public function testSetEmailThrowErrorIfNull()
$user = new User("Georges VI", "test@example.com");
$user->setEmail("");
}

public function testAddAndGetWorkingGroup()
{
$user = new User("Georges VI", "test@example.com");
$this->assertCount(0, $user->getWorkingGroups());

$workingGroup = $this->getMockBuilder(WorkingGroup::class)->disableOriginalConstructor()->getMock();
$user->addWorkingGroup($workingGroup);
$this->assertCount(1, $user->getWorkingGroups());
$this->assertSame($workingGroup, $user->getWorkingGroups()->first());
}

public function testAddAndGetWorkingGroupNoDuplicateObjectReference()
{
$user = new User("Georges VI", "test@example.com");
$this->assertCount(0, $user->getWorkingGroups());

$workingGroup = $this->getMockBuilder(WorkingGroup::class)->disableOriginalConstructor()->getMock();
$user->addWorkingGroup($workingGroup);
$user->addWorkingGroup($workingGroup);
$this->assertCount(1, $user->getWorkingGroups());
}

public function testSetAndGetWorkingGroups()
{
$user = new User("Georges VI", "test@example.com");
$this->assertCount(0, $user->getWorkingGroups());

$workingGroup = $this->getMockBuilder(WorkingGroup::class)->disableOriginalConstructor()->getMock();
$wGCollection = new ArrayCollection();
$wGCollection->add($workingGroup);
$user->setWorkingGroups($wGCollection);

$this->assertCount(1, $user->getWorkingGroups());
$this->assertSame($workingGroup, $user->getWorkingGroups()->first());
}

public function testSetEmptyArrayCollectionAndGetNullWorkingGroups()
{
$user = new User("Georges VI", "test@example.com");
$workingGroup = $this->getMockBuilder(WorkingGroup::class)->disableOriginalConstructor()->getMock();
$wGCollection = new ArrayCollection();
$wGCollection->add($workingGroup);
$user->setWorkingGroups($wGCollection);
$this->assertCount(1, $user->getWorkingGroups());
$this->assertSame($workingGroup, $user->getWorkingGroups()->first());

$user->setWorkingGroups(new ArrayCollection());
$this->assertCount(0, $user->getWorkingGroups());
}
}

0 comments on commit 8a7584f

Please sign in to comment.