我如何找到可用的公共方法?


9

我发现使用Drupal 8的最大问题是我无法获取所需的数据。Drupal 8希望我使用公共方法,而不是通过对象手动向下钻取。问题是,我无法弄清楚获得可用方法列表的一致方法!(它们神奇地存在,我觉得我应该知道它们)。=

对于此示例,假设我有一个带有视频字段的内容类型。我需要在该字段中获取视频文件的原始URL。

因此,我将从节点ID($ nid)开始,以某种方式我必须弄清楚如何加载该节点。这还不错,因为有很多示例。所以我做类似的事情$node = \Drupal\node\Entity\Node::load($nid);

到目前为止,一切都很好。然后,我需要获取视频字段(field_main_video)的值。这使我永远都想不通,因为'net周围存在冲突的文档。最终我发现我必须做这样的事情(因为它是一个多值项):

$video = \Drupal\node\Entity\Node::load($nid)->field_main_video->getValue();

...然后遍历数组等。使用kint也不帮助我找到这个。因为例如,如果我kint($node)查看方法下的内容,则不会在其中看到getValue()。仍然不可怕,因为周围有足够的示例可以弄清楚。

不过,当我深入研究时,我不知道(这是重要的部分)是,不是获取视频字段实体ID,而是加载实体,然后在实体中找到“ uri”字段,等等(例如我在D7中会:)有一种方法可以让我在同一行代码中全部获取URI!

$url = \Drupal\node\Entity\Node::load($nid)->field_main_video->entity->getFileUri();

但是我怎么可能知道这个getFileUri()存在呢? 我在博客文章中偶然发现了它。确实,这样做确实比在D7中更容易获得URI……但前提是您(神奇地)知道对象的每个“层”都有哪些方法。

最后,在这个示例中,我想问:如何以一种易于阅读和理解的方式为对象的每个级别找到所有公共方法? 注意,似乎应该有一种以drupal为中心的方式(即devel模块),而不是手动搜索api.drupal.org或使用特定于IDE的方式?


1
官方文档位于api.drupal.org。了解了要处理的对象的类后,您将获得所有方法,包括继承的方法。
kiamlaluno

1
...但是除了在api.drupal.org上查找所有内容之外,php / devel中肯定有一种方法可以将可用方法转储到命令显示的屏幕上?
鲍比(Bobby)

Answers:


14

内容实体与大多数其他事物不同之处在于,它们通常没有方法和适当的接口,至少对于可配置字段而言,没有。

对于内容实体和字段,公共方法并不是您真正想真正了解的,而是要了解字段和属性。而且只有当您通过引用再次进入实体时,方法才有意义。

有关概述,我总是参考出色的Entity API速查表

内容实体具有固定的结构,即实体>字段(FieldItemList)> FieldItem->属性。属性可以是标量,也可以是对其他事物的引用,例如,另一个实体,语言对象,日期对象等。

对于一些指定的示例,一些有用的摘要:

// List of fields that an entity has, the field definitions also have a lot of information like the type.
array_keys($entity->getFieldDefinitions())

// Use get() instead of the magic __get() on the entity level then you at least get some type hints.
$entity->get('field_name').

// Get the list of properties a certain field has, use array_keys() again for just the names, but the definitions also have the type and if it's computed or not.
$entity->getFieldDefinition('field_name')->getFieldStorageDefinition()->getPropertyDefinitions()

// Most field types have value property, but e.g. entity references have target_id and the computed entity. as you found. File and Image fields have additional properties like title/alt/description.
$entity->get('field_name')->value
$entity->get('field_name')->target_id
$entity->get('field_name')->entity

// Note that get('value') is not the same as ->value on the field item level, get() returns a typed data object, get('value')->getValue() is the same as ->value.

// When not specified, the delta 0 is assumed (all fields are a list internally, even something like the node id), you can use array access or the delta to access another delta, make sure it exists.
$entity->get('field_name')[1]->value
$entity->get('field_name')->get(1)->value

// When you have an entity reference, you can get the entity type and class like this:
$entity->get('field_name')->entity->getEntityTypeId()
$entity->get('field_name')->entity->getEntityType()->getClass()
// or 
get_class($entity->get('field_name')->entity)

// From there you can look up the interface and type hint against that, to a) make sure you have a valid, loadable reference and get type hints in an IDE:
$file = $entity->get('field_name')->entity;
if ($file instanceof \Drupal\file\FileInterface) {
  $file->getFileUri();
}

真好!这将需要一点时间来消化,但是我倾向于这个被接受的答案。谢谢!它并不能完全回答问题,那仅仅是因为我的问题和示例都在问两个不同的问题。谢谢!
鲍比(Bobby)

