diff --git a/.travis.yml b/.travis.yml index 870c0ca..4d44a5d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -61,9 +61,22 @@ script: - cd $TRAVIS_BUILD_DIR/../drupal # Download and enable module and its dependencies - - drush --yes dl xautoload + - drush --yes dl entity --dev + - drush --yes dl xautoload-7.x-5.x - drush --yes dl file_entity + # Patch xautoload to add module invoke wrapping. + - cd sites/all/modules/xautoload + - curl -LO https://www.drupal.org/files/issues/2456877-module-invoke-wrapping-1.patch + - patch -p1 < 2456877-module-invoke-wrapping-1.patch + - cd $TRAVIS_BUILD_DIR/../drupal + + # Patch entity to add module invoke wrapping. + - cd sites/all/modules/entity + - curl -LO https://www.drupal.org/files/issues/2455851-add-additional-interfaces-1.patch + - patch -p1 < 2455851-add-additional-interfaces-1.patch + - cd $TRAVIS_BUILD_DIR/../drupal + # Enable the modules - drush --yes pm-enable simpletest typed_entity typed_entity_example diff --git a/README.md b/README.md index dd53c2f..31e98c8 100644 --- a/README.md +++ b/README.md @@ -158,3 +158,12 @@ Care to add **tests**? You can even have unit testing on your custom business lo (make sure those computations on the aspect ratio return the expected values). Check out the [unit test example](modules/typed_entity_example/lib/Drupal/typed_entity_example/Tests/TypedEntityExampleUnitTestCase.php). + +## Installation +This module uses unit testing as an example of how you should test your custom business logic. Sometimes your custom +logic contains calls to the drupal api that is not loaded for unit testing. To work around that you can use X Autoload +mock classes. + +This module needs an extra patch to do this, so you will have to patch: + - `xautoload` with: https://www.drupal.org/files/issues/2456877-module-invoke-wrapping-1.patch + - `entity` with: https://www.drupal.org/files/issues/2455851-add-additional-interfaces-1.patch diff --git a/lib/Drupal/typed_entity/Tests/TypedEntityUnitTestCase.php b/lib/Drupal/typed_entity/Tests/TypedEntityUnitTestCase.php index ee44f3a..c2aedf9 100644 --- a/lib/Drupal/typed_entity/Tests/TypedEntityUnitTestCase.php +++ b/lib/Drupal/typed_entity/Tests/TypedEntityUnitTestCase.php @@ -8,7 +8,10 @@ namespace Drupal\typed_entity\Tests; use Drupal\typed_entity\Exception\TypedEntityException; +use Drupal\typed_entity\TypedEntity\Tests\MockEntityDrupalWrapper; +use Drupal\typed_entity\TypedEntity\Tests\MockEntityWrapperService; use Drupal\typed_entity\TypedEntity\TypedEntity; +use Drupal\typed_entity\TypedEntity\TypedEntityManager; class TypedEntityUnitTestCase extends \DrupalUnitTestCase { @@ -43,8 +46,9 @@ public function setUp() { * Test logging message. */ public function testConstructor() { + $dic = xautoload()->getServiceContainer(); try { - new TypedEntity(NULL, 1); + new TypedEntity($dic, NULL, 1); $this->fail('Exception was not thrown for missing entity type.'); } catch (TypedEntityException $e) { @@ -52,7 +56,7 @@ public function testConstructor() { } try { - new TypedEntity('foo'); + new TypedEntity($dic, 'foo'); $this->fail('Exception was not thrown for missing entity and ID.'); } catch (TypedEntityException $e) { @@ -60,4 +64,35 @@ public function testConstructor() { } } + /** + * Test TypedEntityManager. + */ + public function testTypedEntityManager() { + // Test the discovery. + + // When creating the EMW the entity in the fixture will be used regardless + // of the passed in entity. + $wrapper_service = new MockEntityWrapperService(); + $wrapper_service->setFixturePath(__DIR__ . '/fixtures/article.inc'); + xautoload() + ->getServiceContainer() + ->set('entity_wrapper', $wrapper_service); + + // Get the mock entity to be loaded. + $entity = $wrapper_service->wrap('node', NULL)->value(); + $typed_article = TypedEntityManager::create('node', $entity); + $this->assertEqual('node', $typed_article->getEntityType()); + $this->assertEqual('article', $typed_article->getBundle()); + $this->assertEqual($entity, $typed_article->getEntity(), 'Correct entity set'); + $this->assertTrue($typed_article->access('edit')); + $this->assertTrue($typed_article->getWrapper() instanceof MockEntityDrupalWrapper); + + $random_name = $this->randomName(); + $random_value = $this->randomString(); + $typed_article->{$random_name} = $random_value; + $typed_article->save(); + $entity = $typed_article->getEntity(); + $this->assertEqual($entity->{$random_name}, $random_value); + } + } diff --git a/lib/Drupal/typed_entity/Tests/fixtures/article.inc b/lib/Drupal/typed_entity/Tests/fixtures/article.inc new file mode 100644 index 0000000..d6bd811 --- /dev/null +++ b/lib/Drupal/typed_entity/Tests/fixtures/article.inc @@ -0,0 +1,200 @@ + 'article', + 'entity keys' => + array( + 'id' => 'nid', + 'revision' => 'vid', + 'bundle' => 'type', + 'label' => 'title', + 'language' => 'language', + ), + 'entity' => (object) array( + 'vid' => '1', + 'uid' => '1', + 'title' => 'Lorem ipsum dolor sit amet, consetetur sadipscing', + 'log' => '', + 'status' => '1', + 'comment' => '2', + 'promote' => '1', + 'sticky' => '0', + 'nid' => '1', + 'type' => 'article', + 'language' => 'en', + 'created' => '1368005430', + 'changed' => '1369320916', + 'tnid' => '0', + 'translate' => '0', + 'revision_timestamp' => '1369320916', + 'revision_uid' => '1', + 'body' => + array( + 'und' => + array( + 0 => + array( + 'value' => 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.', + 'summary' => '', + 'format' => 'filtered_html', + 'safe_value' => '

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.

