class

Analyzer::Php::ApiPlatform

Inherits Analyzer::Php::PhpEngine < FileScanEngine < Analyzer < FileHelper < Reference < Object

API Platform builds its HTTP API from class-level resource metadata instead of controller routes:

#[ApiResource(operations: [new Get(), new Post(uriTemplate: '/books/new')])]
#[GetCollection(uriTemplate: '/authors/{authorId}/books')]
class Book { … }

An operation without its own uriTemplate inherits the resource's, and without either one it gets the generated /{short_names} (collection, POST) or /{short_names}/{id} (item) path. routePrefix and the type: api_platform route import's prefix (/api in the Symfony recipe, route_prefix in Laravel's config/api-platform.php) sit in front.

Constants

ARGS_RULES = Noir::TopLevelSplit::Rules.new(strip: false)
ATTRIBUTE_RE = /#\[\s*(\\?(?:[\w\\]+\\)?)(ApiResource|GetCollection|Get|Post|Put|Patch|Delete)\s*(\(|\])/

HttpOperation is not an attribute class, so it only counts inside operations: lists.

COLLECTION_OPERATIONS = {"GetCollection", "Post"}
DECLARATION_RE = /(?<![\w:$>])(class|enum|interface|trait|function)\b(?!\s*:(?!:))\s*(\w*)/
DEFAULT_OPERATIONS = ["Get", "GetCollection", "Post", "Patch", "Delete"] of ::String

API Platform 4's defaults; 3.x also added Put.

ENUM_DEFAULT_OPERATIONS = ["GetCollection", "Get"] of ::String
FORMAT_RE = /\{\._format\}|\.\{_format\}/
GROUPS_ATTR_RE = /#\[\s*(?:[\w\\]*\\)?Groups\s*\(\s*(?:groups\s*:\s*)?(\[[^\]]*\]|['"][^'"]*['"])/
IDENTIFIER_RE = /\bApiProperty\s*\([^)]*\bidentifier\s*:\s*true\b[^$]*?\$(\w+)/
IMPORT_RE = /^\s*use\s+\\?ApiPlatform\\Metadata(?:\\(\w+)|\\\{([^}]*)\}|\s+as\s+(\w+))?\s*;/m
NAMED_ARG_RE = /\A(\w+)\s*:(?!:)\s*(.*)\z/m
NEW_RE = /\A(?:['"][^'"]*['"]\s*=>\s*)?new\s+\\?(?:[\w\\]+\\)?(\w+)\s*(\()?/
NO_UTF_CHECK = Regex::MatchOptions::NO_UTF_CHECK

scan is ASCII, so byte offsets are char offsets; skipping PCRE2's per-call UTF validation keeps the attribute walk linear.

OPERATION_METHODS = {"Get" => "GET", "GetCollection" => "GET", "Post" => "POST", "Put" => "PUT", "Patch" => "PATCH", "Delete" => "DELETE", "HttpOperation" => "GET"}
ORM_ID_RE = /#\[\s*(?:[\w\\]*\\)?Id\s*\][^$]*?\$(\w+)/
PARAMETER_TYPES = {"QueryParameter" => "query", "HeaderParameter" => "header"}
PROPERTY_RE = /(?:public|protected|private)\s+(?:readonly\s+)?(?:\??[\w\\|]+\s+)?\$(\w+)\s*[;=,)]/
QUERY_PARAM_RE = /#\[\s*(?:[\w\\]*\\)?QueryParameter\b\s*(?:\(([^\]]*)\))?/
STRING_RE = /\A(['"])((?:(?!\1).)*)\1\z/m
TAGGER = "api_platform_analyzer"

Class methods

tech_name
Source

Instance methods

analyze
Source
analyze_file(path : String) : Array(Endpoint)
Source
tech

Instance-side view of the same declaration. The per-file rescues live on this base class, which has no way to name the analyzer that is running inside them, so a skipped file could not be attributed to a tech. Deriving it from analyzer_for keeps the name written exactly once.

Source