diff --git a/CHANGELOG.md b/CHANGELOG.md
index 42738c5..4cc7e4d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,7 +4,7 @@ Yii Framework 2 apidoc extension Change Log
3.0.9 under development
-----------------------
-- no changes in this release.
+- Enh #337: Log invalid tags (mspirkov)
3.0.8 November 24, 2025
diff --git a/models/BaseDoc.php b/models/BaseDoc.php
index 10854a0..5be9abd 100644
--- a/models/BaseDoc.php
+++ b/models/BaseDoc.php
@@ -1,4 +1,5 @@
getName() === self::TODO_TAG_NAME) {
$this->todos[] = $tag;
unset($this->tags[$i]);
+ } elseif ($tag instanceof InvalidTag && $context !== null) {
+ $exception = $tag->getException();
+ $message = 'Invalid tag: ' . $tag->render() . '.';
+
+ if ($exception !== null) {
+ $message .= ' Exception message: ' . $exception->getMessage();
+ }
+
+ $context->errors[] = [
+ 'line' => $this->startLine,
+ 'file' => $this->sourceFile,
+ 'message' => $message,
+ ];
}
}
@@ -242,7 +257,8 @@ public static function extractFirstSentence($text, $prevText = '')
if ($length >= $pos + 2) {
$abbrev = mb_substr($text, $pos - 3, 4, 'utf-8');
// do not break sentence after abbreviation
- if ($abbrev === 'e.g.' ||
+ if (
+ $abbrev === 'e.g.' ||
$abbrev === 'i.e.' ||
mb_substr_count($prevText, '`', 'utf-8') % 2 === 1
) {
diff --git a/tests/commands/ApiControllerTest.php b/tests/commands/ApiControllerTest.php
index 97f3352..c15b776 100644
--- a/tests/commands/ApiControllerTest.php
+++ b/tests/commands/ApiControllerTest.php
@@ -99,5 +99,15 @@ public function testGenerateBootstrap()
$sourceFilesCount = count(FileHelper::findFiles($sourceFilesDir, ['recursive' => true]));
$this->assertSame($sourceFilesCount, $filesCount);
+
+ $warningsContent = file_get_contents("{$outputPath}/warnings.txt");
+ // Remove the dynamic parts of the file paths
+ $warningsContent = preg_replace('/(\s*\[file\] => ).*(\/tests\/.*\.php)/', '$1$2', $warningsContent);
+ $this->assertMatchesTextSnapshot($warningsContent);
+
+ $errorsContent = file_get_contents("{$outputPath}/errors.txt");
+ // Remove the dynamic parts of the file paths
+ $errorsContent = preg_replace('/(\s*\[file\] => ).*(\/tests\/.*\.php)/', '$1$2', $errorsContent);
+ $this->assertMatchesTextSnapshot($errorsContent);
}
}
diff --git a/tests/commands/__snapshots__/ApiControllerTest__testGenerateBootstrap__3.html b/tests/commands/__snapshots__/ApiControllerTest__testGenerateBootstrap__3.html
index 93e8e75..7103650 100644
--- a/tests/commands/__snapshots__/ApiControllerTest__testGenerateBootstrap__3.html
+++ b/tests/commands/__snapshots__/ApiControllerTest__testGenerateBootstrap__3.html
@@ -166,6 +166,11 @@
Public Methods
isOlder() |
Checks whether the animal is older than the specified time. |
yiiunit\apidoc\data\api\animal\Animal |
+
+
+ | methodWithInvalidReturnTag() |
+ |
+ yiiunit\apidoc\data\api\animal\Dog |
| render() |
@@ -406,6 +411,50 @@ Method Details
{
return$this->getAge() > $date;
}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source code
+
+
+
+
+
+ publicfunctionmethodWithInvalidReturnTag()
+{
+}
diff --git a/tests/commands/__snapshots__/ApiControllerTest__testGenerateBootstrap__5.txt b/tests/commands/__snapshots__/ApiControllerTest__testGenerateBootstrap__5.txt
new file mode 100644
index 0000000..f688c1b
--- /dev/null
+++ b/tests/commands/__snapshots__/ApiControllerTest__testGenerateBootstrap__5.txt
@@ -0,0 +1,66 @@
+Array
+(
+ [0] => Array
+ (
+ [line] => 41
+ [file] => /tests/data/api/animal/Animal.php
+ [message] => No docblock for element '$propertyWithoutDoc'
+ )
+
+ [1] => Array
+ (
+ [line] => 41
+ [file] => /tests/data/api/animal/Animal.php
+ [message] => No short description for element '$propertyWithoutDoc'
+ )
+
+ [2] => Array
+ (
+ [line] => 43
+ [file] => /tests/data/api/animal/Animal.php
+ [message] => No docblock for element '$propertyWithoutDocAndTypeHint'
+ )
+
+ [3] => Array
+ (
+ [line] => 43
+ [file] => /tests/data/api/animal/Animal.php
+ [message] => No short description for element '$propertyWithoutDocAndTypeHint'
+ )
+
+ [4] => Array
+ (
+ [line] => 70
+ [file] => /tests/data/api/animal/Animal.php
+ [message] => No docblock for element 'setBirthDate'
+ )
+
+ [5] => Array
+ (
+ [line] => 32
+ [file] => /tests/data/api/animal/Cat.php
+ [message] => No docblock for element 'methodWithoutDocAndTypeHints'
+ )
+
+ [6] => Array
+ (
+ [line] => 40
+ [file] => /tests/data/api/animal/Cat.php
+ [message] => No short description for Method 'methodWithTodoTag'
+ )
+
+ [7] => Array
+ (
+ [line] => 30
+ [file] => /tests/data/api/animal/Dog.php
+ [message] => No short description for Method 'methodWithInvalidReturnTag'
+ )
+
+ [8] => Array
+ (
+ [line] => 11
+ [file] => /tests/data/api/base/Component.php
+ [message] => No docblock for element 'yiiunit\apidoc\data\api\base\Component'
+ )
+
+)
diff --git a/tests/commands/__snapshots__/ApiControllerTest__testGenerateBootstrap__6.txt b/tests/commands/__snapshots__/ApiControllerTest__testGenerateBootstrap__6.txt
new file mode 100644
index 0000000..f939d78
--- /dev/null
+++ b/tests/commands/__snapshots__/ApiControllerTest__testGenerateBootstrap__6.txt
@@ -0,0 +1,10 @@
+Array
+(
+ [0] => Array
+ (
+ [line] => 30
+ [file] => /tests/data/api/animal/Dog.php
+ [message] => Invalid tag: @return invalid-type. Exception message: "\yiiunit\apidoc\data\api\animal\invalid-type" is not a valid Fqsen.
+ )
+
+)
diff --git a/tests/data/api/animal/Dog.php b/tests/data/api/animal/Dog.php
index 9bf8c81..6752a83 100644
--- a/tests/data/api/animal/Dog.php
+++ b/tests/data/api/animal/Dog.php
@@ -23,4 +23,11 @@ public function render()
// this method has `inheritdoc` tag without brackets
return 'This is a dog';
}
+
+ /**
+ * @return invalid-type
+ */
+ public function methodWithInvalidReturnTag()
+ {
+ }
}