+', + 'safe_summary' => '', + ), + ), + ), + 'field_tags' => + array( + 'und' => + array( + 0 => + array( + 'tid' => '1', + ), + ), + ), + 'field_image' => + array( + 'und' => + array( + 0 => + array( + 'fid' => '1', + 'uid' => '1', + 'filename' => 'DSCF2211.jpg', + 'uri' => 'public://field/image/DSCF2211.jpg', + 'filemime' => 'image/jpeg', + 'filesize' => '46156', + 'status' => '1', + 'timestamp' => '1424800819', + 'type' => 'image', + 'field_file_image_alt_text' => + array(), + 'field_file_image_title_text' => + array(), + 'rdf_mapping' => + array(), + 'metadata' => + array( + 'height' => 320, + 'width' => 180, + ), + 'alt' => '', + 'title' => '', + 'width' => '180', + 'height' => '320', + ), + ), + ), + 'field_facebook_pub' => + array( + 'und' => + array( + 0 => + array( + 'target_id' => '3', + ), + ), + ), + 'field_it2' => + array(), + 'rdf_mapping' => + array( + 'field_image' => + array( + 'predicates' => + array( + 0 => 'og:image', + 1 => 'rdfs:seeAlso', + ), + 'type' => 'rel', + ), + 'field_tags' => + array( + 'predicates' => + array( + 0 => 'dc:subject', + ), + 'type' => 'rel', + ), + 'rdftype' => + array( + 0 => 'sioc:Item', + 1 => 'foaf:Document', + ), + 'title' => + array( + 'predicates' => + array( + 0 => 'dc:title', + ), + ), + 'created' => + array( + 'predicates' => + array( + 0 => 'dc:date', + 1 => 'dc:created', + ), + 'datatype' => 'xsd:dateTime', + 'callback' => 'date_iso8601', + ), + 'changed' => + array( + 'predicates' => + array( + 0 => 'dc:modified', + ), + 'datatype' => 'xsd:dateTime', + 'callback' => 'date_iso8601', + ), + 'body' => + array( + 'predicates' => + array( + 0 => 'content:encoded', + ), + ), + 'uid' => + array( + 'predicates' => + array( + 0 => 'sioc:has_creator', + ), + 'type' => 'rel', + ), + 'name' => + array( + 'predicates' => + array( + 0 => 'foaf:name', + ), + ), + 'comment_count' => + array( + 'predicates' => + array( + 0 => 'sioc:num_replies', + ), + 'datatype' => 'xsd:integer', + ), + 'last_activity' => + array( + 'predicates' => + array( + 0 => 'sioc:last_activity_date', + ), + 'datatype' => 'xsd:dateTime', + 'callback' => 'date_iso8601', + ), + ), + 'cid' => '9', + 'last_comment_timestamp' => '1405499171', + 'last_comment_name' => '', + 'last_comment_uid' => '1', + 'comment_count' => '9', + 'name' => 'admin', + 'picture' => '0', + 'data' => 'b:0;', + ), +); diff --git a/modules/typed_entity_example/lib/Drupal/typed_entity_example/Tests/TypedEntityExampleUnitTestCase.php b/modules/typed_entity_example/lib/Drupal/typed_entity_example/Tests/TypedEntityExampleUnitTestCase.php index 4bf47f0..520aefa 100644 --- a/modules/typed_entity_example/lib/Drupal/typed_entity_example/Tests/TypedEntityExampleUnitTestCase.php +++ b/modules/typed_entity_example/lib/Drupal/typed_entity_example/Tests/TypedEntityExampleUnitTestCase.php @@ -7,6 +7,7 @@ namespace Drupal\typed_entity_example\Tests; +use Drupal\typed_entity\TypedEntity\Tests\MockEntityWrapperService; use Drupal\typed_entity\TypedEntity\TypedEntityManager; use Drupal\typed_entity_example\TypedEntity\Tests\TypedNodeArticleUnitTest; @@ -43,7 +44,7 @@ public function setUp() { * Test logging message. */ public function testLoggingMessage() { - $typed_article = new TypedNodeArticleUnitTest('node', 1, NULL, 'article'); + $typed_article = new TypedNodeArticleUnitTest(xautoload()->getServiceContainer(), 'node', 1, NULL, 'article'); $this->assertEqual($typed_article->getLoggingMessage(), 'User with id 1. Node with title Foo. Status 1.', 'Logging message is successful.'); } @@ -56,4 +57,53 @@ public function testCamelize() { $this->assertEqual(TypedEntityManager::camelize('1-a>234'), '1A>234'); $this->assertEqual(TypedEntityManager::camelize(''), ''); } + + /** + * Test factory. + */ + public function testFactory() { + $wrapper_service = new MockEntityWrapperService(); + $wrapper_service->setFixturePath(__DIR__ . '/fixtures/article.inc'); + xautoload() + ->getServiceContainer() + ->set('entity_wrapper', $wrapper_service); + + // Get the mock entity to be loaded. + $entity = $wrapper_service->wrap('node', NULL)->value(); + $typed_article = TypedEntityManager::create('node', $entity); + $reflection_article = new \ReflectionClass($typed_article); + if ($reflection_article->name == 'Drupal\typed_entity_example\TypedEntity\Node\Article') { + $this->pass('The hook_typed_entity_registry_info is taking precedence.'); + } + else { + $this->fail('The hook_typed_entity_registry_info is not taking precedence.'); + } + + $wrapper_service->setFixturePath(__DIR__ . '/fixtures/page.inc'); + // Get the mock entity to be loaded. + $entity = $wrapper_service->wrap('node', NULL)->value(); + $typed_page = TypedEntityManager::create('node', $entity); + + $reflection_page = new \ReflectionClass($typed_page); + if ($reflection_page->name == 'Drupal\typed_entity_example\TypedEntity\TypedNode') { + $this->pass('The factory is falling back to TypedNode.'); + } + else { + $this->fail('The factory is not falling back to TypedNode.'); + } + + // Test the fallback to TypedEntity. + $wrapper_service->setFixturePath(__DIR__ . '/fixtures/user.inc'); + // Get the mock entity to be loaded. + $entity = $wrapper_service->wrap('user', NULL)->value(); + $typed_user = TypedEntityManager::create('user', $entity); + $reflection_user = new \ReflectionClass($typed_user); + if ($reflection_user->name == 'Drupal\typed_entity\TypedEntity\TypedEntity') { + $this->pass('The factory is falling back to TypedEntity.'); + } + else { + $this->fail('The factory is not falling back to TypedEntity.'); + } + } + } diff --git a/modules/typed_entity_example/lib/Drupal/typed_entity_example/Tests/TypedEntityExampleWebTestCase.php b/modules/typed_entity_example/lib/Drupal/typed_entity_example/Tests/TypedEntityExampleWebTestCase.php deleted file mode 100644 index 70390e6..0000000 --- a/modules/typed_entity_example/lib/Drupal/typed_entity_example/Tests/TypedEntityExampleWebTestCase.php +++ /dev/null @@ -1,82 +0,0 @@ - 'Typed entity example (functional)', - 'description' => 'Functional tests for Typed Entity.', - 'group' => 'Typed Entity', - ); - } - - /** - * Set up. - */ - protected function setUp() { - parent::setUp('typed_entity_example'); - } - - /** - * Test factory. - */ - public function testFactory() { - $article = $this->drupalCreateNode(array( - 'type' => 'article', - 'title' => 'Test article', - )); - $typed_article = TypedEntityManager::create('node', $article); - $reflection_article = new \ReflectionClass($typed_article); - if ($reflection_article->name == 'Drupal\typed_entity_example\TypedEntity\Node\Article') { - $this->pass('The hook_typed_entity_registry_info is taking precedence.'); - } - else { - $this->fail('The hook_typed_entity_registry_info is not taking precedence.'); - } - - // Test the fallback to the TypedNode. - $page = $this->drupalCreateNode(array( - 'type' => 'page', - 'title' => 'Test article', - )); - $typed_page = TypedEntityManager::create('node', $page); - - $reflection_page = new \ReflectionClass($typed_page); - if ($reflection_page->name == 'Drupal\typed_entity_example\TypedEntity\TypedNode') { - $this->pass('The factory is falling back to TypedNode.'); - } - else { - $this->fail('The factory is not falling back to TypedNode.'); - } - - // Test the fallback to TypedEntity. - $account = $this->drupalCreateUser(); - $typed_user = TypedEntityManager::create('user', $account); - $reflection_user = new \ReflectionClass($typed_user); - if ($reflection_user->name == 'Drupal\typed_entity\TypedEntity\TypedEntity') { - $this->pass('The factory is falling back to TypedEntity.'); - } - else { - $this->fail('The factory is not falling back to TypedEntity.'); - } - } - -} diff --git a/modules/typed_entity_example/lib/Drupal/typed_entity_example/Tests/fixtures/article.inc b/modules/typed_entity_example/lib/Drupal/typed_entity_example/Tests/fixtures/article.inc new file mode 100644 index 0000000..feddbc4 --- /dev/null +++ b/modules/typed_entity_example/lib/Drupal/typed_entity_example/Tests/fixtures/article.inc @@ -0,0 +1,162 @@ + 'article', + 'entity keys' => + array( + 'id' => 'nid', + 'revision' => 'vid', + 'bundle' => 'type', + 'label' => 'title', + 'language' => 'language', + ), + 'entity' => (object) array( + 'vid' => '1', + 'uid' => '1', + 'title' => 'Lorem ipsum dolor sit amet, consetetur sadipscing', + 'log' => '', + 'status' => '1', + 'comment' => '2', + 'promote' => '1', + 'sticky' => '0', + 'nid' => '1', + 'type' => 'article', + 'language' => 'en', + 'created' => '1368005430', + 'changed' => '1369320916', + 'tnid' => '0', + 'translate' => '0', + 'revision_timestamp' => '1369320916', + 'revision_uid' => '1', + 'body' => array( + 'und' => array( + array( + 'value' => 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.', + 'summary' => '', + 'format' => 'filtered_html', + 'safe_value' => '

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.