1
@Berdir,这是一个令人难以置信的例子列表,确实令人难以置信。我只是谷歌的一些信息,任何信息,甚至没有与此接近。很好的答案,本书的材料。
Marko Blazekovic,

4

不确定是否可以完全回答您的问题,但是对我有很大帮助的是使用PhpStorm中的图表功能。

例如显示层次结构 在此处输入图片说明

您可以选择显示方法名称

在此处输入图片说明

希望对您有帮助。


您也可以先按Command +单击,然后再按Command + 7,打开一个类,或单击“结构”选项卡以查看类结构(项目目录视图所在的位置),以快速扫描相同的信息而无需打开UML。
凯文(Kevin)

我不使用phpstorm,但是很高兴知道这点以供将来参考。我正在寻找一种方法来使用devel或以drupal为中心的方法。当然必须在某个地方建一些东西吗?
鲍比(Bobby)

遗憾的是,但是我真的不认为您现在可以在不使用此IDE的情况下有效地修改API。
Oleg Videnov

NetBeans还包括一些PHP层次结构图。可能不是很酷,但是NetBeans是免费软件(PHP Storm是封闭源代码,恕我直言,价格昂贵),您可以免费下载。
sanzante

任何值得他们投入盐分的IDE都可以做到这一点。BTW PHPStorm如果您利用其提供的功能并不昂贵。您可以使用免费的EAP版本,如果您从事的是开源项目(Drupal模块或主题),JetBrains将为您提供免费许可证。虽然这里没有讨论。
凯文(Kevin)

4

好吧,我发现自己经常使用的组合var_dump(get_class_methods($object))来获得给定类的可用方法列表。

我也经常api.drupal.org查看进一步的细节。


2
似乎答案与到目前为止我一直在寻找的最接近。谢谢!
鲍比(Bobby)

0

您已经很亲密了。

首先,让我们看一下方法的定义:https : //api.drupal.org/api/drupal/core%21modules%21file%21src%21Entity%21File.php/function/File%3A%3AgetFileUri/8.2.x

从这里,我们可以看到它属于该类,并且有一个链接:

Class

File
Defines the file entity class.

点击后进入以下网址https : //api.drupal.org/api/drupal/core%21modules%21file%21src%21Entity%21File.php/class/File/8.2.x

在您的IDE中,您也可以搜索\Drupal\file\Entity\File该类。确保这是正确的类的一种方法是查看注释:

@ContentEntityType(
  id = "file",
  label = @Translation("File"),
  handlers = {
    "storage" = "Drupal\file\FileStorage",
    "storage_schema" = "Drupal\file\FileStorageSchema",
    "access" = "Drupal\file\FileAccessControlHandler",
    "views_data" = "Drupal\file\FileViewsData",
  },
  base_table = "file_managed",
  entity_keys = {
    "id" = "fid",
    "label" = "filename",
    "langcode" = "langcode",
    "uuid" = "uuid"
  }
) 

请注意,id它是file。大概,如果进行调试,您可以查看其中的内容,field_main_video->entity并且可以在某个地方看到此ID。然后,您只需在IDE中进行搜索。不过,通常情况下,人们对一个实体类型已经足够了解,可以用来猜测一个人进入正确的类的方式(此后可以验证注释包含正确的ID)。

在这种特殊情况下,我也知道这File可能扩展一个类ContentEntityBase,因为它更像是数据库的内容(内容实体),比配置(配置实体)。因此,当我看到自己的假设得到证实时,这有助于我知道自己找到了正确的班级。

简而言之:您的IDE,战略debug()声明和一些猜测是发现Drupal 8的最佳方法。

PS更改记录也可能会有所帮助。他们在https://www.drupal.org/list-changes/drupal


我认为OP的问题是相反的:知道类实现/拥有哪些公共方法。
kiamlaluno

是的,我可能不得不再读一遍,但我认为这不是我想要的。我试图弄清楚getFileUri()到底是怎么存在的!
鲍比

@Bobby文件是一种实体类型,因此您只需查看其源,即可在其中找到列出并充分记录后的方法。只是您不知道文件是实体类型吗?还是您不知道在代码中定位实体类型的约定?还是链上还有其他东西?D8中所有内容都有很多抽象层,这是symfony方式,因此在深入研究代码之前,首先需要掌握很多“基础”知识
Clive

0

您可以使用PHP的get_class_methods函数。下面的示例向用户上传文件:

$image = $form_state->getValue('image_field_name_from_form');
$file = File::load( $image[0] );
$file->setPermanent();
$file->save();

$methods = [];
foreach (get_class_methods($file) as $method) {
        $methods[] = $method;
}
print_r($methods);

这会将对象$ file的所有可用方法添加到$ methods数组中,您可以打印该数组,然后查看所有可用方法。这对PHP中的所有对象有效,而不仅限于Drupal。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.