vendor/zircote/swagger-php/src/Context.php line 277

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. /**
  3.  * @license Apache 2.0
  4.  */
  5. namespace OpenApi;
  6. use OpenApi\Logger\DefaultLogger;
  7. /**
  8.  * Context.
  9.  *
  10.  * The context in which the annotation is parsed.
  11.  * It includes useful metadata which the Processors can use to augment the annotations.
  12.  *
  13.  * Context hierarchy:
  14.  * - parseContext
  15.  *   |- docBlockContext
  16.  *   |- classContext
  17.  *      |- docBlockContext
  18.  *      |- propertyContext
  19.  *      |- methodContext
  20.  *
  21.  * @property string                           $comment     The PHP DocComment
  22.  * @property string                           $filename
  23.  * @property int                              $line
  24.  * @property int                              $character
  25.  * @property string                           $namespace
  26.  * @property array                            $uses
  27.  * @property string                           $class
  28.  * @property array|string                     $extends     Interfaces may extend a list of interfaces
  29.  * @property array                            $implements
  30.  * @property string                           $method
  31.  * @property string                           $property
  32.  * @property string                           $type
  33.  * @property string                           $trait
  34.  * @property string                           $interface
  35.  * @property bool                             $static      Indicate a static method
  36.  * @property bool                             $nullable    Indicate a nullable value
  37.  * @property bool                             $generated   Indicate the context was generated by a processor or the serializer
  38.  * @property Annotations\AbstractAnnotation   $nested
  39.  * @property Annotations\AbstractAnnotation[] $annotations
  40.  * @property \Psr\Log\LoggerInterface         $logger      Guaranteed to be set when using the `Generator`
  41.  */
  42. class Context
  43. {
  44.     /**
  45.      * Prototypical inheritance for properties.
  46.      *
  47.      * @var Context
  48.      */
  49.     private $_parent;
  50.     /**
  51.      * @param array   $properties new properties for this context
  52.      * @param Context $parent     The parent context
  53.      */
  54.     public function __construct(array $properties = [], ?Context $parent null)
  55.     {
  56.         foreach ($properties as $property => $value) {
  57.             $this->$property $value;
  58.         }
  59.         $this->_parent $parent;
  60.         if (!$this->logger) {
  61.             // BC
  62.             $this->logger = new DefaultLogger();
  63.         }
  64.     }
  65.     /**
  66.      * Check if a property is set directly on this context and not its parent context.
  67.      *
  68.      * @param string $type Example: $c->is('method') or $c->is('class')
  69.      */
  70.     public function is(string $type): bool
  71.     {
  72.         return property_exists($this$type);
  73.     }
  74.     /**
  75.      * Check if a property is NOT set directly on this context and but its parent context.
  76.      *
  77.      * @param string $type Example: $c->not('method') or $c->not('class')
  78.      */
  79.     public function not(string $type): bool
  80.     {
  81.         return property_exists($this$type) === false;
  82.     }
  83.     /**
  84.      * Return the context containing the specified property.
  85.      */
  86.     public function with(string $property): ?Context
  87.     {
  88.         if (property_exists($this$property)) {
  89.             return $this;
  90.         }
  91.         if ($this->_parent !== null) {
  92.             return $this->_parent->with($property);
  93.         }
  94.         return null;
  95.     }
  96.     public function getRootContext(): Context
  97.     {
  98.         if ($this->_parent !== null) {
  99.             return $this->_parent->getRootContext();
  100.         }
  101.         return $this;
  102.     }
  103.     /**
  104.      * Export location for debugging.
  105.      *
  106.      * @return string Example: "file1.php on line 12"
  107.      */
  108.     public function getDebugLocation(): string
  109.     {
  110.         $location '';
  111.         if ($this->class && ($this->method || $this->property)) {
  112.             $location .= $this->fullyQualifiedName($this->class);
  113.             if ($this->method) {
  114.                 $location .= ($this->static '::' '->') . $this->method '()';
  115.             } elseif ($this->property) {
  116.                 $location .= ($this->static '::$' '->') . $this->property;
  117.             }
  118.         }
  119.         if ($this->filename) {
  120.             if ($location !== '') {
  121.                 $location .= ' in ';
  122.             }
  123.             $location .= $this->filename;
  124.         }
  125.         if ($this->line) {
  126.             if ($location !== '') {
  127.                 $location .= ' on';
  128.             }
  129.             $location .= ' line ' $this->line;
  130.             if ($this->character) {
  131.                 $location .= ':' $this->character;
  132.             }
  133.         }
  134.         return $location;
  135.     }
  136.     /**
  137.      * Traverse the context tree to get the property value.
  138.      *
  139.      * @param string $property
  140.      */
  141.     public function __get($property)
  142.     {
  143.         if ($this->_parent !== null) {
  144.             return $this->_parent->$property;
  145.         }
  146.         return null;
  147.     }
  148.     public function __toString()
  149.     {
  150.         return $this->getDebugLocation();
  151.     }
  152.     public function __debugInfo()
  153.     {
  154.         return ['-' => $this->getDebugLocation()];
  155.     }
  156.     /**
  157.      * A short piece of text, usually one line, providing the basic function of the associated element.
  158.      *
  159.      * @return string
  160.      */
  161.     public function phpdocSummary()
  162.     {
  163.         $content $this->phpdocContent();
  164.         if (!$content) {
  165.             return Generator::UNDEFINED;
  166.         }
  167.         $lines preg_split('/(\n|\r\n)/'$content);
  168.         $summary '';
  169.         foreach ($lines as $line) {
  170.             $summary .= $line "\n";
  171.             if ($line === '' || substr($line, -1) === '.') {
  172.                 return trim($summary);
  173.             }
  174.         }
  175.         $summary trim($summary);
  176.         if ($summary === '') {
  177.             return Generator::UNDEFINED;
  178.         }
  179.         return $summary;
  180.     }
  181.     /**
  182.      * An optional longer piece of text providing more details on the associated element’s function. This is very useful when working with a complex element.
  183.      *
  184.      * @return string
  185.      */
  186.     public function phpdocDescription()
  187.     {
  188.         $summary $this->phpdocSummary();
  189.         if (!$summary) {
  190.             return Generator::UNDEFINED;
  191.         }
  192.         if (false !== ($substr substr($this->phpdocContent(), strlen($summary)))) {
  193.             $description trim($substr);
  194.         } else {
  195.             $description '';
  196.         }
  197.         if ($description === '') {
  198.             return Generator::UNDEFINED;
  199.         }
  200.         return $description;
  201.     }
  202.     /**
  203.      * The text contents of the phpdoc comment (excl. tags).
  204.      *
  205.      * @return string
  206.      */
  207.     public function phpdocContent()
  208.     {
  209.         $comment preg_split('/(\n|\r\n)/', (string) $this->comment);
  210.         $comment[0] = preg_replace('/[ \t]*\\/\*\*/'''$comment[0]); // strip '/**'
  211.         $i count($comment) - 1;
  212.         $comment[$i] = preg_replace('/\*\/[ \t]*$/'''$comment[$i]); // strip '*/'
  213.         $lines = [];
  214.         $append false;
  215.         foreach ($comment as $line) {
  216.             $line ltrim($line"\t *");
  217.             if (substr($line01) === '@') {
  218.                 break;
  219.             }
  220.             if ($append) {
  221.                 $i count($lines) - 1;
  222.                 $lines[$i] = substr($lines[$i], 0, -1) . $line;
  223.             } else {
  224.                 $lines[] = $line;
  225.             }
  226.             $append = (substr($line, -1) === '\\');
  227.         }
  228.         $description trim(implode("\n"$lines));
  229.         if ($description === '') {
  230.             return Generator::UNDEFINED;
  231.         }
  232.         return $description;
  233.     }
  234.     /**
  235.      * Create a Context based on the debug_backtrace.
  236.      *
  237.      * @deprecated
  238.      */
  239.     public static function detect(int $index 0): Context
  240.     {
  241.         $context = new Context();
  242.         $backtrace debug_backtrace();
  243.         $position $backtrace[$index];
  244.         if (isset($position['file'])) {
  245.             $context->filename $position['file'];
  246.         }
  247.         if (isset($position['line'])) {
  248.             $context->line $position['line'];
  249.         }
  250.         $caller = isset($backtrace[$index 1]) ? $backtrace[$index 1] : null;
  251.         if (isset($caller['function'])) {
  252.             $context->method $caller['function'];
  253.             if (isset($caller['type']) && $caller['type'] === '::') {
  254.                 $context->static true;
  255.             }
  256.         }
  257.         if (isset($caller['class'])) {
  258.             $fqn explode('\\'$caller['class']);
  259.             $context->class array_pop($fqn);
  260.             if (count($fqn)) {
  261.                 $context->namespace implode('\\'$fqn);
  262.             }
  263.         }
  264.         // @todo extract namespaces and use statements
  265.         return $context;
  266.     }
  267.     /**
  268.      * Resolve the fully qualified name.
  269.      *
  270.      * @param string $source The source name (class/interface/trait)
  271.      */
  272.     public function fullyQualifiedName(?string $source): string
  273.     {
  274.         if ($source === null) {
  275.             return '';
  276.         }
  277.         if ($this->namespace) {
  278.             $namespace str_replace('\\\\''\\''\\' $this->namespace '\\');
  279.         } else {
  280.             // global namespace
  281.             $namespace '\\';
  282.         }
  283.         $thisSource $this->class ?? $this->interface ?? $this->trait;
  284.         if ($thisSource && strcasecmp($source$thisSource) === 0) {
  285.             return $namespace $thisSource;
  286.         }
  287.         $pos strpos($source'\\');
  288.         if ($pos !== false) {
  289.             if ($pos === 0) {
  290.                 // Fully qualified name (\Foo\Bar)
  291.                 return $source;
  292.             }
  293.             // Qualified name (Foo\Bar)
  294.             if ($this->uses) {
  295.                 foreach ($this->uses as $alias => $aliasedNamespace) {
  296.                     $alias .= '\\';
  297.                     if (strcasecmp(substr($source0strlen($alias)), $alias) === 0) {
  298.                         // Aliased namespace (use \Long\Namespace as Foo)
  299.                         return '\\' $aliasedNamespace substr($sourcestrlen($alias) - 1);
  300.                     }
  301.                 }
  302.             }
  303.         } elseif ($this->uses) {
  304.             // Unqualified name (Foo)
  305.             foreach ($this->uses as $alias => $aliasedNamespace) {
  306.                 if (strcasecmp($alias$source) === 0) {
  307.                     return '\\' $aliasedNamespace;
  308.                 }
  309.             }
  310.         }
  311.         return $namespace $source;
  312.     }
  313. }