User and Invite entities added. DTO CreateUserRequest and form type CreateUserRequestType added.

This commit is contained in:
Alexey Skobkin 2018-06-24 01:45:18 +03:00
parent 582def6c2d
commit 13d001272d
7 changed files with 633 additions and 1 deletions

View file

@ -18,6 +18,7 @@
"sensio/framework-extra-bundle": "^5.1", "sensio/framework-extra-bundle": "^5.1",
"symfony/console": "^4.1", "symfony/console": "^4.1",
"symfony/flex": "^1.0", "symfony/flex": "^1.0",
"symfony/form": "^4.1",
"symfony/framework-bundle": "^4.1", "symfony/framework-bundle": "^4.1",
"symfony/lts": "^4@dev", "symfony/lts": "^4@dev",
"symfony/monolog-bundle": "^3.3", "symfony/monolog-bundle": "^3.3",
@ -26,6 +27,7 @@
"symfony/serializer-pack": "^1.0", "symfony/serializer-pack": "^1.0",
"symfony/translation": "^4.1", "symfony/translation": "^4.1",
"symfony/twig-bundle": "^4.1", "symfony/twig-bundle": "^4.1",
"symfony/validator": "^4.1",
"symfony/web-server-bundle": "^4.1", "symfony/web-server-bundle": "^4.1",
"symfony/yaml": "^4.1", "symfony/yaml": "^4.1",
"white-october/pagerfanta-bundle": "^1.2" "white-october/pagerfanta-bundle": "^1.2"

