<?php
/* A method that asks a model for something without building one first
dies where it asks. Yioop crashed on the query statistics screen that
way: one arm of a switch built the model and returned, and the arm
that drew the screen used the name it had left behind.
This reads every method in the tree for a model variable used where
nothing in that method built it. A variable a method is handed as an
argument, or one built from anything at all, counts as built.
php devlog/devscripts/check_model_vars.php
*/
$paths = [];
foreach (["src", "tests"] as $folder) {
$walk = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($folder));
foreach ($walk as $file) {
if ($file->isDir() || substr($file->getFilename(), -4) !== ".php") {
continue;
}
$paths[] = $file->getPathname();
}
}
$missing = [];
foreach ($paths as $path) {
$lines = file($path);
$starts = [];
foreach ($lines as $at => $one) {
if (preg_match('/^\s*(?:public|private|protected|static|\s)*' .
'function\s+(\w+)/', $one, $found)) {
$starts[] = [$at, $found[1]];
}
}
$starts[] = [count($lines), ""];
for ($which = 0; $which < count($starts) - 1; $which++) {
$from = $starts[$which][0];
$to = $starts[$which + 1][0];
$body = implode("", array_slice($lines, $from, $to - $from));
/* A docblock before the next method is not part of this one,
and reading it counted names that method is handed. */
$doc_at = strpos($body, "\n /**");
if ($doc_at !== false) {
$body = substr($body, 0, $doc_at);
}
/* A name that stands in a comment is not a use of it. */
$body = preg_replace('/\/\*.*?\*\//s', "", $body);
$body = preg_replace('/\/\/[^\n]*/', "", $body);
if (!preg_match_all('/\$(\w*_model)\b/', $body, $found)) {
continue;
}
foreach (array_unique($found[1]) as $name) {
/* Given as an argument, or given a value anywhere. */
if (preg_match('/function\s+\w+\s*\([^)]*\$' . $name . '\b/s',
$body) || preg_match('/\$' . $name . '\s*=[^=]/', $body) ||
preg_match('/\$' . $name . '\s*\)/', $body)) {
continue;
}
$missing[] = basename($path) . "::" . $starts[$which][1] .
" uses \$" . $name;
}
}
}
foreach ($missing as $one) {
echo " " . $one . "\n";
}
echo "check: " . (count($missing) ?
count($missing) . " method(s) use a model nothing built" :
"every model a method uses is built there") . "\n";
exit(count($missing) ? 1 : 0);