Completed
Push — master ( a2b782...8e30a2 )
by Glynn
19s queued 12s
created

Component_Compiler::extract_annotation_value()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 3
c 1
b 0
f 1
dl 0
loc 4
rs 10
cc 1
nc 1
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * The base component class.
7
 *
8
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
9
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
10
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
11
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
12
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
13
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
14
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
15
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
16
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
17
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
18
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19
 *
20
 * @author Glynn Quelch <[email protected]>
21
 * @license http://www.opensource.org/licenses/mit-license.html  MIT License
22
 * @package PinkCrab\Perique\View
23
 * @since 1.2.0
24
 */
25
26
namespace PinkCrab\Perique\Services\View\Component;
27
28
use PinkCrab\Perique\Application\Hooks;
29
use PinkCrab\Perique\Services\View\View_Model;
30
use Doctrine\Common\Annotations\AnnotationReader;
0 ignored issues
show
Bug introduced by
The type Doctrine\Common\Annotations\AnnotationReader 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...
31
use Doctrine\Common\Annotations\AnnotationRegistry;
0 ignored issues
show
Bug introduced by
The type Doctrine\Common\Annotations\AnnotationRegistry 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...
32
use PinkCrab\Perique\Services\View\Component\Component;
33
34
class Component_Compiler {
35
36
	/**
37
	 * The base path for components.
38
	 *
39
	 * If blank will assume views/components
40
	 *
41
	 * @var string
42
	 */
43
	private $component_base_path;
44
45
	/**
46
	 * All component aliases..
47
	 *
48
	 * @var array<string, string>
49
	 */
50
	private $component_aliases = array();
51
52
	/** @param array<string, string> $component_aliases */
53
	public function __construct( string $component_base_path = '', array $component_aliases = array() ) {
54
		$this->component_base_path = $component_base_path;
55
		$this->component_aliases   = \apply_filters( Hooks::COMPONENT_ALIASES, $component_aliases );
56
	}
57
58
	/**
59
	 * Compiles the component into a view model.
60
	 *
61
	 * @param Component $component
62
	 * @return View_Model
63
	 */
64
	public function compile( Component $component ): View_Model {
65
		return new View_Model( $this->get_component_path( $component ), $component->get_variables() );
66
	}
67
68
	/**
69
	 * Returns the path to the component.
70
	 *
71
	 * @param Component $component
72
	 * @return string
73
	 */
74
	private function get_component_path( Component $component ): string {
75
76
		// Check aliases.
77
		$aliases = \apply_filters( Hooks::COMPONENT_ALIASES, $this->component_aliases );
78
79
		if ( isset( $aliases[ get_class( $component ) ] ) ) {
80
			return esc_attr( $aliases[ get_class( $component ) ] );
81
		}
82
83
		$from_annotation = $this->get_annotation( 'view', $component );
84
85
		// If it does have a path defined, use that.
86
		if ( ! empty( $from_annotation ) ) {
87
			return \trailingslashit( $this->component_base_path ) . $from_annotation;
88
		}
89
90
		// If the component has a defined path
91
		if ( $component->template() ) {
0 ignored issues
show
Bug introduced by
Are you sure the usage of $component->template() targeting PinkCrab\Perique\Service...t\Component::template() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
92
			return \trailingslashit( $this->component_base_path ) . $component->template();
0 ignored issues
show
Bug introduced by
Are you sure the usage of $component->template() targeting PinkCrab\Perique\Service...t\Component::template() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug introduced by
Are you sure $component->template() of type void can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

92
			return \trailingslashit( $this->component_base_path ) . /** @scrutinizer ignore-type */ $component->template();
Loading history...
93
		}
94
95
		// Get path based on class name.
96
		$reflect    = new \ReflectionClass( $component );
97
		$short_name = $reflect->getShortName();
98
		// Add space between capitals, make lowercase and replace underscores with dashes.
99
		$short_name = strtolower( preg_replace( '/(?<!^)[A-Z]/', '$0', $short_name ) ?? '' );
100
		$short_name = str_replace( '_', '-', $short_name );
101
		return \trailingslashit( $this->component_base_path ) . $short_name;
102
	}
103
104
	/**
105
	 * Attempts to extract a defined Annotation from component class doc block.
106
	 *
107
	 * @param string $annotation
108
	 * @param Component $component
109
	 * @return string|null
110
	 */
111
	private function get_annotation( string $annotation, Component $component ): ?string {
112
		$reflect = new \ReflectionClass( $component );
113
		$comment = $reflect->getDocComment();
114
115
		// if no comment, return null.
116
		if ( empty( $comment ) ) {
117
			return null;
118
		}
119
120
		// Check if the comment contains the annotation "@{$annotation}" using regex.
121
		$pattern = "/@{$annotation}\s+(.*)/";
122
		preg_match( $pattern, $comment, $matches );
123
124
		return $matches[1] ?? null;
125
	}
126
}
127