+', + 'safe_summary' => '', + ), + ), + ), + 'field_tags' => array( + 'und' => array( + array( + 'tid' => '1', + ), + ), + ), + 'field_image' => array( + 'und' => array( + array( + 'fid' => '1', + 'uid' => '1', + 'filename' => 'DSCF2211.jpg', + 'uri' => 'public://field/image/DSCF2211.jpg', + 'filemime' => 'image/jpeg', + 'filesize' => '46156', + 'status' => '1', + 'timestamp' => '1424800819', + 'type' => 'image', + 'field_file_image_alt_text' => array(), + 'field_file_image_title_text' => array(), + 'rdf_mapping' => array(), + 'metadata' => array( + 'height' => 320, + 'width' => 180, + ), + 'alt' => '', + 'title' => '', + 'width' => '180', + 'height' => '320', + ), + ), + ), + 'field_facebook_pub' => array( + 'und' => array( + array( + 'target_id' => '3', + ), + ), + ), + 'field_it2' => array(), + 'rdf_mapping' => array( + 'field_image' => array( + 'predicates' => array( + 'og:image', + 'rdfs:seeAlso', + ), + 'type' => 'rel', + ), + 'field_tags' => array( + 'predicates' => array( + 'dc:subject', + ), + 'type' => 'rel', + ), + 'rdftype' => array( + 'sioc:Item', + 'foaf:Document', + ), + 'title' => array( + 'predicates' => + array( + 'dc:title', + ), + ), + 'created' => array( + 'predicates' => array( + 'dc:date', + 'dc:created', + ), + 'datatype' => 'xsd:dateTime', + 'callback' => 'date_iso8601', + ), + 'changed' => array( + 'predicates' => array( + 'dc:modified', + ), + 'datatype' => 'xsd:dateTime', + 'callback' => 'date_iso8601', + ), + 'body' => array( + 'predicates' => array( + 'content:encoded', + ), + ), + 'uid' => array( + 'predicates' => array( + 'sioc:has_creator', + ), + 'type' => 'rel', + ), + 'name' => array( + 'predicates' => array( + 'foaf:name', + ), + ), + 'comment_count' => array( + 'predicates' => array( + 'sioc:num_replies', + ), + 'datatype' => 'xsd:integer', + ), + 'last_activity' => array( + 'predicates' => array( + 'sioc:last_activity_date', + ), + 'datatype' => 'xsd:dateTime', + 'callback' => 'date_iso8601', + ), + ), + 'cid' => '9', + 'last_comment_timestamp' => '1405499171', + 'last_comment_name' => '', + 'last_comment_uid' => '1', + 'comment_count' => '9', + 'name' => 'admin', + 'picture' => '0', + 'data' => 'b:0;', + ), +); diff --git a/modules/typed_entity_example/lib/Drupal/typed_entity_example/Tests/fixtures/page.inc b/modules/typed_entity_example/lib/Drupal/typed_entity_example/Tests/fixtures/page.inc new file mode 100644 index 0000000..08dac38 --- /dev/null +++ b/modules/typed_entity_example/lib/Drupal/typed_entity_example/Tests/fixtures/page.inc @@ -0,0 +1,131 @@ + 'page', + 'entity keys' => + array( + 'id' => 'nid', + 'revision' => 'vid', + 'bundle' => 'type', + 'label' => 'title', + 'language' => 'language', + ), + 'entity' => (object) array( + 'vid' => '3', + 'uid' => '1', + 'title' => 'Video embed', + 'log' => '', + 'status' => '1', + 'comment' => '1', + 'promote' => '0', + 'sticky' => '0', + 'nid' => '3', + 'type' => 'page', + 'language' => 'en', + 'created' => '1391502189', + 'changed' => '1391502189', + 'tnid' => '0', + 'translate' => '0', + 'revision_timestamp' => '1391502189', + 'revision_uid' => '1', + 'body' => + array( + 'und' => array( + array( + 'value' => 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.', + 'summary' => '', + 'format' => 'filtered_html', + 'safe_value' => '

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.

