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

Posted

技术标签:

【中文标题】如何获取 Laravel 中所有模型的列表?【英文标题】:How do I get a list of all models in Laravel? 【发布时间】:2016-03-07 08:01:31 【问题描述】:

我想在 Laravel 项目中找到所有模型的列表,作为备份的数据库表。

我想这样做来构建一个仪表板,显示所有模型中的数据随时间变化的方式,即如果有用户模型,过去 90 天内每天添加或修改的用户数量。

【问题讨论】:

【参考方案1】:

我将浏览您的文件系统并从您的模型文件夹中提取所有 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));

我刚试过这个,它吐出了我所有模型的完整文件路径。如果那是您要查找的内容,您可以剥离字符串以使其仅显示名称空间和模型名称。

【讨论】:

好的!这让我的某个地方有用,实际上我可以使用它。 您可以使用app_path('Models') 而不是在第一行连接一个字符串,Laravel 的方式也是使用File::allFiles($path) 而不是自己编写所有逻辑。【参考方案2】:

我想建议一种不同的方法,使用 PHP reflection,而不是依赖所有模型都将驻留在名为 Model 的命名空间或目录中。

下面的代码示例收集了所有应用程序类,验证它们是否真的扩展了 Eloquent Model 类并且不是抽象的。

<?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();

【讨论】:

这绝对是这里最强大的选项。谢谢?? 谢谢!迄今为止最可靠的答案,尽管它缺少包提供的模型(想想 spatie 权限/标签等) 那是真的@Anders,这段代码只关心应用程序类。 :) @RibeiroBreno 我的目录中有一个特征,它在$valid = $reflection-&gt;isSubclassOf(Model::class) 行给出错误 Class App\Models\Traits\Model 不存在 你好@DaniyalNasir!这看起来像一个命名空间问题。您是否包含了上述所有“使用”语句?【参考方案3】:

请注意,这可能会遗漏在引导期间不在范围内的模型。请参阅下面的编辑。

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

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

正如@ChronoFish 提到的,这种方法并不是在所有情况下都拉出所有模型。

例如,这在引导生命周期的早期阶段根本不起作用,就像在服务提供商中一样。但即使它正在工作,它也可能会丢失一些模型,具体取决于您的项目结构,因为并非所有类都在范围内。对于我的测试项目,所有模型都已加载,但在更复杂的应用程序中,这可能会遗漏大量类。

感谢您的评论!

我目前正在使用这样的东西:

        $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 或更低版本的默认设置可以将其留空,但随后会拉入 app 目录中的所有类,而不仅仅是 Eloquent 模型。

在这种情况下,您可以通过像这样过滤列表来确保只获得模型:

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

【讨论】:

我认为这只会给你实例化的类。它不会为您提供我认为是 OP 要求的项目的所有模型。 @ChronoFish 类不必实例化,只需声明(在范围内定义)。一旦 Laravel 加载了所有模型依赖项,您的所有模型都将通过 get_declared_classes 可用。然而,应该提到的是,在 Laravel 引导生命周期的某些早期阶段,情况还不是这样(例如,在运行服务提供者时)。我将在我的回答中包含这一点以澄清。 我注意到 Laravel 似乎并没有主动引导模型类。在我的测试项目中声明了所有可用模型,但在另一个项目中,一些模型丢失了,因此根据您的项目,这可能不是您的正确选择,感谢您的评论! 聪明的方法,喜欢这个想法,不知道 is_subclass_of 方法,这解决了我的问题。【参考方案4】:

一种方法是使用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\\");

【讨论】:

你应该添加一些关于你在做什么以及 OP 做错了什么的描述 使用 SPL secure.php.net/manual/en/book.spl.php递归列出目录中的所有文件【参考方案5】:

根据主题答案:

<?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;

【讨论】:

如果应用程序有添加更多模型的服务提供商,这个答案会错过他们。 (在应用开发者决定为模型使用不同路径的情况下)【参考方案6】:

我正在寻找可读的东西,所以,我制作了这段代码来获取所有模型名称,你可以按照自己的意愿格式化。

<?php

function getModelNames(): array

    $path = app_path('Models') . '/*.php';
    return collect(glob($path))->map(fn ($file) => basename($file, '.php'))->toArray();

【讨论】:

又好又短。谢谢【参考方案7】:

这是我的解决方案。不打算在子文件夹中搜索模型。

<?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);
    

【讨论】:

【参考方案8】:

你也可以试试这个来解决问题:

https://gist.github.com/mohammad425/231242958edb640601108bdea7bcf9ac

【讨论】:

以上是关于如何获取 Laravel 中所有模型的列表?的主要内容,如果未能解决你的问题,请参考以下文章

如何从每个父模型中获取 N 条记录?在 laravel 中雄辩

如何从 Laravel 8 Jetstream 注册页面中的数据库中获取数据?

如何在 laravel 中获取所有服务器会话的列表?

如何在laravel中获取嵌套关系模型[重复]

laravel-mongodb中如何获取数据库中所有表的名称

如何在 laravel 中获取所有模型/迁移名称并添加单个新列