1<?php
2
3declare(strict_types=1);
4
5/**
6 * This file is part of phpDocumentor.
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 *
11 * @link http://phpdoc.org
12 */
13
14namespace phpDocumentor\Reflection\DocBlock\Tags;
15
16use phpDocumentor\Reflection\DocBlock\Description;
17use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
18use phpDocumentor\Reflection\Fqsen;
19use phpDocumentor\Reflection\FqsenResolver;
20use phpDocumentor\Reflection\Types\Context as TypeContext;
21use phpDocumentor\Reflection\Utils;
22use Webmozart\Assert\Assert;
23use function array_key_exists;
24use function explode;
25
26/**
27 * Reflection class for a @covers tag in a Docblock.
28 */
29final class Covers extends BaseTag implements Factory\StaticMethod
30{
31    /** @var string */
32    protected $name = 'covers';
33
34    /** @var Fqsen */
35    private $refers;
36
37    /**
38     * Initializes this tag.
39     */
40    public function __construct(Fqsen $refers, ?Description $description = null)
41    {
42        $this->refers      = $refers;
43        $this->description = $description;
44    }
45
46    public static function create(
47        string $body,
48        ?DescriptionFactory $descriptionFactory = null,
49        ?FqsenResolver $resolver = null,
50        ?TypeContext $context = null
51    ) : self {
52        Assert::stringNotEmpty($body);
53        Assert::notNull($descriptionFactory);
54        Assert::notNull($resolver);
55
56        $parts = Utils::pregSplit('/\s+/Su', $body, 2);
57
58        return new static(
59            self::resolveFqsen($parts[0], $resolver, $context),
60            $descriptionFactory->create($parts[1] ?? '', $context)
61        );
62    }
63
64    private static function resolveFqsen(string $parts, ?FqsenResolver $fqsenResolver, ?TypeContext $context) : Fqsen
65    {
66        Assert::notNull($fqsenResolver);
67        $fqsenParts = explode('::', $parts);
68        $resolved = $fqsenResolver->resolve($fqsenParts[0], $context);
69
70        if (!array_key_exists(1, $fqsenParts)) {
71            return $resolved;
72        }
73
74        return new Fqsen($resolved . '::' . $fqsenParts[1]);
75    }
76
77    /**
78     * Returns the structural element this tag refers to.
79     */
80    public function getReference() : Fqsen
81    {
82        return $this->refers;
83    }
84
85    /**
86     * Returns a string representation of this tag.
87     */
88    public function __toString() : string
89    {
90        if ($this->description) {
91            $description = $this->description->render();
92        } else {
93            $description = '';
94        }
95
96        $refers = (string) $this->refers;
97
98        return $refers . ($description !== '' ? ($refers !== '' ? ' ' : '') . $description : '');
99    }
100}
101