Completed
Pull Request — develop (#76)
by
unknown
05:30
created

Issue   B

Complexity

Total Complexity 53

Size/Duplication

Total Lines 492
Duplicated Lines 9.76 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 99.18%

Importance

Changes 15
Bugs 4 Features 2
Metric Value
wmc 53
c 15
b 4
f 2
lcom 1
cbo 7
dl 48
loc 492
ccs 121
cts 122
cp 0.9918
rs 7.4757

17 Methods

Rating   Name   Duplication   Size   Complexity  
A getTags() 12 12 3
A getIssueTagId() 0 15 3
A setup() 0 7 2
A actions() 0 6 2
A fields() 0 20 3
B issueModifyFields() 0 29 1
A fieldTitle() 0 9 1
A fieldBody() 0 9 1
C fieldStatusTags() 12 68 10
B fieldTypeTags() 12 58 8
C fieldResolutionTags() 12 70 8
A fieldAssignedTo() 0 11 1
A fieldUpload() 0 8 2
B fieldTimeQuote() 0 24 1
A rules() 0 9 1
A getRedirectUrl() 0 8 2
A extractQuoteValue() 0 15 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Issue often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Issue, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * This file is part of the Tinyissue package.
5
 *
6
 * (c) Mohamed Alsharaf <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Tinyissue\Form;
13
14
use Tinyissue\Model;
15
16
/**
17
 * Issue is a class to defines fields & rules for add/edit issue form.
18
 *
19
 * @author Mohamed Alsharaf <[email protected]>
20
 */
21
class Issue extends FormAbstract
22
{
23
24
    /**
25
     * An instance of project model.
26
     *
27
     * @var Model\Project
28
     */
29
    protected $project;
30
31
    /**
32
     * Collection of all tags.
33
     *
34
     * @var \Illuminate\Database\Eloquent\Collection
35
     */
36
    protected $tags = null;
37
38
    /**
39
     * @param string $type
40
     *
41
     * @return \Illuminate\Database\Eloquent\Collection|null
42 7
     */
43 View Code Duplication
    protected function getTags($type = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
44 7
    {
45 7
        if ($this->tags === null) {
46
            $this->tags = (new Model\Tag())->getGroupTags();
47
        }
48 7
49 7
        if ($type) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $type of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
50
            return $this->tags->where('name', $type)->first()->tags;
51
        }
52
53
        return $this->tags;
54
    }
55
56
    /**
57
     * Get issue tag for specific type/group.
58
     *
59
     * @param string $type
60
     *
61
     * @return int
62 7
     */
63
    protected function getIssueTagId($type)
64 7
    {
65 6
        if (!$this->isEditing()) {
66
            return 0;
67
        }
68 2
69 2
        $groupId     = $this->getTags($type)->first()->parent_id;
70
        $selectedTag = $this->getModel()->tags->where('parent_id', $groupId);
71 2
72 2
        if ($selectedTag->count() === 0) {
73
            return 0;
74
        }
75 2
76
        return $selectedTag->last()->id;
77
    }
78
79
    /**
80
     * @param array $params
81
     *
82
     * @return void
83 6
     */
84
    public function setup(array $params)
85 6
    {
86 6
        $this->project = $params['project'];
87 2
        if (!empty($params['issue'])) {
88
            $this->editingModel($params['issue']);
89 6
        }
90
    }
91
92
    /**
93
     * @return array
94 6
     */
95
    public function actions()
96
    {
97 6
        return [
98
            'submit' => $this->isEditing() ? 'update_issue' : 'create_issue',
99
        ];
100
    }
101
102
    /**
103
     * @return array
104 6
     */
105
    public function fields()
106 6
    {
107
        $issueModify = \Auth::user()->permission('issue-modify');
108 6
109 6
        $fields = $this->fieldTitle();
110 6
        $fields += $this->fieldBody();
111
        $fields += $this->fieldTypeTags();
112
113 6
        // Only on creating new issue
114 5
        if (!$this->isEditing()) {
115
            $fields += $this->fieldUpload();
116
        }
117
118 6
        // Show fields for users with issue modify permission
119 6
        if ($issueModify) {
120
            $fields += $this->issueModifyFields();
121
        }
122 6
123
        return $fields;
124
    }
125
126
    /**
127
     * Return a list of fields for users with issue modify permission.
128
     *
129
     * @return array
130 6
     */
131
    protected function issueModifyFields()
132 6
    {
133
        $fields = [];
134 6
135
        $fields['internal_status'] = [
136
            'type' => 'legend',
137
        ];
138
139 6
        // Status tags
140
        $fields += $this->fieldStatusTags();
141
142 6
		/*
143
		$fields['You_have_currently_no_permission_to_change_the_status'] = [
144
            'type' => 'label',
145 6
        ];
146
		*/
147
148 6
149
        // Assign users
150 6
        $fields += $this->fieldAssignedTo();
151
152
        // Quotes
153
        $fields += $this->fieldTimeQuote();
154
155
        // Resolution tags
156
        $fields += $this->fieldResolutionTags();
157
158 7
        return $fields;
159
    }
160
161
    /**
162
     * Returns title field.
163
     *
164 7
     * @return array
165
     */
166
    protected function fieldTitle()
167
    {
168
        return [
169
            'title' => [
170
                'type'  => 'text',
171
                'label' => 'title',
172
            ],
173 7
        ];
174
    }
175
176
    /**
177
     * Returns body field.
178
     *
179 7
     * @return array
180
     */
181
    protected function fieldBody()
182
    {
183
        return [
184
            'body' => [
185
                'type'  => 'textarea',
186
                'label' => 'issue',
187
            ],
188 6
        ];
189
    }
190 6
191 6
    /**
192 6
     * Returns status tag field.
193 6
     *
194 6
     * @return array
195 6
     */
196 6
    protected function fieldStatusTags()
197 6
    {
198
199
		/**
200
		 * Let the user only select from tags he may access
201 6
		 * according to the tags VIEW_LIMIT_ROLE - nickbe
202 6
		**/
203 6
204 6
		$current_tag = $this->getIssueTagId('status');
205 6
		$tags = $this->project->getKanbanTags();
206
207
208 6
		$single_tag = false;
209 View Code Duplication
		foreach ($tags as $position => $tag) {
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...
210
211
			/**
212
			 * Let's check if the user can access the current tag
213
			 * if not then this is the only tag he will see
214
			**/
215 7
216
			if ( $current_tag == $tag->id && \Auth::user()->role_id < $tag->role_limit ) {
217 7
				$single_tag = true;
218 7
				break;
219 7
			}
220 7
		}
221 7
222 7
223 7
		/**
224 7
		 * Show tags as usual and according to role
225
		 * or simply show one single active (locked) tag
226
		**/
227
228 7
		if ($single_tag) {
229 7
230 7
			foreach ($tags as $position => $tag) {
231 7
				if ($current_tag !== $tag->id) {
232 7
						unset($tags[$position]);
233
					}
234
			}
235 7
236
		} else {
237
238
			$tags = $tags->filter(function (Model\Tag $tag) {
239
				return !(\Auth::user()->role_id < $tag->role_limit || $tag->name == Model\Tag::STATUS_OPEN || $tag->name == Model\Tag::STATUS_CLOSED);
0 ignored issues
show
Documentation introduced by
The property role_limit does not exist on object<Tinyissue\Model\Tag>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
240
			});
241
242
		}
243 6
244
245 6
        $options = [];
246
        foreach ($tags as $tag) {
247 6
            $options[ucwords($tag->name)] = [
248
                'name'      => 'tag_status',
249
                'value'     => $tag->id,
250
                'data-tags' => $tag->id,
251
                'color'     => $tag->bgcolor,
252 6
            ];
253
        }
254 6
255 6
        $fields['tag_status'] = [
0 ignored issues
show
Coding Style Comprehensibility introduced by
$fields was never initialized. Although not strictly required by PHP, it is generally a good practice to add $fields = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
256 6
            'label'  => 'status',
257 6
            'type'   => 'radioButton',
258 6
            'radios' => $options,
259 6
            'check'  => $this->getIssueTagId('status'),
260
        ];
261
262
        return $fields;
263 6
    }
264 6
    /**
265 6
     * Returns tags field.
266 6
     *
267 6
     * @return array
268
     */
269
    protected function fieldTypeTags()
270 6
    {
271
        $tags    = $this->getTags('type');
272
273
274
		$current_tag = $this->getIssueTagId('type');
275
		$single_tag = false;
276
277 View Code Duplication
		foreach ($tags as $position => $tag) {
0 ignored issues
show
Bug introduced by
The expression $tags of type object<Illuminate\Databa...oquent\Collection>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
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...
278 6
279
			/**
280
			 * Let's check if the user can access the current tag
281
			 * if not then this is the only tag he will see
282 6
			**/
283 6
284 6
			if ( $current_tag == $tag->id && \Auth::user()->role_id < $tag->role_limit ) {
285 6
				$single_tag = true;
286
				break;
287
			}
288
		}
289
290
		if ($single_tag) {
291
292
			foreach ($tags as $position => $tag) {
0 ignored issues
show
Bug introduced by
The expression $tags of type object<Illuminate\Databa...oquent\Collection>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
293
				if ($current_tag !== $tag->id) {
294
						unset($tags[$position]);
295 6
					}
296
			}
297 6
298 6
		} else {
299 6
300
			$tags = $tags->filter(function (Model\Tag $tag) {
301 6
				return !(\Auth::user()->role_id < $tag->role_limit );
0 ignored issues
show
Documentation introduced by
The property role_limit does not exist on object<Tinyissue\Model\Tag>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
302
			});
303
304
		}
305
306
307
308
        $options = [];
309 6
        foreach ($tags as $tag) {
310
            $options[ucwords($tag->name)] = [
311
                'name'      => 'tag_type',
312
                'value'     => $tag->id,
313 6
                'data-tags' => $tag->id,
314 6
                'color'     => $tag->bgcolor,
315
            ];
316
        }
317 6
318 6
        $fields['tag_type'] = [
0 ignored issues
show
Coding Style Comprehensibility introduced by
$fields was never initialized. Although not strictly required by PHP, it is generally a good practice to add $fields = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
319 6
            'label'  => 'type',
320 6
            'type'   => 'radioButton',
321
            'radios' => $options,
322
            'check'  => $this->getIssueTagId('type'),
323 6
        ];
324 6
325 6
        return $fields;
326 6
    }
327
328
    /**
329 6
     * Returns tags field.
330
     *
331
     * @return array
332
     */
333
    protected function fieldResolutionTags()
334
    {
335
        $tags    = $this->getTags('resolution');
336
337 7
338
		$current_tag = $this->getIssueTagId('resolution');
339
		$single_tag = false;
340 7
341 View Code Duplication
		foreach ($tags as $position => $tag) {
0 ignored issues
show
Bug introduced by
The expression $tags of type object<Illuminate\Databa...oquent\Collection>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
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...
342
343
			/**
344 7
			 * Let's check if the user can access the current tag
345
			 * if not then this is the only tag he will see
346
			**/
347
348
			if ( $current_tag == $tag->id && \Auth::user()->role_id < $tag->role_limit ) {
349
				$single_tag = true;
350
				break;
351
			}
352
		}
353
354
355
		/**
356
		 * Show tags as usual and according to role
357
		 * or simply show one single active (locked) tag
358
		**/
359
360
		if ($single_tag) {
361
362
			foreach ($tags as $position => $tag) {
0 ignored issues
show
Bug introduced by
The expression $tags of type object<Illuminate\Databa...oquent\Collection>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
363
				if ($current_tag !== $tag->id) {
364
						unset($tags[$position]);
365
					}
366 6
			}
367
368 6
		} else {
369 2
370 2
			$tags = $tags->filter(function (Model\Tag $tag) {
371 2
				return !(\Auth::user()->role_id < $tag->role_limit );
0 ignored issues
show
Documentation introduced by
The property role_limit does not exist on object<Tinyissue\Model\Tag>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
372
			});
373
374 2
			$options = [
375 2
				trans('tinyissue.none') => [
376
					'name'      => 'tag_resolution',
377
					'value'     => 0,
378
					'data-tags' => 0,
379 5
					'color'     => '#62CFFC',
380
				],
381
			];
382
383
		}
384
385
        foreach ($tags as $tag) {
386
            $options[ucwords($tag->name)] = [
0 ignored issues
show
Bug introduced by
The variable $options does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
387
                'name'      => 'tag_resolution',
388
                'value'     => $tag->id,
389
                'data-tags' => $tag->id,
390
                'color'     => $tag->bgcolor,
391
            ];
392
        }
393
394
        $fields['tag_resolution'] = [
0 ignored issues
show
Coding Style Comprehensibility introduced by
$fields was never initialized. Although not strictly required by PHP, it is generally a good practice to add $fields = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
395
            'label'  => 'resolution',
396
            'type'   => 'radioButton',
397
            'radios' => $options,
398
            'check'  => $this->getIssueTagId('resolution'),
399
        ];
400
401
        return $fields;
402
    }
403
404
    /**
405
     * Returns assigned to field.
406
     *
407
     * @return array
408
     */
409
    protected function fieldAssignedTo()
410
    {
411
        return [
412
            'assigned_to' => [
413
                'type'    => 'select',
414
                'label'   => 'assigned_to',
415
                'options' => [0 => ''] + $this->project->usersCanFixIssue()->get()->lists('fullname', 'id')->all(),
416
                'value'   => (int) $this->project->default_assignee,
417
            ],
418
        ];
419
    }
420
421
    /**
422
     * Returns upload field.
423
     *
424
     * @return array
425
     */
426
    protected function fieldUpload()
427
    {
428
        $user                      = \Auth::guest() ? new Model\User() : \Auth::user();
429
        $fields                    = $this->projectUploadFields('upload', $this->project, $user);
430
        $fields['upload']['label'] = 'attachments';
431
432
        return $fields;
433
    }
434
435
    /**
436
     * Returns time quote field.
437
     *
438
     * @return array
439
     */
440
    protected function fieldTimeQuote()
441
    {
442
        return [
443
            'time_quote' => [
444
                'type'   => 'groupField',
445
                'label'  => 'quote',
446
                'fields' => [
447
                    'h' => [
448
                        'type'          => 'number',
449
                        'append'        => trans('tinyissue.hours'),
450
                        'value'         => $this->extractQuoteValue('h'),
451
                        'addGroupClass' => 'col-sm-12 col-md-12 col-lg-4',
452
                    ],
453
                    'm' => [
454
                        'type'          => 'number',
455
                        'append'        => trans('tinyissue.minutes'),
456
                        'value'         => $this->extractQuoteValue('m'),
457
                        'addGroupClass' => 'col-sm-12 col-md-12 col-lg-4',
458
                    ],
459
                ],
460
                'addClass' => 'row issue-quote',
461
            ],
462
        ];
463
    }
464
465
    /**
466
     * @return array
467
     */
468
    public function rules()
469
    {
470
        $rules = [
471
            'title' => 'required|max:200',
472
            'body'  => 'required',
473
        ];
474
475
        return $rules;
476
    }
477
478
    /**
479
     * @return string
480
     */
481
    public function getRedirectUrl()
482
    {
483
        if ($this->isEditing()) {
484
            return $this->getModel()->to('edit');
485
        }
486
487
        return 'project/' . $this->project->id . '/issue/new';
488
    }
489
490
    /**
491
     * Extract number of hours, or minutes, or seconds from a quote.
492
     *
493
     * @param string $part
494
     *
495
     * @return float|int
496
     */
497
    protected function extractQuoteValue($part)
498
    {
499
        if ($this->getModel() instanceof Model\Project\Issue) {
500
            $seconds = $this->getModel()->time_quote;
501
            if ($part === 'h') {
502
                return floor($seconds / 3600);
503
            }
504
505
            if ($part === 'm') {
506
                return ($seconds / 60) % 60;
507
            }
508
        }
509
510
        return 0;
511
    }
512
}
513