diff --git a/CHANGELOG.md b/CHANGELOG.md index d54ca18..871a6bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ Changelog ========= +2.0.0 (unreleased) +------------------ + +* **2016-05-05**: REST write and delete support enabled + 1.3.0 ----- diff --git a/Form/Type/StaticContent.php b/Form/Type/StaticContent.php new file mode 100644 index 0000000..609d345 --- /dev/null +++ b/Form/Type/StaticContent.php @@ -0,0 +1,24 @@ + + */ +class StaticContent extends AbstractResourceType +{ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder->add('title', TextType::class); + $builder->add('body', TextType::class); + } + + public function getName() + { + return 'cmf_static_content'; + } +} diff --git a/Model/StaticContent.php b/Model/StaticContent.php index 4dc7573..a17e72c 100644 --- a/Model/StaticContent.php +++ b/Model/StaticContent.php @@ -14,6 +14,7 @@ use Doctrine\Common\Collections\ArrayCollection; use Knp\Menu\NodeInterface; use Sonata\BlockBundle\Model\BlockInterface; +use Sylius\Component\Resource\Model\ResourceInterface; use Symfony\Cmf\Bundle\CoreBundle\Translatable\TranslatableInterface; use Symfony\Cmf\Component\Routing\RouteObjectInterface; use Symfony\Cmf\Component\Routing\RouteReferrersInterface; @@ -42,7 +43,8 @@ class StaticContent extends StaticContentBase implements RouteReferrersInterface, PublishTimePeriodInterface, PublishableInterface, - TranslatableInterface + TranslatableInterface, + ResourceInterface { /** * @var bool whether this content is publishable @@ -308,4 +310,51 @@ public function getMenuNodes() { return $this->menuNodes; } + + /** + * Returns a string representation of the Resource. + * + * This method is necessary to allow for resource de-duplication, for example by means + * of array_unique(). The string returned need not have a particular meaning, but has + * to be identical for different ResourceInterface instances referring to the same + * resource; and it should be unlikely to collide with that of other, unrelated + * resource instances. + * + * @return string A string representation unique to the underlying Resource + */ + public function __toString() + { + return $this->getTitle(); + } + + /** + * Returns true if the resource has not been updated since the given timestamp. + * + * @param int $timestamp The last time the resource was loaded + * + * @return bool True if the resource has not been updated, false otherwise + * + * @deprecated since 2.8, to be removed in 3.0. If your resource can check itself for + * freshness implement the SelfCheckingResourceInterface instead. + */ + public function isFresh($timestamp) + { + return true; + } + + /** + * Returns the tied resource. + * + * @return mixed The resource + * + * @deprecated since 2.8, to be removed in 3.0. As there are many different kinds of resource, + * a single getResource() method does not make sense at the interface level. You + * can still call getResource() on implementing classes, probably after performing + * a type check. If you know the concrete type of Resource at hand, the return value + * of this method may make sense to you. + */ + public function getResource() + { + return $this; + } } diff --git a/Resources/config/serializer/cmf/Model.StaticContent.yml b/Resources/config/serializer/cmf/Model.StaticContent.yml new file mode 100644 index 0000000..a4c321d --- /dev/null +++ b/Resources/config/serializer/cmf/Model.StaticContent.yml @@ -0,0 +1,2 @@ +Symfony\Cmf\Bundle\ContentBundle\Model\StaticContent: + exclusion_policy: ALL diff --git a/Resources/views/StaticContent/index.html b/Resources/views/StaticContent/index.html new file mode 100644 index 0000000..16c51c1 --- /dev/null +++ b/Resources/views/StaticContent/index.html @@ -0,0 +1 @@ +INDEX diff --git a/Tests/Resources/DataFixtures/Phpcr/LoadContentData.php b/Tests/Resources/DataFixtures/Phpcr/LoadContentData.php index ace82b8..32fa943 100644 --- a/Tests/Resources/DataFixtures/Phpcr/LoadContentData.php +++ b/Tests/Resources/DataFixtures/Phpcr/LoadContentData.php @@ -16,6 +16,7 @@ use Doctrine\ODM\PHPCR\Document\Generic; use PHPCR\Util\NodeHelper; use Symfony\Cmf\Bundle\ContentBundle\Doctrine\Phpcr\StaticContent; +use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route; class LoadContentData implements FixtureInterface { @@ -29,6 +30,11 @@ public function load(ObjectManager $manager) $contentRoot->setParent($root); $manager->persist($contentRoot); + $routeRoot = new Generic(); + $routeRoot->setNodename('routes'); + $routeRoot->setParent($root); + $manager->persist($routeRoot); + $content = new StaticContent(); $content->setName('content-1'); $content->setTitle('Content 1'); @@ -36,6 +42,12 @@ public function load(ObjectManager $manager) $content->setParentDocument($contentRoot); $manager->persist($content); + $route = new Route(); + $route->setContent($content); + $route->setParentDocument($routeRoot); + $route->setName('content-1'); + $manager->persist($route); + $content = new StaticContent(); $content->setName('content-2'); $content->setTitle('Content 2'); @@ -43,6 +55,21 @@ public function load(ObjectManager $manager) $content->setParentDocument($contentRoot); $manager->persist($content); + $collection = new StaticContent(); + $collection->setName('collection'); + $collection->setTitle('Collection'); + $collection->setBody('Body of Collection'); + $collection->setParentDocument($contentRoot); + $manager->persist($collection); + + $collectionRoute = new Route(); + $collectionRoute->setContent($collection); + $collectionRoute->setParentDocument($routeRoot); + $collectionRoute->setName('collection'); + $manager->persist($collectionRoute); + + + $manager->flush(); } } diff --git a/Tests/Resources/Fixtures/json/post.json b/Tests/Resources/Fixtures/json/post.json new file mode 100644 index 0000000..38f5707 --- /dev/null +++ b/Tests/Resources/Fixtures/json/post.json @@ -0,0 +1,4 @@ +{ + "title": "My new title", + "body": "My new body" +} diff --git a/Tests/Resources/Fixtures/json/put.json b/Tests/Resources/Fixtures/json/put.json new file mode 100644 index 0000000..38f5707 --- /dev/null +++ b/Tests/Resources/Fixtures/json/put.json @@ -0,0 +1,4 @@ +{ + "title": "My new title", + "body": "My new body" +} diff --git a/Tests/Resources/app/AppKernel.php b/Tests/Resources/app/AppKernel.php index f231a03..4858d36 100644 --- a/Tests/Resources/app/AppKernel.php +++ b/Tests/Resources/app/AppKernel.php @@ -27,6 +27,12 @@ public function configure() new \Symfony\Cmf\Bundle\RoutingBundle\CmfRoutingBundle(), new \Symfony\Cmf\Bundle\MenuBundle\CmfMenuBundle(), new \Symfony\Cmf\Bundle\CoreBundle\CmfCoreBundle(), + new FOS\RestBundle\FOSRestBundle(), + new JMS\SerializerBundle\JMSSerializerBundle($this), + new Sylius\Bundle\ResourceBundle\SyliusResourceBundle(), + new WhiteOctober\PagerfantaBundle\WhiteOctoberPagerfantaBundle(), + new Bazinga\Bundle\HateoasBundle\BazingaHateoasBundle(), + new \Symfony\Cmf\Bundle\RestBundle\CmfRestBundle(), )); } diff --git a/Tests/Resources/app/Resources/views/StaticContent/create.html.twig b/Tests/Resources/app/Resources/views/StaticContent/create.html.twig new file mode 100644 index 0000000..40c6d46 --- /dev/null +++ b/Tests/Resources/app/Resources/views/StaticContent/create.html.twig @@ -0,0 +1 @@ +CREATE diff --git a/Tests/Resources/app/Resources/views/StaticContent/index.html.twig b/Tests/Resources/app/Resources/views/StaticContent/index.html.twig new file mode 100644 index 0000000..16c51c1 --- /dev/null +++ b/Tests/Resources/app/Resources/views/StaticContent/index.html.twig @@ -0,0 +1 @@ +INDEX diff --git a/Tests/Resources/app/Resources/views/StaticContent/update.html.twig b/Tests/Resources/app/Resources/views/StaticContent/update.html.twig new file mode 100644 index 0000000..9f4f846 --- /dev/null +++ b/Tests/Resources/app/Resources/views/StaticContent/update.html.twig @@ -0,0 +1 @@ +UPDATE diff --git a/Tests/Resources/app/config/cmf_content.yml b/Tests/Resources/app/config/cmf_content.yml index d97cbc7..d0da6ab 100644 --- a/Tests/Resources/app/config/cmf_content.yml +++ b/Tests/Resources/app/config/cmf_content.yml @@ -3,14 +3,40 @@ cmf_core: locales: ['en', 'de', 'fr'] cmf_routing: + chain: + routers_by_id: + cmf_routing.dynamic_router: 20 + router.default: 100 dynamic: enabled: true persistence: phpcr: enabled: true + route_basepaths: /test/routes + controllers_by_class: + Symfony\Cmf\Bundle\ContentBundle\Doctrine\Phpcr\StaticContent: cmf_content.rest_controller:getAction cmf_content: persistence: phpcr: enabled: true content_basepath: /test/contents + +cmf_rest: + dynamic: + enabled: true + crud_controller_by_method: cmf.controller.static_content + +sylius_resource: + resources: + cmf.static_content: + driver: doctrine/phpcr-odm + templates: ":StaticContent" + classes: + model: Symfony\Cmf\Bundle\ContentBundle\Doctrine\Phpcr\StaticContent + form: + default: Symfony\Cmf\Bundle\ContentBundle\Form\Type\StaticContent + +fos_rest: + format_listener: + enabled: true diff --git a/Tests/Resources/app/config/routing.php b/Tests/Resources/app/config/routing.php index b7c2dba..6eb06b7 100644 --- a/Tests/Resources/app/config/routing.php +++ b/Tests/Resources/app/config/routing.php @@ -15,8 +15,9 @@ $collection->addCollection( $loader->import(CMF_TEST_CONFIG_DIR.'/routing/sonata_routing.yml') ); -// $collection->addCollection( -// $loader->import(__DIR__.'/routing/my_test_routing.yml') -// ); + +$collection->addCollection( + $loader->import(__DIR__.'/routing.yml') +); return $collection; diff --git a/Tests/Resources/app/config/routing.yml b/Tests/Resources/app/config/routing.yml new file mode 100644 index 0000000..fb4084c --- /dev/null +++ b/Tests/Resources/app/config/routing.yml @@ -0,0 +1,4 @@ +cmf_static_content_index: + path: "/collection" + defaults: {_controller: "cmf.controller.static_content:indexAction" } + diff --git a/Tests/WebTest/Controller/RESTContentControllerTest.php b/Tests/WebTest/Controller/RESTContentControllerTest.php new file mode 100644 index 0000000..38e7e6e --- /dev/null +++ b/Tests/WebTest/Controller/RESTContentControllerTest.php @@ -0,0 +1,77 @@ + + */ +class RESTContentControllerTest extends BaseTestCase +{ + public function setUp() + { + $this->db('PHPCR')->loadFixtures(array( + 'Symfony\Cmf\Bundle\ContentBundle\Tests\Resources\DataFixtures\Phpcr\LoadContentData', + )); + $this->client = $this->createClient(); + } + + public function testGET() + { + $this->client->request('GET', '/content-1', array(), array(), array('ACCEPT'=> 'application/json')); + $res = $this->client->getResponse(); + $this->assertEquals(200, $res->getStatusCode()); + } + + public function testPUT() + { + $this->client->request( + 'PUT', + '/content-1', + array(), + array(), + array('ACCEPT'=> 'application/json', 'CONTENT_TYPE' => 'application/json'), + file_get_contents(__DIR__ . '/../../Resources/Fixtures/json/put.json') + ); + $res = $this->client->getResponse(); + $this->assertEquals(Response::HTTP_OK, $res->getStatusCode()); + } + + public function testDELETE() + { + $this->client->request( + 'DELETE', + '/content-1', + array(), + array(), + array('ACCEPT'=> 'application/json') + ); + $res = $this->client->getResponse(); + $this->assertEquals(Response::HTTP_FOUND, $res->getStatusCode()); + } + + public function testPOST() + { + $this->client->request( + 'POST', + '/collection', + array(), + array(), + array('ACCEPT'=> 'application/json', 'CONTENT_TYPE' => 'application/json'), + file_get_contents(__DIR__ . '/../../Resources/Fixtures/json/post.json') + ); + $res = $this->client->getResponse(); + $this->assertEquals(Response::HTTP_OK, $res->getStatusCode()); + } +} diff --git a/composer.json b/composer.json index b856feb..e11f791 100644 --- a/composer.json +++ b/composer.json @@ -11,17 +11,34 @@ "homepage": "https://github.com/symfony-cmf/ContentBundle/contributors" } ], + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/ElectricMaxxx/RestBundle.git" + }, + { + "type": "path", + "url": "https://github.com/dantleech/Sylius/tree/phpcrodm_form_builder/src/Sylius/Bundle/ResourceBundle", + "options": { + "symlink": false + } + } + ], + "minimum-stability": "dev", "require": { "php": "^5.3.9|^7.0", "symfony/framework-bundle": "^2.3|3.*", "symfony-cmf/core-bundle": "^1.1", "symfony-cmf/menu-bundle": "^1.1|2.*", - "symfony-cmf/routing-bundle": "^1.2" + "symfony-cmf/routing-bundle": "^1.2", + "sylius/resource-bundle": "^0.18", + "doctrine/orm": "^2.4.8,<2.5" }, "require-dev": { "symfony-cmf/testing": "^1.3", "sonata-project/doctrine-phpcr-admin-bundle": "^1.1", - "symfony/monolog-bundle": "^2.3" + "symfony/monolog-bundle": "^2.3", + "electricmaxxx/rest-bundle":"dev-master" }, "suggest": { "friendsofsymfony/rest-bundle": "Improved handling for different output formats", @@ -39,5 +56,8 @@ "branch-alias": { "dev-master": "2.0-dev" } + }, + "scripts": { + "post:update":"rm -rf vendor/sylius/resource-bundle/" } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index bbdb251..681debb 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -7,6 +7,7 @@ ./Tests/Functional + ./Tests/WebTest