Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show\Field 链式方法调用时与 Str 门面方法名冲突导致 BadMethodCallException #2157

Open
masterwto opened this issue Jan 26, 2025 · 0 comments

Comments

@masterwto
Copy link

链式方法调用时与 Str 门面方法名冲突导致 BadMethodCallException

问题描述

当使用 Show\Field 组件进行链式方法调用时,若方法名与 Illuminate\Support\Str 门面的宏方法同名,会导致错误的方法调用路由。系统会尝试调用不存在的 Str 门面方法而不是字段对象的方法,从而抛出异常。

错误示例:

// 控制器代码
$show->field('path')
->link('#')
->setElementClass('custom-class');
// 抛出异常:
// BadMethodCallException: Method Illuminate\Support\Str::setElementClass does not exist

复现步骤

  1. 创建包含以下代码的 Show 页面:
protected function detail($id)
{
  return Show::make($id, Model::class, function (Show $show) {
    $show->field('path')
      ->link('#')
      ->setElementClass('custom-class');
  });
}
  1. 访问该模型的详情页

  2. 观察控制台错误输出:

BadMethodCallException: Method Illuminate\Support\Str::setElementClass does not exist

预期行为

应该成功调用 Dcat\Admin\Show\Field::setElementClass() 方法,为字段元素添加指定 CSS 类。

实际行为

系统错误地尝试调用 Illuminate\Support\Str::setElementClass() 方法,导致抛出异常。

环境信息

组件 版本
Dcat Admin 2.2.0
Laravel 8.83.0
PHP 8.1.12
数据库 MySQL 5.7

问题分析

通过调试跟踪发现以下关键点:

  1. 方法调用路由机制
    当字段值被转换为字符串时(在 toHtml() 方法中),会触发 __call 魔术方法的路由判断

  2. 源码定位

    • 方法调用入口:src/Show/Field.php:688 (__call())
    • 字符串转换逻辑:src/Show/Field.php:729 (toHtml())
  3. 冲突根源
    当方法名同时存在于以下两个位置时会发生路由错误:

    • Field 组件方法 (如 setElementClass)
    • Str 门面宏方法 (通过 Field::macro() 注册)

临时解决方案

通过自定义视图显式传递参数:

$show->field('path')
->link(admin_route(...))
->view('admin.show.link-field', [
'class' => 'field-path',
'href' => admin_route(...),
'value' => $model->name
]);

对应视图文件:

<!-- resources/views/admin/show/link-field.blade.php -->
<a href="{{ $href }}" class="{{ $class }}">{{ $value }}</a>

建议改进方案

  1. 方法名冲突检测
    Field::__call() 方法中添加优先级判断:

    if (method_exists($this, $method)) {
        return $this->$method(...$parameters);
    }
    if (Str::hasMacro($method)) {
        // ...当前处理逻辑
    }
  2. 别名方法注册
    为常用方法注册保护性别名:

    Field::macro('elementClass', function ($class) {
        return $this->setHtmlAttribute('class', $class);
    });
  3. 文档补充
    Show Field 文档 中添加方法名冲突警告说明


关联仓库
https://github.com/jqhph/dcat-admin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant