Test Failed
Pull Request — master (#13)
by
unknown
02:16
created

OracleMutex::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 18
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 8
c 1
b 0
f 0
dl 0
loc 18
rs 10
cc 2
nc 2
nop 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Mutex;
6
7
use InvalidArgumentException;
8
use PDO;
9
10
/**
11
 * OracleMutex implements mutex "lock" mechanism via Oracle locks.
12
 *
13
 * Application configuration example:
14
 *
15
 * @see http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_lock.htm
16
 */
17
class OracleMutex implements MutexInterface
18
{
19
    /** available lock modes */
20
    public const MODE_X = 'X_MODE';
21
    public const MODE_NL = 'NL_MODE';
22
    public const MODE_S = 'S_MODE';
23
    public const MODE_SX = 'SX_MODE';
24
    public const MODE_SS = 'SS_MODE';
25
    public const MODE_SSX = 'SSX_MODE';
26
27
    protected PDO $connection;
28
    private bool $released = false;
29
30
    /**
31
     * @var string lock mode to be used.
32
     *
33
     * @see http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_lock.htm#CHDBCFDI
34
     */
35
    private string $lockMode;
36
    /**
37
     * @var bool whether to release lock on commit.
38
     */
39
    private bool $releaseOnCommit;
40
41
    private string $name;
42
43
    /**
44
     * OracleMutex constructor.
45
     *
46
     * @param string $name Mutex name.
47
     * @param PDO $connection PDO connection instance to use.
48
     * @param string $lockMode Lock mode to be used.
49
     * @param bool $releaseOnCommit Whether to release lock on commit.
50
     */
51
    public function __construct(
52
        string $name,
53
        PDO $connection,
54
        string $lockMode = self::MODE_X,
55
        bool $releaseOnCommit = false
56
    ) {
57
        $this->name = $name;
58
        $this->connection = $connection;
59
60
        $driverName = $connection->getAttribute(PDO::ATTR_DRIVER_NAME);
61
        if (in_array($driverName, ['oci', 'obdb'])) {
62
            throw new InvalidArgumentException(
63
                'Connection must be configured to use Oracle database. Got ' . $driverName . '.'
64
            );
65
        }
66
67
        $this->lockMode = $lockMode;
68
        $this->releaseOnCommit = $releaseOnCommit;
69
    }
70
71
    public function __destruct()
72
    {
73
        if (!$this->released) {
74
            $this->release();
75
        }
76
    }
77
78
    /**
79
     * {@inheritdoc}
80
     *
81
     * @see http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_lock.htm
82
     */
83
    public function acquire(int $timeout = 0): bool
84
    {
85
        $lockStatus = null;
86
87
        // clean vars before using
88
        $releaseOnCommit = $this->releaseOnCommit ? 'TRUE' : 'FALSE';
89
        $timeout = (int) abs($timeout);
90
91
        // inside pl/sql scopes pdo binding not working correctly :(
92
93
        $statement = $this->connection->prepare('DECLARE
94
            handle VARCHAR2(128);
95
        BEGIN
96
            DBMS_LOCK.ALLOCATE_UNIQUE(:name, handle);
97
            :lockStatus := DBMS_LOCK.REQUEST(
98
                handle,
99
                DBMS_LOCK.' . $this->lockMode . ',
100
                ' . $timeout . ',
101
                ' . $releaseOnCommit . '
102
            );
103
        END;');
104
105
        $statement->bindValue(':name', $this->name);
106
        $statement->bindParam(':lockStatus', $lockStatus, PDO::PARAM_INT, 1);
107
        $statement->execute();
108
109
        if ($lockStatus === 0 || $lockStatus === '0') {
110
            $this->released = false;
111
            return true;
112
        }
113
114
        return false;
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     *
120
     * @see http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_lock.htm
121
     */
122
    public function release(): void
123
    {
124
        $releaseStatus = null;
125
126
        $statement = $this->connection->prepare(
127
            'DECLARE
128
                handle VARCHAR2(128);
129
            BEGIN
130
                DBMS_LOCK.ALLOCATE_UNIQUE(:name, handle);
131
                :result := DBMS_LOCK.RELEASE(handle);
132
            END;'
133
        );
134
        $statement->bindValue(':name', $this->name);
135
        $statement->bindParam(':result', $releaseStatus, PDO::PARAM_INT, 1);
136
        $statement->execute();
137
138
        if ($releaseStatus !== 0 && $releaseStatus !== '0') {
139
            throw new RuntimeExceptions("Unable to release lock \"$this->name\".");
0 ignored issues
show
Bug introduced by
The type Yiisoft\Mutex\RuntimeExceptions was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
140
        }
141
142
        $this->released = true;
143
    }
144
}
145