+', + 'safe_summary' => '', + ), + ), + ), + 'field_video' => + array( + 'und' => array( + array( + 'video_url' => 'http://www.youtube.com/watch?v=fSAgFxjFSqY', + 'thumbnail_path' => 'public://video_embed_field_thumbnails/youtube/fSAgFxjFSqY.jpg', + 'video_data' => 'a:26:{s:5:"xmlns";s:27:"http://www.w3.org/2005/Atom";s:11:"xmlns$media";s:29:"http://search.yahoo.com/mrss/";s:8:"xmlns$gd";s:32:"http://schemas.google.com/g/2005";s:9:"xmlns$gml";s:26:"http://www.opengis.net/gml";s:8:"xmlns$yt";s:37:"http://gdata.youtube.com/schemas/2007";s:12:"xmlns$georss";s:28:"http://www.georss.org/georss";s:7:"gd$etag";s:28:"W/"D0ANRX47eCp7I2A9Wh9SEkQ."";s:2:"id";s:38:"tag:youtube.com,2008:video:fSAgFxjFSqY";s:9:"published";s:24:"2013-06-18T00:25:08.000Z";s:7:"updated";s:24:"2014-02-01T23:03:14.000Z";s:8:"category";a:2:{i:0;a:2:{s:6:"scheme";s:37:"http://schemas.google.com/g/2005#kind";s:4:"term";s:43:"http://gdata.youtube.com/schemas/2007#video";}i:1;a:3:{s:6:"scheme";s:52:"http://gdata.youtube.com/schemas/2007/categories.cat";s:4:"term";s:9:"Education";s:5:"label";s:9:"Education";}}s:5:"title";s:44:"Frontend Workflows with Grunt and Angular JS";s:7:"content";a:2:{s:4:"type";s:29:"application/x-shockwave-flash";s:3:"src";s:73:"http://www.youtube.com/v/fSAgFxjFSqY?version=3&f=videos&app=youtube_gdata";}s:4:"link";a:5:{i:0;a:3:{s:3:"rel";s:9:"alternate";s:4:"type";s:9:"text/html";s:4:"href";s:64:"http://www.youtube.com/watch?v=fSAgFxjFSqY&feature=youtube_gdata";}i:1;a:3:{s:3:"rel";s:51:"http://gdata.youtube.com/schemas/2007#video.related";s:4:"type";s:20:"application/atom+xml";s:4:"href";s:65:"http://gdata.youtube.com/feeds/api/videos/fSAgFxjFSqY/related?v=2";}i:2;a:3:{s:3:"rel";s:44:"http://gdata.youtube.com/schemas/2007#mobile";s:4:"type";s:9:"text/html";s:4:"href";s:42:"http://m.youtube.com/details?v=fSAgFxjFSqY";}i:3;a:3:{s:3:"rel";s:46:"http://gdata.youtube.com/schemas/2007#uploader";s:4:"type";s:20:"application/atom+xml";s:4:"href";s:67:"http://gdata.youtube.com/feeds/api/users/8TXEl4mrSZ4BVOkOJdhXQA?v=2";}i:4;a:3:{s:3:"rel";s:4:"self";s:4:"type";s:20:"application/atom+xml";s:4:"href";s:57:"http://gdata.youtube.com/feeds/api/videos/fSAgFxjFSqY?v=2";}}s:6:"author";a:1:{i:0;a:3:{s:4:"name";s:12:"David Mosher";s:3:"uri";s:52:"http://gdata.youtube.com/feeds/api/users/vidjadavemo";s:9:"yt$userId";s:22:"8TXEl4mrSZ4BVOkOJdhXQA";}}s:16:"yt$accessControl";a:8:{i:0;a:2:{s:6:"action";s:7:"comment";s:10:"permission";s:7:"allowed";}i:1;a:2:{s:6:"action";s:11:"commentVote";s:10:"permission";s:7:"allowed";}i:2;a:2:{s:6:"action";s:12:"videoRespond";s:10:"permission";s:9:"moderated";}i:3;a:2:{s:6:"action";s:4:"rate";s:10:"permission";s:7:"allowed";}i:4;a:2:{s:6:"action";s:5:"embed";s:10:"permission";s:7:"allowed";}i:5;a:2:{s:6:"action";s:4:"list";s:10:"permission";s:7:"allowed";}i:6;a:2:{s:6:"action";s:8:"autoPlay";s:10:"permission";s:7:"allowed";}i:7;a:2:{s:6:"action";s:9:"syndicate";s:10:"permission";s:7:"allowed";}}s:11:"gd$comments";a:1:{s:11:"gd$feedLink";a:3:{s:3:"rel";s:46:"http://gdata.youtube.com/schemas/2007#comments";s:4:"href";s:66:"http://gdata.youtube.com/feeds/api/videos/fSAgFxjFSqY/comments?v=2";s:9:"countHint";i:25;}}s:12:"georss$where";a:1:{s:9:"gml$Point";a:1:{s:7:"gml$pos";s:19:"52.13437 -106.64766";}}s:5:"yt$hd";a:0:{}s:11:"media$group";a:14:{s:14:"media$category";a:1:{i:0;s:9:"Education";}s:13:"media$content";a:3:{i:0;a:7:{s:3:"url";s:73:"http://www.youtube.com/v/fSAgFxjFSqY?version=3&f=videos&app=youtube_gdata";s:4:"type";s:29:"application/x-shockwave-flash";s:6:"medium";s:5:"video";s:9:"isDefault";s:4:"true";s:10:"expression";s:4:"full";s:8:"duration";i:3757;s:9:"yt$format";i:5;}i:1;a:6:{s:3:"url";s:102:"rtsp://r4---sn-cg07luel.c.youtube.com/CiILENy73wIaGQmmSsUYFyAgfRMYDSANFEgGUgZ2aWRlb3MM/0/0/0/video.3gp";s:4:"type";s:10:"video/3gpp";s:6:"medium";s:5:"video";s:10:"expression";s:4:"full";s:8:"duration";i:3757;s:9:"yt$format";i:1;}i:2;a:6:{s:3:"url";s:102:"rtsp://r4---sn-cg07luel.c.youtube.com/CiILENy73wIaGQmmSsUYFyAgfRMYESARFEgGUgZ2aWRlb3MM/0/0/0/video.3gp";s:4:"type";s:10:"video/3gpp";s:6:"medium";s:5:"video";s:10:"expression";s:4:"full";s:8:"duration";i:3757;s:9:"yt$format";i:6;}}s:12:"media$credit";a:1:{i:0;s:11:"vidjadavemo";}s:17:"media$description";s:675:"A screencast that shows front-end developers how they can craft workflows with Grunt JS, along with some specific workflow improvements when working with Angular JS. + +This is part 4 of a screencast series: + +Part 1: "Intro to Angular JS" http://www.youtube.com/watch?v=8ILQOFAgaXE +Part 2: "End to End with Angular JS" http://www.youtube.com/watch?v=hqAyiqUs93c +Part 3: "Security with Angular JS" http://www.youtube.com/watch?v=18ifoT-Id54 +Part 5: "Testing Strategies for Angular JS" http://www.youtube.com/watch?v=UYVcY9EJcRs + +Resources: + +Github Source: https://github.com/davemo/frontend-workflows-with-grunt-and-angularjs +Resource Bundle: http://bitly.com/bundles/dmosher/7";s:14:"media$keywords";a:0:{}s:13:"media$license";s:2:"cc";s:12:"media$player";a:1:{s:3:"url";s:71:"http://www.youtube.com/watch?v=fSAgFxjFSqY&feature=youtube_gdata_player";}s:15:"media$thumbnail";a:7:{i:0;a:5:{s:3:"url";s:46:"http://i1.ytimg.com/vi/fSAgFxjFSqY/default.jpg";s:6:"height";i:90;s:5:"width";i:120;s:4:"time";s:12:"00:31:18.500";s:7:"yt$name";s:7:"default";}i:1;a:4:{s:3:"url";s:48:"http://i1.ytimg.com/vi/fSAgFxjFSqY/mqdefault.jpg";s:6:"height";i:180;s:5:"width";i:320;s:7:"yt$name";s:9:"mqdefault";}i:2;a:4:{s:3:"url";s:48:"http://i1.ytimg.com/vi/fSAgFxjFSqY/hqdefault.jpg";s:6:"height";i:360;s:5:"width";i:480;s:7:"yt$name";s:9:"hqdefault";}i:3;a:4:{s:3:"url";s:48:"http://i1.ytimg.com/vi/fSAgFxjFSqY/sddefault.jpg";s:6:"height";i:480;s:5:"width";i:640;s:7:"yt$name";s:9:"sddefault";}i:4;a:5:{s:3:"url";s:40:"http://i1.ytimg.com/vi/fSAgFxjFSqY/1.jpg";s:6:"height";i:90;s:5:"width";i:120;s:4:"time";s:12:"00:15:39.250";s:7:"yt$name";s:5:"start";}i:5;a:5:{s:3:"url";s:40:"http://i1.ytimg.com/vi/fSAgFxjFSqY/2.jpg";s:6:"height";i:90;s:5:"width";i:120;s:4:"time";s:12:"00:31:18.500";s:7:"yt$name";s:6:"middle";}i:6;a:5:{s:3:"url";s:40:"http://i1.ytimg.com/vi/fSAgFxjFSqY/3.jpg";s:6:"height";i:90;s:5:"width";i:120;s:4:"time";s:12:"00:46:57.750";s:7:"yt$name";s:3:"end";}}s:11:"media$title";s:44:"Frontend Workflows with Grunt and Angular JS";s:14:"yt$aspectRatio";s:10:"widescreen";s:11:"yt$duration";a:1:{s:7:"seconds";s:4:"3757";}s:11:"yt$uploaded";s:24:"2013-06-18T00:25:08.000Z";s:13:"yt$uploaderId";s:24:"UC8TXEl4mrSZ4BVOkOJdhXQA";s:10:"yt$videoid";s:11:"fSAgFxjFSqY";}s:9:"gd$rating";a:5:{s:7:"average";d:5;s:3:"max";i:5;s:3:"min";i:1;s:9:"numRaters";i:143;s:3:"rel";s:40:"http://schemas.google.com/g/2005#overall";}s:11:"yt$recorded";s:10:"2013-06-17";s:13:"yt$statistics";a:2:{s:13:"favoriteCount";s:1:"0";s:9:"viewCount";s:5:"13967";}s:9:"yt$rating";a:2:{s:11:"numDislikes";s:1:"0";s:8:"numLikes";s:3:"143";}s:5:"terms";a:1:{i:0;s:9:"Education";}s:7:"handler";s:7:"youtube";}', + 'embed_code' => NULL, + 'description' => 'sed diam nonumy', + ), + ), + ), + 'rdf_mapping' => array( + 'rdftype' => array( + 'foaf:Document', + ), + 'title' => array( + 'predicates' => array( + 'dc:title', + ), + ), + 'created' => array( + 'predicates' => array( + 'dc:date', + 1 => 'dc:created', + ), + 'datatype' => 'xsd:dateTime', + 'callback' => 'date_iso8601', + ), + 'changed' => array( + 'predicates' => array( + 'dc:modified', + ), + 'datatype' => 'xsd:dateTime', + 'callback' => 'date_iso8601', + ), + 'body' => array( + 'predicates' => array( + 'content:encoded', + ), + ), + 'uid' => array( + 'predicates' => array( + 'sioc:has_creator', + ), + 'type' => 'rel', + ), + 'name' => array( + 'predicates' => array( + 'foaf:name', + ), + ), + 'comment_count' => array( + 'predicates' => array( + 'sioc:num_replies', + ), + 'datatype' => 'xsd:integer', + ), + 'last_activity' => array( + 'predicates' => array( + 'sioc:last_activity_date', + ), + 'datatype' => 'xsd:dateTime', + 'callback' => 'date_iso8601', + ), + ), + 'cid' => '0', + 'last_comment_timestamp' => '1391502189', + 'last_comment_name' => NULL, + 'last_comment_uid' => '1', + 'comment_count' => '0', + 'name' => 'admin', + 'picture' => '0', + 'data' => 'b:0;', + ), +); diff --git a/modules/typed_entity_example/lib/Drupal/typed_entity_example/Tests/fixtures/user.inc b/modules/typed_entity_example/lib/Drupal/typed_entity_example/Tests/fixtures/user.inc new file mode 100644 index 0000000..322acde --- /dev/null +++ b/modules/typed_entity_example/lib/Drupal/typed_entity_example/Tests/fixtures/user.inc @@ -0,0 +1,48 @@ + 'user', + 'entity keys' => array( + 'id' => 'uid', + 'revision' => '', + 'bundle' => '', + ), + 'entity' => (object) array( + 'uid' => '1', + 'name' => 'admin', + 'pass' => '$S$DKHuKBpoLMv8gFfAhD8krXvxRQUt3WbFkS7L3S72rXArVs2sEDDp', + 'mail' => 'admin@example.org', + 'theme' => '', + 'signature' => '', + 'signature_format' => 'filtered_html', + 'created' => '1367961694', + 'access' => '1427100351', + 'login' => '1426940306', + 'status' => '1', + 'timezone' => 'Europe/Berlin', + 'language' => '', + 'picture' => NULL, + 'init' => 'admin@example.org', + 'data' => FALSE, + 'roles' => array( + 2 => 'authenticated user', + 3 => 'administrator', + ), + 'rdf_mapping' => array( + 'rdftype' => array( + 'sioc:UserAccount', + ), + 'name' => array( + 'predicates' => array( + 'foaf:name', + ), + ), + 'homepage' => array( + 'predicates' => array( + 'foaf:page', + ), + 'type' => 'rel', + ), + ), + ), +); diff --git a/src/Entity/EntityWrapperService.php b/src/Entity/EntityWrapperService.php new file mode 100644 index 0000000..9e280b9 --- /dev/null +++ b/src/Entity/EntityWrapperService.php @@ -0,0 +1,19 @@ +entityType = $type; + // When using this class for unit testing, set the fixture class in the + // service container. + /** @var MockEntityWrapperServiceInterface $mock_service */ + $mock_service = xautoload() + ->getServiceContainer() + ->get('entity_wrapper'); + $this->initFixture($mock_service->getFixture()); + } + + + /** + * Generates a fixture for easier mocking. + * + * This function needs to be run in a context with drupal bootstrap. + * + * @param string $entity_type + * The entity type. + * @param mixed $entity + * Either a loaded entity or its ID. + * + * @return string + * The serialized fixture array. + */ + public static function generateFixture($entity_type, $entity) { + $wrapper = new \EntityDrupalWrapper($entity_type, $entity); + $entity_info = entity_get_info($wrapper->type()); + $fixture = array( + 'bundle' => $wrapper->getBundle(), + 'entity keys' => $entity_info['entity keys'], + 'entity' => $wrapper->value(), + ); + + return var_export($fixture, TRUE); + } + + /** + * {@inheritdoc} + */ + public function info() { + return array( + 'langcode' => $this->entity->{$this->entityKeys['language']}, + 'type' => $this->entityType, + 'property defaults' => array(), + ); + } + + /** + * {@inheritdoc} + */ + public function type() { + return $this->entityType; + } + + /** + * {@inheritdoc} + */ + public function value(array $options = array()) { + return $this->entity; + } + + /** + * {@inheritdoc} + */ + public function raw() { + return $this->value(); + } + + /** + * {@inheritdoc} + */ + public function set($value) { + $this->entity = $value; + } + + /** + * {@inheritdoc} + */ + public function validate($value) { + return TRUE; + } + + /** + * {@inheritdoc} + */ + public function optionsList($op = 'edit') { + FALSE; + } + + /** + * {@inheritdoc} + */ + public function label() { + return 'Label'; + } + + /** + * {@inheritdoc} + */ + public function access($op, $account = NULL) { + return TRUE; + } + + /** + * {@inheritdoc} + */ + public function getPropertyInfo($name = NULL) { + return array(); + } + + /** + * {@inheritdoc} + */ + public function &refPropertyInfo() { + return $this->getPropertyInfo(); + } + + /** + * {@inheritdoc} + */ + public function language($langcode = LANGUAGE_NONE) {} + + /** + * {@inheritdoc} + */ + public function getPropertyLanguage() { + return (object) array('language' => LANGUAGE_NONE); + } + + /** + * {@inheritdoc} + */ + public function get($name) { + return new MockEntityDrupalWrapper(NULL, NULL, $this->entity->{$name}); + } + + /** + * {@inheritdoc} + */ + public function getIterator() { + return array(); + } + + /** + * {@inheritdoc} + */ + public function getIdentifier() { + return $this->entity->{$this->entityKeys['id']}; + } + + /** + * {@inheritdoc} + */ + public function getBundle() { + return $this->bundle; + } + + /** + * {@inheritdoc} + */ + public function view($view_mode = 'full', $langcode = NULL, $page = NULL) { + return array(); + } + + /** + * {@inheritdoc} + */ + public function entityAccess($op, $account = NULL) { + return TRUE; + } + + /** + * {@inheritdoc} + */ + public function save() {} + + /** + * {@inheritdoc} + */ + public function delete() {} + + /** + * {@inheritdoc} + */ + public function entityInfo() { + return array(); + } + + /** + * {@inheritdoc} + */ + public function entityKey($name) { + return $this->entityKeys[$name]; + } + + /** + * Sub wrappers. + * + * @param $name + * The name of the requested property. + * + * @return \EntityMetadataWrapperInterface + * The wrapper. + */ + public function __get($name) { + return $this->get($name); + } + + /** + * Takes a fixture and initializes the class properties. + * + * @param array $fixture + */ + protected function initFixture(array $fixture) { + $this->entityKeys = $fixture['entity keys']; + $this->bundle = $fixture['bundle']; + $this->entity = $fixture['entity']; + } + +} diff --git a/src/TypedEntity/Tests/MockEntityWrapperService.php b/src/TypedEntity/Tests/MockEntityWrapperService.php new file mode 100644 index 0000000..2c661a7 --- /dev/null +++ b/src/TypedEntity/Tests/MockEntityWrapperService.php @@ -0,0 +1,79 @@ +fixture) { + return $this->fixture; + } + $this->fixture = $this->loadFixture($this->fixturePath); + return $this->fixture; + } + + /** + * {@inheritdoc} + */ + public function setFixturePath($fixturePath) { + $this->fixturePath = $fixturePath; + $this->fixture = NULL; + } + + /** + * Load a fixture from a file with a serialized entity. + * + * @param string $fixture_path + * The path to a file containing a serialized fixture. + * + * @return array + * The loaded fixture. + * + * @throws TypedEntityException + */ + protected function loadFixture($fixture_path) { + $fixture = NULL; + if (!file_exists($fixture_path)) { + throw new TypedEntityException('The provided fixture file does not exist.'); + } + + require $fixture_path; + + if (empty($fixture) || !is_array($fixture)) { + throw new TypedEntityException('The contents of the fixture is not valid.'); + } + return $fixture; + } + +} diff --git a/src/TypedEntity/Tests/MockEntityWrapperServiceInterface.php b/src/TypedEntity/Tests/MockEntityWrapperServiceInterface.php new file mode 100644 index 0000000..1e37723 --- /dev/null +++ b/src/TypedEntity/Tests/MockEntityWrapperServiceInterface.php @@ -0,0 +1,29 @@ +dic = $dic; $this->entityType = $entity_type; $this->entityId = $entity_id; $this->entity = $entity; @@ -85,9 +96,9 @@ public function getEntityId() { // This means that somehow we do not have neither entity nor entity ID. throw new TypedEntityException('You need to provide the fully loaded entity or the entity ID.'); } - list($entity_id, , $bundle) = entity_extract_ids($this->getEntityType(), $this->entity); - $this->entityId = $entity_id; - $this->bundle = $bundle; + $this->entityId = $this + ->getWrapper() + ->getIdentifier(); return $this->entityId; } @@ -104,8 +115,12 @@ public function getEntity() { // We do not have neither entity nor ID. We cannot load. return NULL; } - $entities = entity_load($this->getEntityType(), array($this->getEntityId())); - $this->entity = isset($entities[$this->getEntityId()]) ? $entities[$this->getEntityId()] : NULL; + + $this->entity = $this + ->dic + ->get('entity_wrapper') + ->wrap($this->getEntityType(), $entity_id) + ->value(); return $this->entity; } @@ -124,9 +139,9 @@ public function getBundle() { return $this->bundle; } - list($entity_id, , $bundle) = entity_extract_ids($this->getEntityType(), $this->getEntity()); - $this->entityId = $entity_id; - $this->bundle = $bundle; + $this->bundle = $this + ->getWrapper() + ->getBundle(); return $this->bundle; } @@ -137,7 +152,10 @@ public function getWrapper() { if (isset($this->wrapper)) { return $this->wrapper; } - $this->wrapper = entity_metadata_wrapper($this->getEntityType(), $this->getEntity()); + $this->wrapper = $this + ->dic + ->get('entity_wrapper') + ->wrap($this->getEntityType(), $this->getEntity()); return $this->wrapper; } diff --git a/src/TypedEntity/TypedEntityManager.php b/src/TypedEntity/TypedEntityManager.php index 93b1987..99d7db8 100644 --- a/src/TypedEntity/TypedEntityManager.php +++ b/src/TypedEntity/TypedEntityManager.php @@ -7,14 +7,44 @@ namespace Drupal\typed_entity\TypedEntity; +use Drupal\xautoload\DIC\ServiceContainer; +use Drupal\xautoload\DrupalSystem\DrupalSystemInterface; + class TypedEntityManager implements TypedEntityManagerInterface { + /** + * Drupal system wrapper. + * + * @var DrupalSystemInterface + */ + protected static $system; + + /** + * Drupal system wrapper. + * + * @var ServiceContainer + */ + protected static $dic; + + /** + * Constructor. + * + * Declare a private constructor to make sure this class is never + * instantiated. All method and properties here must be static. + */ + private function __construct() {} + /** * {@inheritdoc} */ - public static function create($entity_type, $entity) { + public static function create($entity_type, $entity, ServiceContainer $dic = NULL) { + if (!isset($dic)) { + $dic = xautoload()->getServiceContainer(); + } + static::$dic = $dic; + static::$system = $dic->get('system'); $class_name = static::getClass($entity_type, $entity); - return new $class_name($entity_type, NULL, $entity); + return new $class_name($dic, $entity_type, NULL, $entity); } /** @@ -30,7 +60,11 @@ public static function create($entity_type, $entity) { */ public static function getClass($entity_type, $entity) { $classes = &drupal_static(__METHOD__); - list(,, $bundle) = entity_extract_ids($entity_type, $entity); + /** @var \EntityDrupalWrapperInterface $wrapper */ + $wrapper = static::$dic + ->get('entity_wrapper') + ->wrap($entity_type, $entity); + $bundle = $wrapper->getBundle(); $cid = $entity_type . ':' . $bundle; if (isset($classes[$cid])) { @@ -38,7 +72,7 @@ public static function getClass($entity_type, $entity) { } $cached_classes = array(); - if ($cache = cache_get('typed_entity_classes', 'cache_bootstrap')) { + if ($cache = static::$system->cacheGet('typed_entity_classes', 'cache_bootstrap')) { $cached_classes = $cache->data; } @@ -57,7 +91,7 @@ public static function getClass($entity_type, $entity) { break; } } - cache_set('typed_entity_classes', $classes, 'cache_bootstrap'); + static::$system->cacheSet('typed_entity_classes', $classes, 'cache_bootstrap'); return $classes[$cid]; } @@ -79,7 +113,7 @@ public static function getClass($entity_type, $entity) { * An array of class name candidates. */ protected static function getClassNameCandidates($entity_type, $bundle = NULL) { - $candidates = module_invoke_all('typed_entity_registry_info'); + $candidates = static::$system->moduleInvokeAll('typed_entity_registry_info'); $candidate_entity_type = $candidate_bundle = ''; foreach ($candidates as $candidate) { if ($candidate['entity_type'] != $entity_type) { @@ -122,7 +156,7 @@ protected static function getClassNameCandidates($entity_type, $bundle = NULL) { protected static function getClassNameCandidatesEntity($entity_type) { $names = array(); $class_name_entity_type = 'Typed' . static::camelize($entity_type); - foreach (module_list() as $module_name) { + foreach (static::$system->moduleList() as $module_name) { $names[] = '\\Drupal\\' . $module_name . '\\TypedEntity\\' . $class_name_entity_type; } @@ -147,7 +181,7 @@ protected static function getClassNameCandidatesBundle($entity_type, $bundle) { return $names; } $class_name_bundle = 'Typed' . static::camelize($entity_type) . static::camelize($bundle); - foreach (module_list() as $module_name) { + foreach (static::$system->moduleList() as $module_name) { $names[] = '\\Drupal\\' . $module_name . '\\TypedEntity\\' . $class_name_bundle; } diff --git a/typed_entity.module b/typed_entity.module index 478ba2a..09f6e35 100644 --- a/typed_entity.module +++ b/typed_entity.module @@ -4,3 +4,14 @@ * @file * Module implementation file. */ + +use Drupal\typed_entity\Entity\EntityWrapperService; + +/** + * Implements hook_xautoload(). + */ +function typed_entity_xautoload($adapter) { + xautoload() + ->getServiceContainer() + ->set('entity_wrapper', new EntityWrapperService()); +}