15

I am trying to create Drupal entity instances from an external script that is not part of Drupal or a Drupal module.

For Drupal 7 there was drupal_bootstrap to load the required Drupal dependencies. However, after a long search all I found for Drupal 8 was a note that drupal_bootstrap is deprecated for Drupal 8.

And indeed, I get a

Call to undefined function drupal_bootstrap()

when I try to call it after including as in

define('DRUPAL_ROOT', __DIR__ .'/../drupal');
require_once DRUPAL_ROOT . '/core/vendor/autoload.php';
require_once DRUPAL_ROOT . '/core/includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);

So how can I use the Drupal 8 API from an outside script?!

1
  • You can use drush php-script. This execute php code with a full Drupal bootstrap directly from a shell script.
    – rpayanm
    Sep 15, 2015 at 19:27

5 Answers 5

9

For current version of drupal 8.x:

define('DRUPAL_DIR', '/usr/share/nginx/html');
use Drupal\Core\DrupalKernel;
use Symfony\Component\HttpFoundation\Request;
require_once DRUPAL_DIR . '/core/includes/database.inc';
require_once DRUPAL_DIR . '/core/includes/schema.inc';
// Specify relative path to the drupal root.
$autoloader = require_once DRUPAL_DIR . '/autoload.php';

$request = Request::createFromGlobals();

// Bootstrap drupal to different levels
$kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
$kernel->boot();
$kernel->prepareLegacyRequest($request);

$em = $kernel->getContainer()->get('entity.manager');

$entity = $em->getStorage('node')->create(
        array(
          'type' => "article",
          'title'=> "test entity",
          'body' => "body body body",
        ));

$entity->save();
2
  • You don't need require_once and preparelegacyrequest. Here's some suggestions. // Avoid errors if you use realpath chdir(DRUPAL_DIR); // Uncomment if you need a processed request object. // $kernel->prepareLegacyRequest($request); // $kernel->handle($request);
    – Teenage
    Oct 20, 2020 at 16:55
  • How to use this for multisite with same code base and multidatabase? I see "The specified database connection is not defined" Feb 2, 2021 at 10:48
5

I finally ended up with this code. It has some ugly extra includes but at least it works:

define('DRUPAL_DIR', __DIR__ .'/../drupal');

use Drupal\Core\DrupalKernel;
use Symfony\Component\HttpFoundation\Request;

$autoloader = require_once DRUPAL_DIR . '/autoload.php';
$request = Request::createFromGlobals();
$kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
$kernel->boot();

require_once DRUPAL_DIR . '/core/includes/database.inc';
require_once DRUPAL_DIR . '/core/includes/schema.inc';


$em = $kernel->getContainer()->get('entity.manager');

$entity = $em->getStorage('my_entity')->create(array(
        'id' => "116",
        'name' => "test entity",
));
$entity->save();
5
  • You can get by without all those require_once calls if you just require autoload.php: require_once 'your_drupal/autoload.php';
    – paul-m
    Sep 19, 2015 at 19:46
  • I think I do require autoload.php (line 4)? This did suffice when I used handleRequest but not when trying to boot only the basics to get to the entity manager.
    – sleidig
    Oct 1, 2015 at 9:42
  • 2
    You may need to add chdir()
    – pmagunia
    Feb 26, 2017 at 3:38
  • Removing require_once gives "Call to undefined function Drupal\Core\Entity\Sql\drupal_schema_get_field_value()" which is quite lame :( Jan 13, 2020 at 13:54
  • 1
    You don't need require_once. Here's some suggestions. ``` lang-php // Avoid errors if you use realpath chdir(DRUPAL_DIR); // Uncomment if you need a processed request object. // $kernel->prepareLegacyRequest($request); `// $kernel->handle($request);```
    – Teenage
    Oct 20, 2020 at 17:01
3

Firstly: Always look for change notices. You can find them here: https://www.drupal.org/list-changes

Here's the main one dealing with drupal_bootstrap(): https://www.drupal.org/node/2275139

Have a look at Drupal 8's front controller (index.php).

You make an instance of the kernel and then have it handle requests.

But since you only want to poke entities into it, you won't handle requests. You just need to bootstrap the kernel and then use the various services to add your entities. The list of services is in core/core.services.yml and is quite huge. You might look for entity_manager.

Also, D8 has a RESTful API built in, so you might just be able to let D8 do all the work while you ping it over http.

3

You can use the following to bootstrap Drupal 8 from an external script to query the database:

use Drupal\Core\DrupalKernel;
use Drupal\Core\Site\Settings;
use Symfony\Component\HttpFoundation\Request;

define('DRUPAL_DIR', __DIR__ .'/../drupal');

// Bootstrap
$autoloader = require DRUPAL_DIR . '/autoload.php';
require_once DRUPAL_DIR . '/core/includes/bootstrap.inc';
require_once DRUPAL_DIR . '/core/modules/node/node.module'; // necessary when saving nodes 
$request = Request::createFromGlobals();
Settings::initialize(dirname(dirname(DRUPAL_DIR)), DrupalKernel::findSitePath($request), $autoloader);
$kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod')->boot();

$em = $kernel->getContainer()->get('entity.manager');
$node_storage = $em->getStorage('node');
// ...
1
  • For Drupal 9, this answer worked perfectly (+1)
    – MiharbKH
    Feb 17, 2022 at 12:06
2

To bootstrap Drupal 8 from an external script, I would use the following code, similar to the code used in the authorize.php file.

use Drupal\Core\DrupalKernel;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

// Change the directory to the Drupal root.
chdir('the Drupal root directory');
$autoloader = (require_once 'autoload.php');

try {
  $request = Request::createFromGlobals();
  $kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
  $kernel->boot();
  $kernel->preHandle($request);

  // Ensure the request includes the session if appropriate.
  if (PHP_SAPI !== 'cli') {
    $request->setSession($kernel->getContainer()->get('session'));
  }
  
  // Your code.

} catch (HttpExceptionInterface $e) {
  $response = new Response('', $e->getStatusCode());
  $response->prepare($request)->send();
  exit;
}

The database.inc file contains only deprecated functions, and it should not be used. The schema.inc file isn't necessary to run queries on entities.

To be able to query node entities, the code needs to load the System and the Node modules.

\Drupal::moduleHandler()->addModule('system', 'core/modules/system');
\Drupal::moduleHandler()->addModule('node', 'core/modules/node');
\Drupal::moduleHandler()->load('system');
\Drupal::moduleHandler()->load('node');

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.