CreateCommand   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 160
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 25%

Importance

Changes 0
Metric Value
wmc 16
lcom 1
cbo 4
dl 0
loc 160
ccs 18
cts 72
cp 0.25
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A __invoke() 0 23 1
A askForPackageName() 0 20 3
A askForAuthor() 0 20 3
A askForDescription() 0 9 2
A parseAuthorString() 0 17 3
A isValidEmail() 0 13 3
1
<?php
2
3
namespace Ptondereau\PackMe\Commands;
4
5
use Ptondereau\PackMe\Crafters\CrafterInterface;
6
use Ptondereau\PackMe\Package;
7
use Symfony\Component\Console\Helper\HelperSet;
8
use Symfony\Component\Console\Input\InputInterface;
9
use Symfony\Component\Console\Output\OutputInterface;
10
11
/**
12
 * Class CreateCommand.
13
 */
14
class CreateCommand extends AbstractBaseCommand
15
{
16
    /**
17
     * Crafter.
18
     *
19
     * @var CrafterInterface
20
     */
21
    protected $crafter;
22
23
    /**
24
     * CreateCommand constructor.
25
     *
26
     * @param CrafterInterface $crafter
27
     * @param HelperSet        $helperSet
28
     */
29 9
    public function __construct(CrafterInterface $crafter, HelperSet $helperSet)
30
    {
31 9
        parent::__construct($helperSet);
32 9
        $this->crafter = $crafter;
33 9
    }
34
35
    public function __invoke($dir, InputInterface $input, OutputInterface $output)
36
    {
37
        $this->input = $input;
38
        $this->output = $output;
0 ignored issues
show
Bug introduced by
The property output cannot be accessed from this context as it is declared private in class Ptondereau\PackMe\Commands\AbstractBaseCommand.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
39
40
        $output->writeln('<info>I need to know a little more about your future awesome laravel package...</info>');
41
        $output->writeln('');
42
43
        $package = new Package(
44
            $this->askForPackageName(),
45
            $this->askForAuthor(),
46
            $dir
47
        );
48
        $package->setDescription($this->askForDescription());
49
50
        $output->writeln('');
51
        $output->writeln('<info>Crafting your laravel package...</info>');
52
53
        $this->crafter->craft($package);
54
55
        $output->writeln('');
56
        $output->writeln('<info>Successfully crafted!</info>');
57
    }
58
59
    /**
60
     * @param string $package
61
     *
62
     * @return string
63
     */
64
    protected function askForPackageName($package = 'vendor/package')
65
    {
66
        return $this->askAndValidate(
67
            'Package name (<vendor>/<name>) [<comment>'.$package.'</comment>]: ',
68
            function ($value) use ($package) {
69
                if (null === $value) {
70
                    return $package;
71
                }
72
                if (!preg_match('{^[a-z0-9_.-]+/[a-z0-9_.-]+$}', $value)) {
73
                    throw new \InvalidArgumentException(
74
                        'The package name '.$value.' is invalid, it should be lowercase and have a vendor name, a forward slash, and a package name, matching: [a-z0-9_.-]+/[a-z0-9_.-]+'
75
                    );
76
                }
77
78
                return $value;
79
            },
80
            null,
81
            $package
82
        );
83
    }
84
85
    /**
86
     * @param string $author
87
     *
88
     * @return string
89
     */
90
    protected function askForAuthor($author = 'Author Name <[email protected]>')
91
    {
92
        $self = $this;
93
94
        return $this->askAndValidate(
95
            'Author [<comment>'.$author.'</comment>]: ',
96
            function ($value) use ($self, $author) {
97
                if (null === $value) {
98
                    return $author;
99
                }
100
101
                $value = $value ?: $author;
102
                $parsed = $self->parseAuthorString($value);
103
104
                return sprintf('%s <%s>', $parsed['name'], $parsed['email']);
105
            },
106
            null,
107
            $author
108
        );
109
    }
110
111
    /**
112
     * @param bool|string $description
113
     *
114
     * @return string
115
     */
116
    protected function askForDescription($description = false)
117
    {
118
        $description = $description ?: false;
119
120
        return $this->ask(
121
            'Description [<comment>'.$description.'</comment>]: ',
122
            $description
0 ignored issues
show
Bug introduced by
It seems like $description defined by $description ?: false on line 118 can also be of type boolean; however, Ptondereau\PackMe\Comman...tractBaseCommand::ask() does only seem to accept null|string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
123
        );
124
    }
125
126
    /**
127
     * Parse the author string.
128
     *
129
     * @private
130
     *
131
     * @param string $author
132
     *
133
     * @return array
134
     */
135 9
    private function parseAuthorString($author)
136
    {
137
        if (
138 9
            preg_match('/^(?P<name>[- \.,\p{L}\p{N}\'’]+) <(?P<email>.+?)>$/u', $author, $match)
139 9
            && $this->isValidEmail($match['email'])
140 3
        ) {
141
            return [
142 3
                'name'  => trim($match['name']),
143 3
                'email' => $match['email'],
144 1
            ];
145
        }
146
147 6
        throw new \InvalidArgumentException(
148
            'Invalid author string.  Must be in the format: '.
149 4
            'John Smith <[email protected]>'
150 2
        );
151
    }
152
153
    /**
154
     * Check if a given email is a good email.
155
     *
156
     * @param $email
157
     *
158
     * @return bool
159
     */
160 6
    private function isValidEmail($email)
161
    {
162
        // assume it's valid if we can't validate it
163 6
        if (!function_exists('filter_var')) {
164
            return true;
165
        }
166
        // php <5.3.3 has a very broken email validator, so bypass checks
167 6
        if (PHP_VERSION_ID < 50303) {
168
            return true;
169
        }
170
171 6
        return false !== filter_var($email, FILTER_VALIDATE_EMAIL);
172
    }
173
}
174