php 如何获取Laravel中所有模型的列表?

hlswsv35  于 2023-05-16  发布在  PHP
关注(0)|答案(9)|浏览(218)

我想在Laravel项目中找到所有模型的列表,数据库表作为备份。
我想这样做是为了构建一个 Jmeter 板,显示所有模型中的数据随时间变化的方式,即如果存在用户模型,则显示在过去90天内每天添加或修改的用户数。

qvtsj1bj

qvtsj1bj1#

我想建议一种不同的方法,使用PHP reflection,而不是依赖于所有模型都驻留在名为Model的名称空间或目录中。
下面的代码示例收集了所有的应用程序类,验证它们是否实际上扩展了EloquentModel类,并且不是抽象的。

<?php

use Illuminate\Container\Container;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\File;

function getModels(): Collection
{
    $models = collect(File::allFiles(app_path()))
        ->map(function ($item) {
            $path = $item->getRelativePathName();
            $class = sprintf('\%s%s',
                Container::getInstance()->getNamespace(),
                strtr(substr($path, 0, strrpos($path, '.')), '/', '\\'));

            return $class;
        })
        ->filter(function ($class) {
            $valid = false;

            if (class_exists($class)) {
                $reflection = new \ReflectionClass($class);
                $valid = $reflection->isSubclassOf(Model::class) &&
                    !$reflection->isAbstract();
            }

            return $valid;
        });

    return $models->values();
}
oewdyzsn

oewdyzsn2#

我会浏览你的文件系统,从models文件夹中取出所有的php文件。我把我的模型保存在app/Models文件夹中,所以类似这样:

$path = app_path() . "/Models";

function getModels($path){
    $out = [];
    $results = scandir($path);
    foreach ($results as $result) {
        if ($result === '.' or $result === '..') continue;
        $filename = $path . '/' . $result;
        if (is_dir($filename)) {
            $out = array_merge($out, getModels($filename));
        }else{
            $out[] = substr($filename,0,-4);
        }
    }
    return $out;
}

dd(getModels($path));

我刚试过这个,它吐出了我所有模型的完整文件路径。您可以剥离字符串,使其只显示名称空间和模型名称(如果这是您正在寻找的)。

00jrzges

00jrzges3#

  • 请注意,这可能会错过在引导过程中不在范围内的模型。请参见下面的编辑。*

有一种方法可以加载声明的模型,而无需迭代文件系统。由于大多数模型都是在引导后声明的,你可以调用get_declared_classes并像这样过滤模型命名空间的返回值(我的类在\App\Models命名空间中):

$models   = collect(get_declared_classes())->filter(function ($item) {
    return (substr($item, 0, 11) === 'App\Models\\');
});

正如@ChronoFish所提到的,这种方法并不能在所有情况下提取所有模型。
例如,这在 Bootstrap 生命周期的早期阶段根本不起作用,如在服务提供商中。但即使它在工作,它也可能会错过一些模型,这取决于项目的结构,因为并非所有类都在范围内。在我的测试项目中,加载了所有模型,但在更复杂的应用程序中,可能会遗漏大量的类。
感谢您的评论!
我目前正在使用这样的东西:

$appNamespace = Illuminate\Container\Container::getInstance()->getNamespace();
        $modelNamespace = 'Models';

        $models = collect(File::allFiles(app_path($modelNamespace)))->map(function ($item) use ($appNamespace, $modelNamespace) {
            $rel   = $item->getRelativePathName();
            $class = sprintf('\%s%s%s', $appNamespace, $modelNamespace ? $modelNamespace . '\\' : '',
                implode('\\', explode('/', substr($rel, 0, strrpos($rel, '.')))));
            return class_exists($class) ? $class : null;
        })->filter();

$modelNamespace是为那些有一个独特的文件夹和命名空间的模型,这是强烈推荐的,或者谁正在使用Laravel 8+,这是新的默认值。那些只使用Laravel 7或更低版本的默认值的人可以将此留空,但随后将拉入应用程序目录中的所有类,而不仅仅是Eloquent模型。
在这种情况下,你可以通过像这样过滤列表来确保你只得到模型:

$models->filter(
    function ($model) {
        return !is_subclass_of($model, Illuminate\Database\Eloquent\Model::class);
    }
);
falq053o

falq053o4#

根据主题答案:

<?php

use Illuminate\Support\Facades\File;

/**
 * Get Available models in app.
 * 
 * @return array $models
 */
public static function getAvailableModels()
{

    $models = [];
    $modelsPath = app_path('Models');
    $modelFiles = File::allFiles($modelsPath);
    foreach ($modelFiles as $modelFile) {
        $models[] = '\App\\' . $modelFile->getFilenameWithoutExtension();
    }

    return $models;
}
x8diyxa7

x8diyxa75#

我正在寻找一些可读的东西,所以,我做了这个代码,得到所有模型的名称,你可以格式化你想要的。

<?php

function getModelNames(): array
{
    $path = app_path('Models') . '/*.php';
    return collect(glob($path))->map(fn ($file) => basename($file, '.php'))->toArray();
}
fjaof16o

fjaof16o6#

一种方法是使用Standard PHP Library (SPL)递归地列出目录中的所有文件,您可以使用下面的函数。

function getModels($path, $namespace){
        $out = [];

        $iterator = new \RecursiveIteratorIterator(
            new \RecursiveDirectoryIterator(
                $path
            ), \RecursiveIteratorIterator::SELF_FIRST
        );
        foreach ($iterator as $item) {
            /**
             * @var \SplFileInfo $item
             */
            if($item->isReadable() && $item->isFile() && mb_strtolower($item->getExtension()) === 'php'){
                $out[] =  $namespace .
                    str_replace("/", "\\", mb_substr($item->getRealPath(), mb_strlen($path), -4));
            }
        }
        return $out;
}
getModels(app_path("Models/"), "App\\Models\\");
zqdjd7g9

zqdjd7g98#

这就是我的解决方案。不用于搜索子文件夹中的模型。

<?php

use Illuminate\Database\Eloquent\Model;

function getModels(?string $path = null): array
    {
        $path = $path ?? app_path();

        // Se obtienen los archivos en el directorio, sin subdirectorios.
        $files = File::files($path);

        // Se obtienen los nombres sin rutas ni extensiones.
        $filenames = array_map(function ($file): string {
            $pathinfo = pathinfo($file);

            return $pathinfo['filename'];
        }, $files);

        $namespace = "\App";

        // Se conservan aquellos que sean modelos.
        $mapped = array_map(
            function ($filename) use ($namespace): ?string {
                $class = "{$namespace}\\{$filename}";

                if (!class_exists($class)) {
                    return null;
                }

                $object = new $class;

                if (!$object instanceof Model) {
                    return null;
                }

                return $class;
            },
            $filenames
        );

        // Se filtran los que no son modelos.
        $models = array_filter($mapped);

        return array_values($models);
    }
c0vxltue

c0vxltue9#

我认为这样更好更简单(不使用反射类)

function get_all_models(): array
    {
        $namespace = app()->getNamespace() . "Models\\";
        $files     = File::allFiles(app_path('Models'));
        return collect($files)
             ->map(function (SplFileInfo $file) use ($namespace) {
                 $filePath = str_replace('.' . $file->getExtension(), '', $file->getRelativePathname());
                 return $namespace . str_replace('/', '\\', $filePath);
             })
             ->filter(function ($class) {
                 return class_exists($class) && is_subclass_of($class, Model::class);
             })->values()->toArray();
    }

相关问题