356
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "b6ca92cab0ca13436da7c0a3acde22ad", "content-hash": "0b2aebb419be98d3475cfe76e436f2b0",
"packages": [ "packages": [
{ {
"name": "doctrine/annotations", "name": "doctrine/annotations",
@ -2270,6 +2270,87 @@
], ],
"time": "2018-05-02T19:08:56+00:00" "time": "2018-05-02T19:08:56+00:00"
}, },
{
"name": "symfony/form",
"version": "v4.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/form.git",
"reference": "95f8237303e1f7101fee0e72d6ba630a3e4c5178"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/form/zipball/95f8237303e1f7101fee0e72d6ba630a3e4c5178",
"reference": "95f8237303e1f7101fee0e72d6ba630a3e4c5178",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"symfony/event-dispatcher": "~3.4|~4.0",
"symfony/intl": "~3.4|~4.0",
"symfony/options-resolver": "~3.4|~4.0",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.0",
"symfony/property-access": "~3.4|~4.0"
},
"conflict": {
"phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0",
"symfony/dependency-injection": "<3.4",
"symfony/doctrine-bridge": "<3.4",
"symfony/framework-bundle": "<3.4",
"symfony/http-kernel": "<3.4",
"symfony/twig-bridge": "<3.4.5|<4.0.5,>=4.0"
},
"require-dev": {
"doctrine/collections": "~1.0",
"symfony/config": "~3.4|~4.0",
"symfony/console": "~3.4|~4.0",
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/http-foundation": "~3.4|~4.0",
"symfony/http-kernel": "~3.4|~4.0",
"symfony/security-csrf": "~3.4|~4.0",
"symfony/translation": "~3.4|~4.0",
"symfony/validator": "~3.4|~4.0",
"symfony/var-dumper": "~3.4|~4.0"
},
"suggest": {
"symfony/framework-bundle": "For templating with PHP.",
"symfony/security-csrf": "For protecting forms against CSRF attacks.",
"symfony/twig-bridge": "For templating with Twig.",
"symfony/validator": "For form validation."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Form\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Form Component",
"homepage": "https://symfony.com",
"time": "2018-05-30T07:26:09+00:00"
},
{ {
"name": "symfony/framework-bundle", "name": "symfony/framework-bundle",
"version": "v4.1.0", "version": "v4.1.0",
@ -2584,6 +2665,81 @@
], ],
"time": "2018-05-01T23:02:13+00:00" "time": "2018-05-01T23:02:13+00:00"
}, },
{
"name": "symfony/intl",
"version": "v4.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/intl.git",
"reference": "e2a48225f7d525b23a6e34caaa7320205abcf179"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/intl/zipball/e2a48225f7d525b23a6e34caaa7320205abcf179",
"reference": "e2a48225f7d525b23a6e34caaa7320205abcf179",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"symfony/polyfill-intl-icu": "~1.0"
},
"require-dev": {
"symfony/filesystem": "~3.4|~4.0"
},
"suggest": {
"ext-intl": "to use the component with locales other than \"en\""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Intl\\": ""
},
"classmap": [
"Resources/stubs"
],
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Bernhard Schussek",
"email": "bschussek@gmail.com"
},
{
"name": "Eriksen Costa",
"email": "eriksen.costa@infranology.com.br"
},
{
"name": "Igor Wiedler",
"email": "igor@wiedler.ch"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "A PHP replacement layer for the C intl extension that includes additional data from the ICU library.",
"homepage": "https://symfony.com",
"keywords": [
"i18n",
"icu",
"internationalization",
"intl",
"l10n",
"localization"
],
"time": "2018-05-30T07:26:09+00:00"
},
{ {
"name": "symfony/lts", "name": "symfony/lts",
"version": "dev-master", "version": "dev-master",
@ -2806,6 +2962,60 @@
], ],
"time": "2018-06-04T05:55:43+00:00" "time": "2018-06-04T05:55:43+00:00"
}, },
{
"name": "symfony/options-resolver",
"version": "v4.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
"reference": "9b9ab6043c57c8c5571bc846e6ebfd27dff3b589"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/9b9ab6043c57c8c5571bc846e6ebfd27dff3b589",
"reference": "9b9ab6043c57c8c5571bc846e6ebfd27dff3b589",
"shasum": ""
},
"require": {
"php": "^7.1.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\OptionsResolver\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony OptionsResolver Component",
"homepage": "https://symfony.com",
"keywords": [
"config",
"configuration",
"options"
],
"time": "2018-05-30T07:26:09+00:00"
},
{ {
"name": "symfony/orm-pack", "name": "symfony/orm-pack",
"version": "v1.0.5", "version": "v1.0.5",
@ -2834,6 +3044,64 @@
"description": "A pack for the Doctrine ORM", "description": "A pack for the Doctrine ORM",
"time": "2017-12-12T01:47:50+00:00" "time": "2017-12-12T01:47:50+00:00"
}, },
{
"name": "symfony/polyfill-intl-icu",
"version": "v1.8.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-icu.git",
"reference": "80ee17ae83c10cd513e5144f91a73607a21edb4e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/80ee17ae83c10cd513e5144f91a73607a21edb4e",
"reference": "80ee17ae83c10cd513e5144f91a73607a21edb4e",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"symfony/intl": "~2.3|~3.0|~4.0"
},
"suggest": {
"ext-intl": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.8-dev"
}
},
"autoload": {
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for intl's ICU-related data and classes",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"icu",
"intl",
"polyfill",
"portable",
"shim"
],
"time": "2018-04-25T14:53:50+00:00"
},
{ {
"name": "symfony/polyfill-mbstring", "name": "symfony/polyfill-mbstring",
"version": "v1.8.0", "version": "v1.8.0",
@ -3665,6 +3933,92 @@
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2018-05-16T14:41:07+00:00" "time": "2018-05-16T14:41:07+00:00"
}, },
{
"name": "symfony/validator",
"version": "v4.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/validator.git",
"reference": "f07bc14af6759710fb4639811a8240650d89786a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/validator/zipball/f07bc14af6759710fb4639811a8240650d89786a",
"reference": "f07bc14af6759710fb4639811a8240650d89786a",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.0",
"symfony/translation": "~3.4|~4.0"
},
"conflict": {
"phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0",
"symfony/dependency-injection": "<3.4",
"symfony/http-kernel": "<3.4",
"symfony/intl": "<4.1",
"symfony/yaml": "<3.4"
},
"require-dev": {
"doctrine/annotations": "~1.0",
"doctrine/cache": "~1.0",
"egulias/email-validator": "^1.2.8|~2.0",
"symfony/cache": "~3.4|~4.0",
"symfony/config": "~3.4|~4.0",
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/expression-language": "~3.4|~4.0",
"symfony/http-foundation": "~4.1",
"symfony/http-kernel": "~3.4|~4.0",
"symfony/intl": "~4.1",
"symfony/property-access": "~3.4|~4.0",
"symfony/var-dumper": "~3.4|~4.0",
"symfony/yaml": "~3.4|~4.0"
},
"suggest": {
"doctrine/annotations": "For using the annotation mapping. You will also need doctrine/cache.",
"doctrine/cache": "For using the default cached annotation reader and metadata cache.",
"egulias/email-validator": "Strict (RFC compliant) email validation",
"psr/cache-implementation": "For using the metadata cache.",
"symfony/config": "",
"symfony/expression-language": "For using the Expression validator",
"symfony/http-foundation": "",
"symfony/intl": "",
"symfony/property-access": "For accessing properties within comparison constraints",
"symfony/yaml": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Validator\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Validator Component",
"homepage": "https://symfony.com",
"time": "2018-05-30T07:26:09+00:00"
},
{ {
"name": "symfony/web-server-bundle", "name": "symfony/web-server-bundle",
"version": "v4.1.0", "version": "v4.1.0",

70
src/Entity/Invite.php Normal file
View file

@ -0,0 +1,70 @@
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Table(name="invites", schema="users")
* @ORM\Entity()
*/
class Invite
{
/**
* @var int
*
* @ORM\Id()
* @ORM\GeneratedValue(strategy="AUTO")
* @ORM\Column(name="id", type="integer")
*/
private $id;
/**
* @var User
*
* @ORM\ManyToOne(targetEntity="App\Entity\User")
* @ORM\JoinColumn(name="user_id", nullable=false)
*/
private $user;
/**
* @var string
*
* @ORM\Column(name="code", type="string", length=32)
*/
private $code;
/**
* @var User|null
*
* @ORM\ManyToOne(targetEntity="App\Entity\User")
* @ORM\JoinColumn(name="used_by_id", nullable=true)
*/
private $usedBy;
public function __construct(User $user)
{
$this->user = $user;
$this->code = md5(random_bytes(100));
}
public function getId(): int
{
return $this->id;
}
public function getUser(): User
{
return $this->user;
}
public function getCode(): string
{
return $this->code;
}
public function getUsedBy(): ?User
{
return $this->usedBy;
}
}

121
src/Entity/User.php Normal file
View file

@ -0,0 +1,121 @@
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* @ORM\Table(name="users", schema="users")
* @ORM\Entity()
*/
class User implements UserInterface, \Serializable
{
/**
* @var int
*
* @ORM\Id
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="username", type="string", length=25, unique=true)
*/
private $username;
/**
* @var string
*
* @ORM\Column(name="password", type="text")
*/
private $password;
/**
* @var string
*
* @ORM\Column(name="email", type="string", length=254, unique=true)
*/
private $email;
/**
* @var Invite[]|ArrayCollection
*
* @ORM\OneToMany(targetEntity="App\Entity\Invite", mappedBy="user", fetch="EXTRA_LAZY")
*/
private $invites;
public function __construct(string $username, string $password, string $email)
{
$this->username = $username;
$this->password = $password;
$this->email = $email;
}
public function getId(): int
{
return $this->id;
}
public function getUsername()
{
return $this->username;
}
public function getPassword()
{
return $this->password;
}
public function getSalt()
{
// Salt is not needed when using Argon2i
// @see https://symfony.com/doc/current/reference/configuration/security.html#using-the-argon2i-password-encoder
return null;
}
public function getEmail(): string
{
return $this->email;
}
public function getRoles()
{
return ['ROLE_USER'];
}
public function eraseCredentials()
{
}
/** @return Invite[]|ArrayCollection */
public function getInvites(): \Traversable
{
return $this->invites;
}
/** @see \Serializable::serialize() */
public function serialize()
{
return serialize([
$this->id,
$this->username,
$this->password,
]);
}
/** @see \Serializable::unserialize() */
public function unserialize($serialized)
{
list(
$this->id,
$this->username,
$this->password
) = unserialize($serialized, ['allowed_classes' => false]);
}
}

View file

@ -0,0 +1,39 @@
<?php
namespace App\Form;
use Symfony\Component\Validator\Constraints as Assert;
class CreateUserRequest
{
/**
* @var string
*
* @Assert\NotBlank()
* @Assert\Length(min="2", max="25")
*/
public $username;
/**
* @var string
*
* @Assert\NotBlank()
* @Assert\Length(min="8")
*/
public $password;
/**
* @var string
*
* @Assert\Email()
*/
public $email;
/**
* @var string
*
* @Assert\NotBlank()
* @Assert\Length(min="32", max="32")
*/
public $inviteCode;
}

View file

@ -0,0 +1,31 @@
<?php
namespace App\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class CreateUserRequestType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('username', TextType::class)
->add('password', PasswordType::class)
->add('email', EmailType::class)
->add('inviteCode', TextType::class)
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => CreateUserRequest::class,
]);
}
}

