Test Failed
Pull Request — master (#476)
by
unknown
03:09
created

AddCommand::tryCreateUser()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 7
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 10
ccs 0
cts 5
cp 0
crap 6
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace App\Command\Fixture;
6
7
use App\Blog\Entity\Comment;
8
use App\Blog\Entity\Post;
9
use App\Blog\Entity\Tag;
10
use App\Blog\Tag\TagRepository;
11
use App\User\User;
12
use App\User\UserLogin;
13
use App\User\UserLoginException;
14
use App\User\UserPassword;
15
use App\User\UserPasswordException;
16
use Cycle\ORM\EntityManager;
17
use DateTimeImmutable;
18
use Exception;
19
use Faker\Factory;
20
use Faker\Generator;
21
use Symfony\Component\Console\Command\Command;
22
use Symfony\Component\Console\Input\InputArgument;
23
use Symfony\Component\Console\Input\InputInterface;
24
use Symfony\Component\Console\Output\OutputInterface;
25
use Symfony\Component\Console\Style\SymfonyStyle;
26
use Yiisoft\Yii\Console\ExitCode;
27
use Yiisoft\Yii\Cycle\Command\CycleDependencyProxy;
28
use Yiisoft\Yii\Cycle\Data\Writer\EntityWriter;
29
30
final class AddCommand extends Command
31
{
32
    protected static $defaultName = 'fixture/add';
33
34
    private CycleDependencyProxy $promise;
35
    private EntityManager $entityManager;
36
    private Generator $faker;
37
    /** @var User[] */
38
    private array $users = [];
39
    /** @var Tag[] */
40
    private array $tags = [];
41
42
    private const DEFAULT_COUNT = 10;
43
44
    public function __construct(
45
        CycleDependencyProxy $promise,
46
        EntityManager $entityManager
47
    ) {
48
        $this->promise = $promise;
49
        $this->entityManager = $entityManager;
50
        parent::__construct();
51
    }
52
53
    public function configure(): void
54
    {
55
        $this
56
            ->setDescription('Add fixtures')
57
            ->setHelp('This command adds random content')
58
            ->addArgument('count', InputArgument::OPTIONAL, 'Count', self::DEFAULT_COUNT);
59
    }
60
61
    protected function execute(InputInterface $input, OutputInterface $output): int
62
    {
63
        $io = new SymfonyStyle($input, $output);
64
65
        $count = (int)$input->getArgument('count');
66
        // get faker
67
        if (!class_exists(Factory::class)) {
68
            $io->error('Faker should be installed. Run `composer install --dev`');
69
            return ExitCode::UNSPECIFIED_ERROR;
70
        }
71
        $this->faker = Factory::create();
72
73
        try {
74
            $this->addUsers($count);
75
            $this->addTags($count);
76
            $this->addPosts($count);
77
78
            $this->saveEntities();
79
        } catch (\Throwable $t) {
80
            $io->error($t->getMessage());
81
            return $t->getCode() ?: ExitCode::UNSPECIFIED_ERROR;
82
        }
83
        $io->success('Done');
84
        return ExitCode::OK;
85
    }
86
87
    private function saveEntities(): void
88
    {
89
        (new EntityWriter($this->entityManager))->write($this->users);
90
    }
91
92
    private function addUsers(int $count): void
93
    {
94
        /** @var \App\User\UserRepository $userRepository */
95
        $userRepository = $this->promise
96
            ->getORM()
97
            ->getRepository(User::class);
98
        for ($i = 0; $i < $count; ++$i) {
99
            $user = $this->tryCreateUser($userRepository);
100
            $this->users[] = $user;
101
        }
102
    }
103
104
    private function tryCreateUser(\App\User\UserRepository $userRepository): User
105
    {
106
        $login = $this->faker->firstName . rand(0, 9999);
107
        try {
108
            return new User(
109
                UserLogin::createNew($login, $userRepository),
110
                UserPassword::createNew($login)
111
            );
112
        } catch (UserLoginException|UserPasswordException) {
113
            return $this->tryCreateUser($userRepository);
114
        }
115
    }
116
117
    private function addTags(int $count): void
118
    {
119
        /** @var TagRepository $tagRepository */
120
        $tagRepository = $this->promise
121
            ->getORM()
122
            ->getRepository(Tag::class);
123
        $this->tags = [];
124
        $tagWords = [];
125
        for ($i = 0, $fails = 0; $i < $count; ++$i) {
126
            $word = $this->faker->word();
127
            if (in_array($word, $tagWords, true)) {
128
                --$i;
129
                ++$fails;
130
                if ($fails >= $count) {
131
                    break;
132
                }
133
                continue;
134
            }
135
            $tagWords[] = $word;
136
            $tag = $tagRepository->getOrCreate($word);
137
            $this->tags[] = $tag;
138
        }
139
    }
140
141
    private function addPosts(int $count): void
142
    {
143
        if (empty($this->users)) {
144
            throw new Exception('No users');
145
        }
146
        for ($i = 0; $i < $count; ++$i) {
147
            /** @var User $postUser */
148
            $postUser = $this->users[array_rand($this->users)];
149
            $post = new Post($this->faker->text(64), $this->faker->realText(rand(1000, 4000)));
150
            $postUser->addPost($post);
151
            $public = rand(0, 2) > 0;
152
            $post->setPublic($public);
153
            if ($public) {
154
                $post->setPublishedAt(new DateTimeImmutable(date('r', rand(time(), strtotime('-2 years')))));
155
            }
156
            // link tags
157
            $postTags = (array)array_rand($this->tags, rand(1, count($this->tags)));
158
            foreach ($postTags as $tagId) {
159
                $tag = $this->tags[$tagId];
160
                $post->addTag($tag);
161
                // todo: uncomment when issue is resolved https://github.com/cycle/orm/issues/70
162
                // $tag->addPost($post);
163
            }
164
            // add comments
165
            $commentsCount = rand(0, $count);
166
            for ($j = 0; $j <= $commentsCount; ++$j) {
167
                $comment = new Comment($this->faker->realText(rand(100, 500)));
168
                $commentPublic = rand(0, 3) > 0;
169
                $comment->setPublic($commentPublic);
170
                if ($commentPublic) {
171
                    $comment->setPublishedAt(new DateTimeImmutable(date('r', rand(time(), strtotime('-1 years')))));
172
                }
173
                $commentUser = $this->users[array_rand($this->users)];
174
                $commentUser->addComment($comment);
175
                $comment->setPost($post);
176
            }
177
        }
178
    }
179
}
180