Completed
Push — master ( c814ba...8cfaee )
by Jan
04:18
created

ConvertBBCodeCommand::configure()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 9
rs 10
1
<?php
2
/**
3
 *
4
 * part-db version 0.1
5
 * Copyright (C) 2005 Christoph Lechner
6
 * http://www.cl-projects.de/
7
 *
8
 * part-db version 0.2+
9
 * Copyright (C) 2009 K. Jacobs and others (see authors.php)
10
 * http://code.google.com/p/part-db/
11
 *
12
 * Part-DB Version 0.4+
13
 * Copyright (C) 2016 - 2019 Jan Böhmer
14
 * https://github.com/jbtronics
15
 *
16
 * This program is free software; you can redistribute it and/or
17
 * modify it under the terms of the GNU General Public License
18
 * as published by the Free Software Foundation; either version 2
19
 * of the License, or (at your option) any later version.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU General Public License
27
 * along with this program; if not, write to the Free Software
28
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
29
 *
30
 */
31
32
namespace App\Command;
33
34
35
use App\Entity\Attachments\AttachmentType;
36
use App\Entity\Base\NamedDBElement;
37
use App\Entity\Devices\Device;
38
use App\Entity\Parts\Category;
39
use App\Entity\Parts\Manufacturer;
40
use App\Entity\Parts\MeasurementUnit;
41
use App\Entity\Parts\Part;
42
use App\Entity\Parts\Storelocation;
43
use App\Entity\Parts\Supplier;
44
use App\Entity\PriceInformations\Currency;
45
use App\Entity\UserSystem\Group;
46
use App\Helpers\BBCodeToMarkdownConverter;
47
use Doctrine\ORM\EntityManagerInterface;
48
use Doctrine\ORM\EntityRepository;
49
use Symfony\Component\Console\Command\Command;
50
use Symfony\Component\Console\Input\InputInterface;
51
use Symfony\Component\Console\Output\OutputInterface;
52
use Symfony\Component\Console\Style\SymfonyStyle;
53
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
54
55
/**
56
 * This command converts the BBCode used by old Part-DB versions (<1.0), to the current used markdown format.
57
 * @package App\Command
58
 */
59
class ConvertBBCodeCommand extends Command
60
{
61
    /** @var string The LIKE criteria used to detect on SQL server if a entry contains BBCode */
62
    protected const BBCODE_CRITERIA = "%[%]%[/%]%";
63
    /** @var string The regex (performed in PHP) used to check if a property really contains BBCODE  */
64
    protected const BBCODE_REGEX = '/\\[.+\\].*\\[\\/.+\\]/';
65
66
    protected static $defaultName = 'app:convert-bbcode';
67
68
    protected $em;
69
    protected $propertyAccessor;
70
    protected $converter;
71
72
    public function __construct(EntityManagerInterface $entityManager, PropertyAccessorInterface $propertyAccessor)
73
    {
74
        $this->em = $entityManager;
75
        $this->propertyAccessor = $propertyAccessor;
76
77
        $this->converter = new BBCodeToMarkdownConverter();
78
79
        parent::__construct();
80
    }
81
82
    protected function configure()
83
    {
84
        $this
85
            ->setDescription('Converts BBCode used in old Part-DB versions to newly used Markdown')
86
            ->setHelp('Older versions of Part-DB (<1.0) used BBCode for rich text formatting.
87
                Part-DB now uses Markdown which offers more features but is incompatible with BBCode.
88
                When you upgrade from an pre 1.0 version you have to run this command to convert your comment fields');
89
90
        $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!');
91
    }
92
93
    /**
94
     * Returns a list which entities and which properties need to be checked.
95
     * @return array
96
     */
97
    protected function getTargetsLists() : array
98
    {
99
        return [
100
            Part::class => ['description', 'comment'],
101
            AttachmentType::class => ['comment'],
102
            Storelocation::class => ['comment'],
103
            Device::class => ['comment'],
104
            Category::class => ['comment'],
105
            Manufacturer::class => ['comment'],
106
            MeasurementUnit::class => ['comment'],
107
            Supplier::class => ['comment'],
108
            Currency::class => ['comment'],
109
            Group::class => ['comment'],
110
        ];
111
    }
112
113
    protected function execute(InputInterface $input, OutputInterface $output)
114
    {
115
        $io = new SymfonyStyle($input, $output);
116
        $targets = $this->getTargetsLists();
117
118
        //Convert for every class target
119
        foreach ($targets as $class => $properties) {
120
            $io->section(sprintf('Convert entities of class %s', $class));
121
            $io->note(sprintf(
122
                'Search for entities of type %s that need conversion',
123
                $class
124
            ));
125
            //Determine which entities of this type we need to modify
126
            /** @var EntityRepository $repo */
127
            $repo = $this->em->getRepository($class);
128
            $qb = $repo->createQueryBuilder('e')
129
                ->select('e');
130
            //Add fields criteria
131
            foreach ($properties as $key => $property) {
132
                $qb->orWhere('e.' . $property . ' LIKE ?' . $key);
133
                $qb->setParameter($key, static::BBCODE_CRITERIA);
134
            }
135
136
            //Fetch resulting classes
137
            $results = $qb->getQuery()->getResult();
138
            $io->note(sprintf('Found %d entities, that need to be converted!', count($results)));
139
140
            //In verbose mode print the names of the entities
141
            foreach ($results as $result) {
142
                /** @var NamedDBElement $result */
143
                $io->writeln(
144
                    'Convert entity: ' . $result->getName() . ' (' . $result->getIDString() . ')',
145
                    OutputInterface::VERBOSITY_VERBOSE
146
                );
147
                foreach ($properties as $property) {
148
                    //Retrieve bbcode from entity
149
                    $bbcode = $this->propertyAccessor->getValue($result, $property);
150
                    //Check if the current property really contains BBCode
151
                    if (!preg_match(static::BBCODE_REGEX, $bbcode)) {
152
                        continue;
153
                    }
154
                    $io->writeln(
155
                        'BBCode (old): '
156
                        . str_replace('\n', ' ', substr($bbcode, 0, 255)),
157
                        OutputInterface::VERBOSITY_VERY_VERBOSE
158
                    );
159
                    $markdown = $this->converter->convert($bbcode);
160
                    $io->writeln(
161
                        'Markdown (new): '
162
                        . str_replace('\n', ' ', substr($markdown, 0, 255)),
163
                        OutputInterface::VERBOSITY_VERY_VERBOSE
164
                    );
165
                    $io->writeln('', OutputInterface::VERBOSITY_VERY_VERBOSE);
166
                    $this->propertyAccessor->setValue($result, $property, $markdown);
167
                }
168
169
            }
170
        }
171
172
        //If we are not in dry run, save changes to DB
173
        if (!$input->getOption('dry-run')) {
174
            $this->em->flush();
175
            $io->success('Changes saved to DB successfully!');
176
        }
177
    }
178
179
180
}