View file

@ -146,6 +146,9 @@
"ref": "e921bdbfe20cdefa3b82f379d1cd36df1bc8d115" "ref": "e921bdbfe20cdefa3b82f379d1cd36df1bc8d115"
} }
}, },
"symfony/form": {
"version": "v4.1.0"
},
"symfony/framework-bundle": { "symfony/framework-bundle": {
"version": "3.3", "version": "3.3",
"recipe": { "recipe": {
@ -164,6 +167,9 @@
"symfony/inflector": { "symfony/inflector": {
"version": "v4.1.0" "version": "v4.1.0"
}, },
"symfony/intl": {
"version": "v4.1.0"
},
"symfony/lts": { "symfony/lts": {
"version": "4-dev" "version": "4-dev"
}, },
@ -179,9 +185,15 @@
"ref": "371d1a2b69984710646b09a1182ef1d4308c904f" "ref": "371d1a2b69984710646b09a1182ef1d4308c904f"
} }
}, },
"symfony/options-resolver": {
"version": "v4.1.0"
},
"symfony/orm-pack": { "symfony/orm-pack": {
"version": "v1.0.5" "version": "v1.0.5"
}, },
"symfony/polyfill-intl-icu": {
"version": "v1.8.0"
},
"symfony/polyfill-mbstring": { "symfony/polyfill-mbstring": {
"version": "v1.8.0" "version": "v1.8.0"
}, },
@ -245,6 +257,9 @@
"ref": "f75ac166398e107796ca94cc57fa1edaa06ec47f" "ref": "f75ac166398e107796ca94cc57fa1edaa06ec47f"
} }
}, },
"symfony/validator": {
"version": "v4.1.0"
},
"symfony/var-dumper": { "symfony/var-dumper": {
"version": "v4.1.0" "version": "v4.1.0"
}, },