0

I have implemented a Service which does stuff with a RESTful API:

services:
  api.clientname:
    class: Drupal\my_custom_module\Api\Clientname
    arguments: ['@http_client', '@messenger', '@logger.factory', '@uuid']

I'm injecting dependencies for ['@http_client', '@messenger', '@logger.factory', '@uuid']:

  • Guzzle HTTP Client
  • messenger service to call $this->messenger->addMessage(),
  • logger factory to call $this->loggerFactory->get('my_custom_module')->debug($message, $variables),
  • UUID service to generate UUID v4, per API specification.

I'm also using the StringTranslationTrait to get $this->t() working in my class.

All this is great so far. When it works, it works, and it logs success to the dblog. But it also needs to log failures. I'm having a problem with exception handling.

I'm trying to do something like this:

    while ($apiCallAttempts < API_CALL_LIMIT && $apiSuccess === FALSE) {
      $apiCallAttempts++;
      try {
        $accessToken = $this->obtainAccessToken($url, $postFields);
        $message = "Step 1: Access Token obtained from API endpoint";
        $this->loggerFactory->get('my_custom_module')->debug($message, []);
        $apiSuccess = TRUE;
      }
      catch (Exception $e) {
        // TODO: "watchdog_exception('my_custom_module', $e);".
        $variables = Error::decodeException($e);
        $this->loggerFactory->get('my_custom_module')->error('%type: @message in %function (line %line of %file).', $variables);
        if ($apiCallAttempts === API_CALL_LIMIT && $apiSuccess === FALSE) {
          // Set errorMessage for messenger service.
          $errorMessage = 'Error CLIENTNAME-01: Authentication API call failed';
          $message = 'Failed to sync %label with API. <br> @error after @limit attempts.';
          $variables = [
            '%label' => $form_id,
            '@error' => $errorMessage,
            '@limit' => strval($apiCallAttempts),
          ];
          $this->messenger->addMessage($errorMessage, 'error');
          $this->loggerFactory->get('dex_provider_hcp_forms')->error($message, $variables);
          return $accessToken;
        }
      }

but it doesn't work because:

Fatal error: Trait 'Drupal\my_custom_module\Api\Exception' not found in /app/docroot/modules/custom/my_custom_module/src/Api/Clientname.php on line 66

After some Googling, I am very confused about how to add the global PHP Exception to my Service class namespace.

Removing a use declaration inside the class removed the "Trait not found" error.

The new error message was:

Error: Class 'Drupal\my_custom_module\Api\Error' not found

EDIT: Both of these things were happening for the same reason. I was using Exception and Error inside my class without prepending them with a backward slash, causing PHP to assume that Exception was in the same namespace as the one I declared for the file. Using \Exception and \Error instead resolved the issue.

The new error message is:

Error: Call to undefined method Error::decodeException()

5
  • Why Trait not found? Are you sure the error is not in a different part of the class? Perhaps you could post the entire class code, but only with the code lines necessary to produce the error. See stackoverflow.com/help/minimal-reproducible-example
    – 4k4
    Aug 19 '20 at 20:32
  • "Trait not found" happened because I tried to add use Exception; inside my Class. Taking that out, and adding a backslash behind \Exception causes the error message to go away, but now when I submit an API request to a deliberately malformed API endpoint, it just hangs and does not log the exception. I must be doing something else wrong. Aug 19 '20 at 20:40
  • 2
    You probably want to use Drupal\Core\Utility\Error;. But I'm afraid the edited question is even more unclear what you are actually asking.
    – 4k4
    Aug 19 '20 at 21:17
  • @4k4 I edited the question. Hopefully it is clearer now. Aug 19 '20 at 21:32
  • Please don't edit your question in a way that it invalidates an already given answer others have put efforts in. Please ask a new question instead.
    – leymannx
    Aug 19 '20 at 22:04
4

When using unqualified class names like Exception and Error, and in the absence of a use statement to qualify the names, PHP assumes those classes are in the "current" namespace. The namespace of your service class appears to be Drupal\my_custom_module\Api, so that is where PHP will look for Exception and Error. When PHP does not find those classes, you will get an error.

To avoid this error, add a backslash before the class name for classes that are in the global namespace. So use \Exception and \Error instead. You do not need a use statement for either of these.

The error Fatal error: Trait 'Drupal\my_custom_module\Api\Exception' not found in /app/docroot/modules/custom/my_custom_module/src/Api/Clientname.php on line 66. is because you probably said use Exception; within the body of your class. The error Error: Class 'Drupal\my_custom_module\Api\Error' not found is because you referred to Error and not \Error.

Note that all these problems are just basic PHP issues - they are not caused by Drupal and do not involve Drupal at all. Specifically, it does not matter that you're in a service class, or that you're doing exception handling, etc.

1
  • 2
    The original post has now been edited with a new error Error: Call to undefined method Error::decodeException(). This is because the PHP \Error class does not have a decodeException() method - that's a valid error. It seems you want to use the Drupal\Core\Utility\Error class instead, which DOES have that method. In that case, don't refer to the class as \Error, just use Error. But you MUST ALSO add a use statement at the top of your class file, outside the class declaration, which says use Drupal\Core\Utility\Error;
    – anonymous
    Aug 19 '20 at 21:21

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