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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34053585/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 12:46:05  来源:igfitidea点击:

How do I get a list of all models in Laravel?

phpmysqlsqllaraveleloquent

提问by Tommy Nicholas

I would like to find a list of all models, database tables as a backup, in a Laravel project.

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

I want to do this to build a dashboard that displays the way data in all of the models has changed over time, I.E. if there is a user model, how many users have been added or modified each day for the last 90 days.

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

回答by Jeff

I would navigate through your filesystem and pull out all of the php files from your models folder. I keep my models in the app/Models folder so something like this:

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

I just tried this and it spit out the full filepath of all of my models. You could strip the strings to make it only show the namespace and model name if thats what you are looking for.

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

回答by Lupinity Labs

Please be aware that this might miss models that have not been in scope during bootstrapping. Please see the edit below.

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

There is a way to load the declaredmodels without iterating the file system. Since most of the models are declared after bootstrapping, you may call get_declared_classesand filter the return for your models' namespaces like this (my classes are in \App\Modelsnamespace):

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

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

Edit: Thanks to @ChronoFish's comment I had a look at this method again and indeed it does not pull up all models in all cases.

编辑:感谢@ChronoFish 的评论,我再次查看了这个方法,确实它并没有在所有情况下拉出所有模型。

For example, this does not work at all in early stages of the bootstrap lifecycle like in service providers. But even when it is working, it might miss a few models, depending on your project's structure, as not all classes are always in scope. For my test project, all models were loaded, but in a more complex application, a significant number of classes may be missed by this.

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

Thanks for your comment!

谢谢你的评论!

I am currently using something like this:

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

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

The $modelNamespaceis for those who have a distinct folder and namespace for their models, which is highly recommended. Those who just go with the Laravel defaults can leave this empty, but will then pull in all classes in the app directory, not just Eloquent models. You may then have to use reflection to make sure you only get models...

$modelNamespace是为那些为他们的模型拥有不同文件夹和命名空间的人准备的,这是强烈推荐的。那些只使用 Laravel 默认值的人可以将其留空,但随后会拉入 app 目录中的所有类,而不仅仅是 Eloquent 模型。然后您可能必须使用反射来确保您只获得模型......

回答by RibeiroBreno

I would like to suggest a different approach by using PHP reflectioninstead of relying that all models will reside in a namespace or directory called Model.

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

The code sample below collects all the application classes, verifies if they actually extend the Eloquent Model class and are not abstract.

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

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

回答by Agel_Nash

One way could be to use the Standard PHP Library (SPL)to recursively list all files inside a directory you can make a function like below.

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