10

I'm finding that the biggest problem in working with Drupal 8 is I can't get the data I need. Drupal 8 wants me to use public methods rather than manually drilling down thru an object. The problem is, I can't figure out a consistent way for getting a list of available methods! (they magically exist, and I feel like I'm just supposed to know about them).=

For this example, let's say I have a content type with a video field. I need to get the raw URL of the video file in that field.

So I'd start with a node id ($nid), and somehow I have to figure out how to load the node. This isn't too bad because there's lots of examples. So I do something like $node = \Drupal\node\Entity\Node::load($nid);.

So far so good. Then I need to get the value of my video field (field_main_video). This took me FOREVER to figure out because there's conflicting documentation around the 'net. Finally I figured out I'd have to do something like this (because it is a multivalue item):

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

...then loop thru the array etc. Using kint didn't help me find this, either. Because, for example, if I kint($node) and look under methods, I don't see getValue() as an item there. Still not terrible, because there were enough examples around to figure it out.

As I go deeper, though, what I didn't know (this is the important part) was that rather than getting the video field entity id, then loading the entity, then finding the "uri" field in the entity, etc (like I would in D7): There was a method that lets me get the URI all in this same line of code!

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

But how could I possibly have known this getFileUri() existed? I happened to stumble upon it in a blog post. This truly DOES make getting a URI easier than in D7...but only if you know (magically) what methods exist for each 'level' of an object.

In the end, with this example I'm asking: How do you find all public methods for each level of an object in a way that's easy to read and understand? Note that it seems there should be a drupal-centric (ie. devel module) way of doing this rather than manually searching api.drupal.org or using something IDE specific?

  • 1
    The official documentation is at api.drupal.org. Once you understand the class of the object you are handling, you get all the methods, including the inherited ones. – kiamlaluno Mar 14 '17 at 14:49
  • 1
    ...but rather than looking up everything on api.drupal.org, surely there is a way in php/devel to dump the available methods to the screen on command? – Bobby Mar 14 '17 at 14:52
12

Content entities are different from most other things in that they often do not have methods and proper interfaces, at least not for configurable fields.

In case of content entities and fields, public methods is not really what you actually want to know, what you want is to know about fields and properties. And only when you get to an entity again through a reference then the methods matter.

For an overview, I always refer to the great Entity API Cheat Sheet.

Content entities have a fixed structure, Entity > Field (FieldItemList) > FieldItem -> Property. A property is either scalar or a reference to something else, e.g. another entity, a language object, a date object, ...

For a few specified examples, some useful snippets:

// 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();
}
  • Nice! This is going to take a bit to digest, but i'm leaning towards this being the accepted answer. Thanks! It doesn't exactly answer the question but thats only because my question and my example were sort of asking 2 different things. Thank you! – Bobby Mar 15 '17 at 14:11
  • @Berdir, this is awsome list of examples, hitting the nail really. I was just google for some info, any info and nothing even close to this. Great answer, book material. – Marko Blazekovic Oct 11 '17 at 11:55
4

Not sure if that will completely answer your question but what helps me a lot is using the diagrams feature in PhpStorm.

For example showing the hierarchy enter image description here

You have options to show also method names

enter image description here

I hope this helps you in a way.

  • You can also open a class with command+click, then command+7 or click Structure tab to see the class structure (where your project directory view would be) to quickly scan the same information without opening UML. – Kevin Mar 14 '17 at 14:49
  • I don't use phpstorm, but this is good to know for future reference. I'm looking for a way to do this using devel or something drupal-centric. surely something must be built in somewhere? – Bobby Mar 14 '17 at 14:53
  • I am sorry to say that, but I really don't think at this moment you can efficiently tinker with the API without using this IDE. – O V Mar 14 '17 at 14:54
  • NetBeans also includes some PHP hierarchy diagrams. Probably not so cool, but NetBeans is Free Software (PHP Storm is closed source and IMHO expensive) and you can download it for free. – sanzante Mar 14 '17 at 14:58
  • Any IDE worth their salt can do this. BTW PHPStorm is not expensive if you utilize what it has to offer. You can use the free EAP version, and if you work on an open source project (Drupal modules or themes), JetBrains will GIVE you a free license. Not a discussion for here though. – Kevin Mar 14 '17 at 15:01
4

Well, I found myself using quite often the combination of var_dump(get_class_methods($object)) to have a list of available methods for the given class.

I also look quite often into api.drupal.org for further details.

  • 2
    This seems like the answer most closely related to what I was looking for so far. Thanks! – Bobby Mar 14 '17 at 16:50
0

You're already very close.

First, let's look at the definition of the method: https://api.drupal.org/api/drupal/core%21modules%21file%21src%21Entity%21File.php/function/File%3A%3AgetFileUri/8.2.x

From here, we can see the class this is part of, and there is a link to it:

Class

File
Defines the file entity class.

Clicking through takes us to: https://api.drupal.org/api/drupal/core%21modules%21file%21src%21Entity%21File.php/class/File/8.2.x

In your IDE, you could also search for the \Drupal\file\Entity\File class. One way to be sure this is the correct class is to look at the annotation:

@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"
  }
) 

Notice the id — it is file. Presumably, if debugging, you could look at the contents of field_main_video->entity and you would see this ID somewhere. Then you just search for it in your IDE. Usually, though, one knows enough about the entity types one is using to guess one's way to the right class (after which one could verify that the annotation contains the correct ID).

In this particular case, I also know that File is probably a class that extends ContentEntityBase, since it's more like database content (a content entity) than configuration (a configuration entity). So when I see my assumptions confirms, that helps me know I have found the right class.

So, in short: your IDE, strategic debug() statements, and some guesswork are the best ways to discover Drupal 8.

P.S. Change records can also be helpful. They are at https://www.drupal.org/list-changes/drupal

  • I take the OP's problem is the reverse: knowing which public methods a class implements / has available. – kiamlaluno Mar 14 '17 at 14:54
  • Yeah, I may have to read this again, but I don't think it's what I'm looking for. I'm trying to figure out how getFileUri() even exists in the first place! – Bobby Mar 14 '17 at 14:59
  • @Bobby A file is an entity type, so you just look at its source, where you'll find the method you're after listed and fully documented. Is it just that you didn't know a file is an entity type? Or that you don't know the convention for locating an entity type in code? Or something else further up the chain? There are many layers of abstraction for everything in D8, it's the symfony way, so there's a lot of "base" knowledge you need first before delving into the code – Clive Mar 14 '17 at 15:29
0

You can use the PHP get_class_methods function. The example below users a file upload:

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

This will add all methods available to the object $file into your $methods array, which you can print and then see all methods available. This is valid for any objects in PHP, not just Drupal.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.