File size: 5,045 Bytes
d2897cd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
<?php

namespace Mautic\PluginBundle\Bundle;

use Doctrine\DBAL\Schema\Comparator;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\ORM\Tools\SchemaTool;
use Mautic\CoreBundle\Factory\MauticFactory;
use Mautic\PluginBundle\Entity\Plugin;
use Symfony\Component\HttpKernel\Bundle\Bundle;

/**
 * Base Bundle class which should be extended by addon bundles.
 */
abstract class PluginBundleBase extends Bundle
{
    /**
     * @throws \Exception
     *
     * @deprecated To be removed in 5.0. Listen to PluginEvents::ON_PLUGIN_INSTALL instead
     */
    public static function onPluginInstall(Plugin $plugin, MauticFactory $factory, $metadata = null, $installedSchema = null): void
    {
        if (null !== $metadata) {
            self::installPluginSchema($metadata, $factory, $installedSchema);
        }
    }

    /**
     * Install plugin schema based on Doctrine metadata.
     *
     * @throws \Exception
     */
    public static function installPluginSchema(array $metadata, MauticFactory $factory, $installedSchema = null): void
    {
        if (null !== $installedSchema) {
            // Schema already exists, so no need to proceed
            return;
        }

        $db             = $factory->getDatabase();
        $schemaTool     = new SchemaTool($factory->getEntityManager());
        $installQueries = $schemaTool->getCreateSchemaSql($metadata);

        foreach ($installQueries as $q) {
            // Check if the query is a DDL statement
            if (self::isDDLStatement($q)) {
                // Execute DDL statements outside of a transaction
                $db->executeQuery($q);
            } else {
                // For non-DDL statements, use transactions
                try {
                    $db->beginTransaction();
                    $db->executeQuery($q);
                    $db->commit();
                } catch (\Exception $e) {
                    // Rollback only for non-DDL statements
                    if ($db->isTransactionActive()) {
                        $db->rollBack();
                    }
                    throw $e;
                }
            }
        }
    }

    private static function isDDLStatement(string $query): bool|int
    {
        return preg_match('/^(CREATE|ALTER|DROP|RENAME|TRUNCATE|COMMENT)\s/i', $query);
    }

    /**
     * Called by PluginController::reloadAction when the addon version does not match what's installed.
     *
     * @throws \Exception
     *
     * @deprecated To be removed in 5.0. Listen to PluginEvents::ON_PLUGIN_UPDATE instead
     */
    public static function onPluginUpdate(
        Plugin $plugin,
        MauticFactory $factory,
        $metadata = null,
        Schema $installedSchema = null
    ): void {
        // Not recommended although availalbe for simple schema changes - see updatePluginSchema docblock
        // self::updatePluginSchema($metadata, $installedSchema, $factory);
    }

    /**
     * Update plugin schema based on Doctrine metadata.
     *
     * WARNING - this is not recommended as Doctrine does not guarantee results. There is a risk
     * that Doctrine will generate an incorrect query leading to lost data. If using this method,
     * be sure to thoroughly test the queries Doctrine generates
     *
     * @throws \Doctrine\DBAL\ConnectionException
     * @throws \Exception
     */
    public static function updatePluginSchema(array $metadata, Schema $installedSchema, MauticFactory $factory): void
    {
        $db               = $factory->getDatabase();
        $schemaTool       = new SchemaTool($factory->getEntityManager());
        $toSchema         = $schemaTool->getSchemaFromMetadata($metadata);
        $comparator       = (new Comparator())->compareSchemas($installedSchema, $toSchema);
        $databasePlatform = $db->getDatabasePlatform();
        $queries          = $databasePlatform->getAlterSchemaSQL($comparator);

        $db->beginTransaction();
        try {
            foreach ($queries as $q) {
                $db->executeQuery($q);
            }

            $db->commit();
        } catch (\Exception $e) {
            $db->rollback();

            throw $e;
        }
    }

    /**
     * Not used yet :-).
     */
    public static function onPluginUninstall(Plugin $plugin, MauticFactory $factory, $metadata = null): void
    {
    }

    /**
     * Drops plugin's tables based on Doctrine metadata.
     *
     * @throws \Doctrine\DBAL\ConnectionException
     * @throws \Exception
     */
    public static function dropPluginSchema(array $metadata, MauticFactory $factory): void
    {
        $db          = $factory->getDatabase();
        $schemaTool  = new SchemaTool($factory->getEntityManager());
        $dropQueries = $schemaTool->getDropSchemaSQL($metadata);

        $db->beginTransaction();
        try {
            foreach ($dropQueries as $q) {
                $db->executeQuery($q);
            }

            $db->commit();
        } catch (\Exception $e) {
            $db->rollback();

            throw $e;
        }
    }
}