在没有类依赖的自定义类/子系统中使用 Laravel 4 模型

Posted

技术标签:

【中文标题】在没有类依赖的自定义类/子系统中使用 Laravel 4 模型【英文标题】:Using Laravel 4 models in custom classes / subsystems without class dependency 【发布时间】:2014-01-28 09:23:16 【问题描述】:

我正在构建一个解析器系统,它将根据请求/cronjob 解析大量不同的 XML/JSON 提要。 我使用 Laravel 4。

线程的目的是在我的上下文中使用 IoC,而不是在自定义类方法中硬编码模型名称

为 Soccer Player 提供一个解析器示例,其 XML 结构如下:

<players category="Midfielders">
   <player id="777">
      <name>Caio Augusto Paim do Santos</name>
   <statistic>
      <club name="Camaçari" id="7191" league="Baiano 2" league_id="1136" season="2013" minutes="" appearences="" lineups="" substitute_in="" substitute_out="" substitutes_on_bench="" goals="" yellowcards="" yellowred="" redcards=""/>

我在我的 /app 文件夹中创建了一个名为 /parsers 的附加目录。这些是自定义类,它们都在同一个文件夹中扩展或实现自定义抽象/接口,基本上负责接收 XML/JSON 文件的路径并返回一个结构良好的 php 数组。

它们在自动加载的 composer.json 中添加为:"app/parsers"

附件结构截图

一切都很好,代码/类是可测试的,不依赖于其他类,但问题就在这里。

查看 XML 示例,其中有: &lt;club id="XXX" league_id="YYY" /&gt; 这是提要俱乐部 ID 和提要联赛 ID,但我在数据库中有自己的 ID 引用到提要 ID。

就像这个截图:

所以逻辑说:转到数据库,检查联赛表中是否有 id 以及从 XML 文件提供的 feed_id。 如果是,获取它,如果不是,创建一个新的联赛并获取 id 以供将来参考。

这需要我在我的解析器类中使用模型,现在我知道你可以使用 IoC 并将模型注入控制器,但我不确定我是否可以对我的解析器类做同样的事情......

所以在我的解析器类中间做这样的事情:

// Try to get league and season ids from database if they already exists, if not, insert
$leagueId = DB::select('SELECT id FROM league WHERE feed_id=?', array($data['league_id']));

$league = new LeagueModel();

非常不正确。

现在只是为了澄清这一切的工作方式,我的解析器在 Laravel Command 类中被调用,如下所示:

/**
* Execute the console command.
*
* @return void
*/
public function fire()

    $this->setParser();
    $this->setStorage();
    $this->parser->parseFile($file);

Laravel Command 类在我的控制器中被调用,例如:

$stamps = $this->getStamp();
Artisan::call('command:getSoccerPlayer',array('stamps' => $stamps, 'parser_id' => Request::segment(2)));

Controller 本身是通过 URI 调用的: /jobs/soccer_player/parse?type=soccer&amp;directory=players

**你有什么建议或者你将如何克服这个问题来避免依赖并在这种情况下仍然使用模型与数据库进行交互? **

PS 请不要注意我的屏幕截图上的整个解析逻辑现在都在同一个方法“解析”中,一旦我看到我希望它如何工作/外观的全貌,我会将它分解成碎片。

感谢任何帮助!

【问题讨论】:

你避免依赖的目的是什么?您的意思是避免使用依赖注入将模型添加到您的类中吗?您是否检查过接口存储库(“存储库模式”)的使用? 我的目的是在解析方法中使用 IoC,而不是硬编码模型名称/查询。我只是不知道怎么做。 Laravel 的社区非常低,而且从不回答。 :( 【参考方案1】:

你仍然可以调用你的命名空间模型

use App\Models\League; 

class SoccerPlayerParser extends AbstractParser
    //...

    public function parse()
    
       //...
        $league = App\Models\League::find($data['league_id']);
       //...
    

    //....

【讨论】:

并非如此。如果我为我的模型提供命名空间,它会丢失 Laravel 默认提供的命名空间,因此我不再有权访问 DB 外观:-/ 请您详细解释一下它是如何失去其外观的 Namespacing 基本上是告诉 SoccerPlayerParser 类在哪里可以找到联赛类 在我声明一个命名空间后,如:namespace App\Models; class League extends Eloquent 没有它,SoccerPlayerParser 对 App\Models 命名空间一无所知:/ 添加命名空间后不能只添加“使用数据库”吗?你的 composer.json 里有什么? "不是真的。如果我给我的模型提供命名空间,它会丢失 Laravel 默认提供的命名空间,因此我不再有权访问 DB 外观:-/" 你仍然可以。应用命名空间后,它会从全局类命名空间中删除定义的类。如果您想使用全局命名空间(即 DB)中的类,只需在命名空间声明后添加 use DB;【参考方案2】:

我在这里看到了两种可能的解决方案,但我不能 100% 确定如何将它集成到您​​的项目中。

第一个是将要使用的模型类的名称存储在配置文件中,并通过new $class 实例化模型,其中$class 是通过Config::get 或类似方法检索到的值。这种解决方案在包中很常见,甚至 Laravel 自己也使用它(参见 app/config/auth.php 中的模型设置)。

另一种方法是不实例化模型,而是为其创建一个接口,然后将其依赖注入到您的命令中。您可以使用Artisan::resolve('MyNamespace\MyCommand') 而不是Artisan::add(new MyCommand) 轻松地将内容自动注入到您的命令中,然后像通过控制器一样通过类型提示进行注入。 http://laravel.com/docs/ioc#practical-usage

将接口设置为命令构造函数的参数后,您可以使用App::bind('MyInterface', 'MyModel') 告诉 Laravel 注入哪个类,并且可以随时交换。

【讨论】:

以上是关于在没有类依赖的自定义类/子系统中使用 Laravel 4 模型的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法制作一个可以在 Java 中使用 [] 的自定义类,类似于数组?

Android Gradle 插件自定义 Gradle 插件模块 ④ ( META-INF 中声明自定义插件的核心类 | 在应用中依赖本地 Maven 仓库中的自定义 Gradle 插件 )

使用依赖属性在自定义类中设置属性

为啥我的自定义类没有出现在 Interface Builder 的下拉列表中?

DynamicLinq:如何使用没有类名的自定义类方法来 ParseLambda

tailwindcss 没有在断点内使用我的自定义类