Completed
Push — master ( 9614ea...2675c0 )
by Filippo
05:35 queued 02:49
created

AbstractCommand::castArg()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 24
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 24
rs 8.5125
cc 5
eloc 16
nc 5
nop 1
1
<?php
2
3
/**
4
 * @file AbstractCommand.php
5
 * @brief This file contains the AbstractCommand class.
6
 * @details
7
 * @author Filippo F. Fadda
8
 */
9
10
11
//! This is the Commands namespace.
12
namespace EoC\CLI\Command;
13
14
15
use EoC\Adapter\CurlAdapter;
16
use EoC\Couch;
17
18
use Symfony\Component\Console\Command\Command;
19
20
21
/**
22
 * @brief This class represents an abstract command that implements the InjectionAwareInterface to automatic set the
23
 * Phalcon Dependency Injector and make it available to every subclasses.
24
 * @nosubgrouping
25
 */
26
abstract class AbstractCommand extends Command {
27
28
  /**
29
   * @brief Creates an instance of the command.
30
   */
31
  public function __construct() {
32
    parent::__construct();
33
  }
34
35
36
  /**
37
   * @brief Returns `true` in case `$arg` seems to be the string representation of an array, `false` otherwise.
38
   * @param[in] mixed $arg The command line argument.
39
   * @return bool
40
   */
41
  protected function isArray($arg) {
42
    if (preg_match('/\A[\[]([^\[\]]+)[\]]\z/i', $arg, $matches))
43
      return TRUE;
44
    else
45
      return FALSE;
46
  }
47
48
49
  /**
50
   * @brief Returns `true` in case `$arg` is a formatted argument, `false` otherwise.
51
   * @details The argument type can be specified using the syntax \%s/. The final slash is followed by the value.\n
52
   *     \%s - the argument is treated as a string.\n
53
   *     \%b - the argument is treated as a boolean.\n
54
   *     \%i - the argument is treated as an integer.\n
55
   *     \%f - the argument is treated as a float.
56
   * @param[in,out] mixed $arg The command line argument.
57
   * @return bool
58
   */
59
  protected function isFormatted(&$arg) {
60
    //  \A            # Assert position at the beginning of the string
61
    //  (?P<type>     # Match the regular expression below and capture its match into backreference with name “type”
62
    //                  # Match either the regular expression below (attempting the next alternative only if this one fails)
63
    //        %s          # Match the characters “%s” literally
64
    //     |            # Or match regular expression number 2 below (attempting the next alternative only if this one fails)
65
    //        %b          # Match the characters “%b” literally
66
    //     |            # Or match regular expression number 3 below (attempting the next alternative only if this one fails)
67
    //        %i          # Match the characters “%i” literally
68
    //     |            # Or match regular expression number 4 below (the entire group fails if this one fails to match)
69
    //        %f          # Match the characters “%f” literally
70
    //  )
71
    //  /             # Match the character “/” literally
72
    //  (?P<value>    # Match the regular expression below and capture its match into backreference with name “value”
73
    //        .         # Match any single character that is not a line break character
74
    //          +         # Between one and unlimited times, as many times as possible, giving back as needed (greedy)
75
    //  )
76
    //  \z            # Assert position at the very end of the string
77
    if (preg_match('#\A(?P<type>%s|%b|%i|%f)/(?P<value>.+)\z#i', $arg, $matches)) {
78
      $type = $matches['type'];
79
      $value = $matches['value'];
80
81
      switch ($type) {
82
        case '%s':
83
          $arg = (string)$value;
84
          break;
85
        case '%b':
86
          $arg = (strtolower($value) === 'false') ? FALSE : (bool)$value;
87
          break;
88
        case '%i':
89
          $arg = (integer)$value;
90
          break;
91
        case '%f':
92
          $arg = (float)$value;
93
          break;
94
      }
95
96
      return TRUE;
97
    }
98
    else {
99
      return FALSE;
100
    }
101
  }
102
103
104
  /**
105
   * @brief Casts the argument to the right format and jsonify it when necessary.
106
   * @param[in] mixed $arg The command line argument.
107
   * @return mixed
108
   */
109
  protected function castArg($arg) {
110
    echo "Original argument: ".$arg.PHP_EOL;
111
    if ($this->isArray($arg)) {
112
      // Removes `[` and `]` from the argument.
113
      $str = substr($arg, 1, -1);
114
115
      // Splits a string using the delimiter `,` and returns the result as an array of strings.
116
      $values = explode(',', $str);
117
118
      $argument = [];
119
      foreach ($values as $value) {
120
        if ($this->isFormatted($value))
121
          $argument[] = $value;
122
        else
123
          $argument[] = (string)$value;
124
      }
125
126
      return $argument;
127
    }
128
    elseif ($this->isFormatted($arg))
129
      return $arg;
130
    else
131
      return (string)$arg ;
132
  }
133
134
135
  /**
136
   * @brief Retrieves the connection in use.
137
   * @retval EoC::Couch The server connection.
138
   */
139
  protected function getConnection() {
0 ignored issues
show
Coding Style introduced by
getConnection uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
140
    $shmKey = ftok($_SERVER['PHP_SELF'], 'c');
141
142 View Code Duplication
    if (@$shmId = shmop_open($shmKey, "a", 0, 0)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
143
      // Gets shared memory block's size.
144
      $shmSize = shmop_size($shmId);
145
146
      // Now lets read the memory segment.
147
      if ($buffer = shmop_read($shmId, 0, $shmSize))
148
        $connection = unserialize($buffer);
149
      else
150
        throw new \RuntimeException("You are not connected to the server.");
151
152
      shmop_close($shmId);
153
    }
154
    else
155
      throw new \RuntimeException("You are not connected to the server.");
156
157
    return new Couch(new CurlAdapter($connection['server'], $connection['user'], $connection['password']));
158
  }
159
160
161
  /**
162
   * @brief Retrieves the database in use.
163
   * @retval string The database name.
164
   */
165
  protected function getDatabase() {
0 ignored issues
show
Coding Style introduced by
getDatabase uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
166
    $shmKey = ftok($_SERVER['PHP_SELF'], 'd');
167
168 View Code Duplication
    if (@$shmId = shmop_open($shmKey, "a", 0, 0)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
169
      // Gets shared memory block's size.
170
      $shmSize = shmop_size($shmId);
171
172
      // Now lets read the memory segment.
173
      if ($buffer = shmop_read($shmId, 0, $shmSize))
174
        $database = $buffer;
175
      else
176
        throw new \RuntimeException("No database selected.");
177
178
      shmop_close($shmId);
179
    }
180
    else
181
      throw new \RuntimeException("No database selected.");
182
183
    return $database;
184
  }
185
186
}