ConvertBBCodeCommand::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
c 0
b 0
f 0
nc 1
nop 2
dl 0
loc 8
rs 10
1
<?php
2
/**
3
 * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
4
 *
5
 * Copyright (C) 2019 - 2022 Jan Böhmer (https://github.com/jbtronics)
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Affero General Public License as published
9
 * by the Free Software Foundation, either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License
18
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19
 */
20
21
declare(strict_types=1);
22
23
namespace App\Command\Migrations;
24
25
use App\Entity\Attachments\AttachmentType;
26
use App\Entity\Base\AbstractNamedDBElement;
27
use App\Entity\ProjectSystem\Project;
28
use App\Entity\Parts\Category;
29
use App\Entity\Parts\Manufacturer;
30
use App\Entity\Parts\MeasurementUnit;
31
use App\Entity\Parts\Part;
32
use App\Entity\Parts\Storelocation;
33
use App\Entity\Parts\Supplier;
34
use App\Entity\PriceInformations\Currency;
35
use App\Entity\UserSystem\Group;
36
use App\Helpers\BBCodeToMarkdownConverter;
37
use Doctrine\ORM\EntityManagerInterface;
38
use Doctrine\ORM\EntityRepository;
39
use Symfony\Component\Console\Command\Command;
40
use Symfony\Component\Console\Input\InputInterface;
41
use Symfony\Component\Console\Output\OutputInterface;
42
use Symfony\Component\Console\Style\SymfonyStyle;
43
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
44
45
use function count;
46
47
/**
48
 * This command converts the BBCode used by old Part-DB versions (<1.0), to the current used markdown format.
49
 */
50
class ConvertBBCodeCommand extends Command
51
{
52
    /**
53
     * @var string The LIKE criteria used to detect on SQL server if a entry contains BBCode
54
     */
55
    protected const BBCODE_CRITERIA = '%[%]%[/%]%';
56
    /**
57
     * @var string The regex (performed in PHP) used to check if a property really contains BBCODE
58
     */
59
    protected const BBCODE_REGEX = '/\\[.+\\].*\\[\\/.+\\]/';
60
61
    protected static $defaultName = 'partdb:migrations:convert-bbcode|app:convert-bbcode';
62
63
    protected EntityManagerInterface $em;
64
    protected PropertyAccessorInterface $propertyAccessor;
65
    protected BBCodeToMarkdownConverter $converter;
66
67
    public function __construct(EntityManagerInterface $entityManager, PropertyAccessorInterface $propertyAccessor)
68
    {
69
        $this->em = $entityManager;
70
        $this->propertyAccessor = $propertyAccessor;
71
72
        $this->converter = new BBCodeToMarkdownConverter();
73
74
        parent::__construct();
75
    }
76
77
    protected function configure(): void
78
    {
79
        $this
80
            ->setDescription('Converts BBCode used in old Part-DB versions to newly used Markdown')
81
            ->setHelp('Older versions of Part-DB (<1.0) used BBCode for rich text formatting.
82
                Part-DB now uses Markdown which offers more features but is incompatible with BBCode.
83
                When you upgrade from an pre 1.0 version you have to run this command to convert your comment fields');
84
85
        $this->addOption('dry-run', null, null, 'Do not save changes to DB. In combination with -v or -vv you can check what will be changed!');
86
    }
87
88
    /**
89
     * Returns a list which entities and which properties need to be checked.
90
     */
91
    protected function getTargetsLists(): array
92
    {
93
        return [
94
            Part::class => ['description', 'comment'],
95
            AttachmentType::class => ['comment'],
96
            Storelocation::class => ['comment'],
97
            Project::class => ['comment'],
98
            Category::class => ['comment'],
99
            Manufacturer::class => ['comment'],
100
            MeasurementUnit::class => ['comment'],
101
            Supplier::class => ['comment'],
102
            Currency::class => ['comment'],
103
            Group::class => ['comment'],
104
        ];
105
    }
106
107
    protected function execute(InputInterface $input, OutputInterface $output): int
108
    {
109
        $io = new SymfonyStyle($input, $output);
110
        $targets = $this->getTargetsLists();
111
112
        //Convert for every class target
113
        foreach ($targets as $class => $properties) {
114
            $io->section(sprintf('Convert entities of class %s', $class));
115
            $io->note(sprintf(
116
                'Search for entities of type %s that need conversion',
117
                $class
118
            ));
119
            //Determine which entities of this type we need to modify
120
            /** @var EntityRepository $repo */
121
            $repo = $this->em->getRepository($class);
122
            $qb = $repo->createQueryBuilder('e')
123
                ->select('e');
124
            //Add fields criteria
125
            foreach ($properties as $key => $property) {
126
                $qb->orWhere('e.'.$property.' LIKE ?'.$key);
127
                $qb->setParameter($key, static::BBCODE_CRITERIA);
128
            }
129
130
            //Fetch resulting classes
131
            $results = $qb->getQuery()->getResult();
132
            $io->note(sprintf('Found %d entities, that need to be converted!', count($results)));
0 ignored issues
show
Bug introduced by
It seems like $results can also be of type integer; however, parameter $value of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

132
            $io->note(sprintf('Found %d entities, that need to be converted!', count(/** @scrutinizer ignore-type */ $results)));
Loading history...
133
134
            //In verbose mode print the names of the entities
135
            foreach ($results as $result) {
136
                /** @var AbstractNamedDBElement $result */
137
                $io->writeln(
138
                    'Convert entity: '.$result->getName().' ('.get_class($result).': '.$result->getID().')',
139
                    OutputInterface::VERBOSITY_VERBOSE
140
                );
141
                foreach ($properties as $property) {
142
                    //Retrieve bbcode from entity
143
                    $bbcode = $this->propertyAccessor->getValue($result, $property);
144
                    //Check if the current property really contains BBCode
145
                    if (!preg_match(static::BBCODE_REGEX, $bbcode)) {
146
                        continue;
147
                    }
148
                    $io->writeln(
149
                        'BBCode (old): '
150
                        .str_replace('\n', ' ', substr($bbcode, 0, 255)),
151
                        OutputInterface::VERBOSITY_VERY_VERBOSE
152
                    );
153
                    $markdown = $this->converter->convert($bbcode);
154
                    $io->writeln(
155
                        'Markdown (new): '
156
                        .str_replace('\n', ' ', substr($markdown, 0, 255)),
157
                        OutputInterface::VERBOSITY_VERY_VERBOSE
158
                    );
159
                    $io->writeln('', OutputInterface::VERBOSITY_VERY_VERBOSE);
160
                    $this->propertyAccessor->setValue($result, $property, $markdown);
161
                }
162
            }
163
        }
164
165
        //If we are not in dry run, save changes to DB
166
        if (!$input->getOption('dry-run')) {
167
            $this->em->flush();
168
            $io->success('Changes saved to DB successfully!');
169
        }
170
171
        return 0;
172
    }
173
}
174