├── .gitignore ├── .styleci.yml ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── README.md ├── UPGRADE-2.0.md ├── composer.json ├── phpunit.xml.dist ├── src ├── CmfCreateBundle.php ├── Command │ └── InitHalloDevelCommand.php ├── Composer │ └── ScriptHandler.php ├── Controller │ ├── ImageController.php │ ├── JsloaderController.php │ └── RestController.php ├── DependencyInjection │ ├── CmfCreateExtension.php │ ├── Compiler │ │ └── MapperPass.php │ └── Configuration.php ├── Resources │ ├── config │ │ ├── controller-image-phpcr.xml │ │ ├── persistence-orm.xml │ │ ├── persistence-phpcr.xml │ │ ├── routing │ │ │ ├── image.xml │ │ │ ├── rest.xml │ │ │ └── rest_no_locale.xml │ │ ├── schema │ │ │ └── create-1.0.xsd │ │ └── services.xml │ ├── meta │ │ └── LICENSE │ ├── public │ │ ├── css │ │ │ ├── createStyle.css │ │ │ ├── halloCmfStyle.css │ │ │ └── overlay.css │ │ ├── img │ │ │ ├── arrow.png │ │ │ ├── close_button.png │ │ │ ├── createbundle.png │ │ │ ├── divider.png │ │ │ ├── drop_left.png │ │ │ ├── move_button.png │ │ │ ├── ok_button.png │ │ │ ├── pager_arrows.png │ │ │ ├── stripe.png │ │ │ ├── tabicon_search.png │ │ │ ├── tabicon_suggestions.png │ │ │ ├── tabicon_upload.png │ │ │ └── trash.png │ │ ├── js │ │ │ ├── init-create-ckeditor.js │ │ │ ├── init-create-common.js │ │ │ └── init-create-hallo.js │ │ └── vendor │ │ │ └── .gitignore │ └── views │ │ ├── includecssfiles.html.twig │ │ ├── includejsfiles-ckeditor.html.twig │ │ ├── includejsfiles-create.html.twig │ │ ├── includejsfiles-hallo-coffee.html.twig │ │ └── includejsfiles-hallo.html.twig ├── Security │ ├── AccessCheckerInterface.php │ ├── AlwaysAllowChecker.php │ └── RoleAccessChecker.php └── Workflow │ └── DoctrinePhpcrDeleteWorkflow.php └── tests └── Unit └── Security ├── AlwaysAllowCheckerTest.php └── RoleAccessCheckerTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | composer.lock 3 | Tests/Resources/app/cache 4 | Tests/Resources/app/logs 5 | -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: symfony 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.5 5 | - 5.6 6 | - 7.0 7 | - hhvm 8 | 9 | sudo: false 10 | 11 | cache: 12 | directories: 13 | - $HOME/.composer/cache/files 14 | 15 | env: 16 | matrix: SYMFONY_VERSION=3.2.* 17 | global: SYMFONY_DEPRECATIONS_HELPER=weak 18 | 19 | matrix: 20 | include: 21 | - php: 7.1 22 | env: DEPS=dev SYMFONY_VERSION=3.3.* 23 | - php: 5.5 24 | env: COMPOSER_FLAGS="--prefer-lowest" SYMFONY_DEPRECATIONS_HELPER=weak 25 | - php: 7.1 26 | env: SYMFONY_VERSION=3.1.* 27 | fast_finish: true 28 | 29 | before_install: 30 | - if [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then echo "memory_limit = -1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; fi 31 | - phpenv config-rm xdebug.ini || true 32 | - composer self-update 33 | - if [ "$DEPS" = "dev" ]; then perl -pi -e 's/^}$/,"minimum-stability":"dev"}/' composer.json; fi 34 | - if [ "$SYMFONY_VERSION" != "" ]; then composer require symfony/symfony:${SYMFONY_VERSION} --no-update; fi 35 | 36 | install: composer update --prefer-dist $COMPOSER_FLAGS 37 | 38 | script: phpunit 39 | 40 | notifications: 41 | irc: "irc.freenode.org#symfony-cmf" 42 | email: "symfony-cmf-devs@googlegroups.com" 43 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Changelog 2 | ========= 3 | 4 | 1.3.0 5 | ----- 6 | 7 | * Doctrine ORM support 8 | * PHP 7 support 9 | 10 | 1.2.0-RC1 11 | --------- 12 | 13 | * **2014-08-20**: Made the rest controller more generic to lay the ground work to support custom workflows 14 | * **2014-06-06**: Updated to PSR-4 autoloading 15 | 16 | 1.1.0 17 | ----- 18 | 19 | Release 1.1.0 20 | 21 | * **2014-05-05**: Support symfony setups not running in the webserver root. 22 | 23 | 1.1.0-RC3 24 | --------- 25 | 26 | * **2014-04-27**: Security was refactored to work consistently and reliably. 27 | The RestController::performSecurityChecks method was removed and replaced 28 | with the AccessCheckerInterface service. The configuration did not need to 29 | be changed. 30 | 31 | 1.1.0-RC2 32 | --------- 33 | 34 | * **2014-04-11**: drop Symfony 2.2 compatibility 35 | 36 | 1.1.0-RC1 37 | --------- 38 | 39 | * **2014-02-28**: Updated the default create.js version to be installed by the 40 | script handler to version a148ce9633535930d7b4b70cc1088102f5c5eb90 (2013-12-08) 41 | The path to the vie.js file is now fixed and no longer `view/vie.js`. 42 | 43 | 1.0.1 44 | ----- 45 | 46 | * **2013-12-26**: 1.0 allowed everybody to edit content if there was no 47 | firewall configured on a route. This version is more secure, preventing 48 | editing if there is no firewall configured. If you want to allow everybody 49 | to edit content, set `cmf_create.role: false`. 50 | If you use this together with the MediaBundle, be sure to use at least 1.1.0 51 | of MediaBundle or image upload will no longer be allowed. 52 | 53 | 1.0.0-RC2 54 | --------- 55 | 56 | * **2013-10-02**: now requires MediaBundle 1.0.0-RC2 which added `UploadFileHelperInterface` 57 | 58 | 1.0.0-RC1 59 | --------- 60 | 61 | * **2013-09-10**: changed the default setting for the `role` option to ROLE_ADMIN. 62 | You hopefully already configure this option. If you really want a public 63 | writable page set the config option `cmf_create.role` to IS_AUTHENTICATED_ANONYMOUSLY 64 | * **2013-09-04**: make CKEditor the default 65 | 66 | 1.0.0-beta4 67 | ----------- 68 | 69 | * **2013-08-20**: Changed configuration to match Bundle standards 70 | * **2013-08-16**: [Model] moved Image document, interface and logic to CmfMedia 71 | , the `image.static_basepath` configuration is renamed to `image.basepath` 72 | 73 | 1.0.0-beta3 74 | ----------- 75 | 76 | * **2013-07-28**: [DependencyInjection] added `enabled` flag to `image` config 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing 2 | ------------ 3 | 4 | Symfony2 CMF is an open source, community-driven project. We follow the same 5 | guidelines as core Symfony2. If you'd like to contribute, please read the 6 | [Contributing Code][1] part of the documentation. If you're submitting a pull 7 | request, please follow the guidelines in the [Submitting a Patch][2] section 8 | and use the [Pull Request Template][3]. 9 | 10 | [1]: http://symfony.com/doc/current/contributing/code/index.html 11 | [2]: http://symfony.com/doc/current/contributing/code/patches.html#check-list 12 | [3]: http://symfony.com/doc/current/contributing/code/patches.html#make-a-pull-request 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Symfony CMF Create Bundle 2 | 3 | [![Build Status](https://travis-ci.org/symfony-cmf/create-bundle.svg?branch=master)](https://travis-ci.org/symfony-cmf/create-bundle) 4 | [![StyleCI](https://styleci.io/repos/5883356/shield)](https://styleci.io/repos/5883356) 5 | [![Latest Stable Version](https://poser.pugx.org/symfony-cmf/create-bundle/version.png)](https://packagist.org/packages/symfony-cmf/create-bundle) 6 | [![Total Downloads](https://poser.pugx.org/symfony-cmf/create-bundle/d/total.png)](https://packagist.org/packages/symfony-cmf/create-bundle) 7 | 8 | > **WARNING: Unmaintained** To focus our efforts in the CMF project, this package 9 | > is currently *not* maintained. Security fixes and submitted bug fixes will 10 | > still be released, but no new features should be expected. 11 | > 12 | > If you want to help co-maintaining this package, tell us in a GitHub issue 13 | > or in the #symfony_cmf channel of the [Symfony devs slack](https://slackinvite.me/to/symfony-devs). 14 | 15 | This bundle is part of the [Symfony Content Management Framework (CMF)](http://cmf.symfony.com/) 16 | and licensed under the [MIT License](LICENSE). 17 | 18 | The CreateBundle integrates [create.js](http://createjs.org/) and the 19 | [CreatePHP](https://github.com/flack/createphp) helper library into Symfony2. 20 | 21 | create.js is a comprehensive web editing interface for Content Management 22 | Systems. Using RDFa annotations in the content, it makes any content editable 23 | directly in the front end. 24 | 25 | CreatePHP is a PHP library to help with RDFa annotation of documents 26 | and entities. 27 | 28 | 29 | ## Requirements 30 | 31 | * Symfony 2.8+ 32 | * create.js (can be installed through a composer post-install task, see the installation guide link below) 33 | * See also the `require` section of [composer.json](composer.json) 34 | 35 | 36 | ## Documentation 37 | 38 | For the install guide and reference, see: 39 | 40 | * [CreateBundle documentation](http://symfony.com/doc/master/cmf/bundles/create/index.html) 41 | 42 | See also: 43 | 44 | * [All Symfony CMF documentation](http://symfony.com/doc/master/cmf/index.html) - complete Symfony CMF reference 45 | * [Symfony CMF Website](http://cmf.symfony.com/) - introduction, live demo, support and community links 46 | 47 | 48 | ## Contributing 49 | 50 | Pull requests are welcome. Please see our [CONTRIBUTING](CONTRIBUTING.md) guide. 51 | 52 | Unit and/or functional tests exist for this bundle. See the 53 | [Testing documentation](http://symfony.com/doc/master/cmf/components/testing.html) 54 | for a guide to running the tests. 55 | 56 | Thanks to 57 | [everyone who has contributed](https://github.com/symfony-cmf/CreateBundle/contributors) already. 58 | -------------------------------------------------------------------------------- /UPGRADE-2.0.md: -------------------------------------------------------------------------------- 1 | # Upgrade from 1.2 to 2.0 2 | 3 | # REST Controller 4 | 5 | * The deprecated methods are removed from the RestController: 6 | 7 | Removed | Use instead 8 | ------------------------ | ------------------------------- 9 | `putDocumentAction()` | `updateDocumentAction()` 10 | `deleteDocumentAction()` | `updateDocumentAction()` 11 | `performSecurityCheck()` | `$this->accessChecker->check()` 12 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "symfony-cmf/create-bundle", 3 | "type": "symfony-bundle", 4 | "description": "Symfony Bundle for createphp and create.js. The easiest way to make any site editable and have semantic annotations with RDFa.", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Liip AG", 9 | "homepage": "http://www.liip.ch/" 10 | }, 11 | { 12 | "name": "Symfony CMF Community", 13 | "homepage": "https://github.com/symfony-cmf/CreateBundle/contributors" 14 | } 15 | ], 16 | "require": { 17 | "php": "^5.5.6|^7.0", 18 | "symfony/framework-bundle": "^2.8|^3.0", 19 | "symfony/assetic-bundle": "^2.1", 20 | "friendsofsymfony/rest-bundle": "^1.0|^2.0", 21 | "midgard/createphp": "^1.1" 22 | }, 23 | "suggest": { 24 | "jms/serializer-bundle": "Add support for advanced serialization capabilities (^0.12|^1.0)", 25 | "symfony-cmf/core-bundle": "To be able to enable 'rest_force_request_locale' (^1.0)", 26 | "symfony-cmf/media-bundle": "When using the default image support (^1.1)" 27 | }, 28 | "autoload": { 29 | "psr-4": { 30 | "Symfony\\Cmf\\Bundle\\CreateBundle\\": "src/" 31 | } 32 | }, 33 | "autoload-dev": { 34 | "psr-4": { 35 | "Symfony\\Cmf\\Bundle\\CreateBundle\\Tests\\": "tests/" 36 | } 37 | }, 38 | "extra": { 39 | "branch-alias": { 40 | "dev-master": "2.0-dev" 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | ./tests/ 10 | 11 | 12 | 13 | 14 | 15 | ./ 16 | 17 | Resources/ 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/CmfCreateBundle.php: -------------------------------------------------------------------------------- 1 | hasExtension('jms_di_extra')) { 25 | $container->getExtension('jms_di_extra')->blackListControllerFile(__DIR__.'/Controller/ImageController.php'); 26 | } 27 | 28 | $container->addCompilerPass(new MapperPass()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Command/InitHalloDevelCommand.php: -------------------------------------------------------------------------------- 1 | setName('cmf:create:init-hallo-devel') 29 | ; 30 | } 31 | 32 | /** 33 | * This will clone the hallo repository into Resources/public/vendor. 34 | */ 35 | protected function execute(InputInterface $input, OutputInterface $output) 36 | { 37 | $status = null; 38 | $output = array(); 39 | $dir = getcwd(); 40 | chdir(__DIR__.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'Resources'.DIRECTORY_SEPARATOR.'public'.DIRECTORY_SEPARATOR.'vendor'); 41 | exec('git clone https://github.com/bergie/hallo.git', $output, $status); 42 | chdir($dir); 43 | if ($status) { 44 | die("Running git submodule sync failed with $status\n"); 45 | } 46 | if ($status) { 47 | die("Running git submodule --init --recursive failed with $status\n"); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Composer/ScriptHandler.php: -------------------------------------------------------------------------------- 1 | getComposer()->getPackage()->getExtra(); 38 | $event->getIO()->write('Download or update create'); 39 | 40 | // directory where the repository should be clone into 41 | if (isset($extra['create-directory'])) { 42 | $directory = getcwd().'/'.$extra['create-directory']; 43 | } else { 44 | $directory = __DIR__.'/../Resources/public/vendor/create'; 45 | } 46 | 47 | // git repository 48 | if (isset($extra['create-repository'])) { 49 | $repository = $extra['create-repository']; 50 | } else { 51 | $repository = 'https://github.com/bergie/create.git'; 52 | } 53 | 54 | // commit id 55 | if (isset($extra['create-commit'])) { 56 | $commit = $extra['create-commit']; 57 | } else { 58 | $commit = self::CREATE_COMMIT_ID; 59 | } 60 | 61 | self::gitSynchronize($directory, $repository, $commit); 62 | } 63 | 64 | public static function downloadCkeditor(Event $event) 65 | { 66 | $extra = $event->getComposer()->getPackage()->getExtra(); 67 | $event->getIO()->write('Download or update ckeditor'); 68 | 69 | // directory where the repository should be clone into 70 | if (isset($extra['ckeditor-directory'])) { 71 | $directory = getcwd().'/'.$extra['ckeditor-directory']; 72 | } else { 73 | $directory = __DIR__.'/../Resources/public/vendor/ckeditor'; 74 | } 75 | 76 | // git repository 77 | if (isset($extra['ckeditor-repository'])) { 78 | $repository = $extra['ckeditor-repository']; 79 | } else { 80 | $repository = 'https://github.com/ckeditor/ckeditor-releases.git'; 81 | } 82 | 83 | // commit id 84 | if (isset($extra['ckeditor-commit'])) { 85 | $commit = $extra['ckeditor-commit']; 86 | } else { 87 | $commit = self::CKEDITOR_COMMIT_ID; 88 | } 89 | 90 | self::gitSynchronize($directory, $repository, $commit); 91 | } 92 | 93 | /** 94 | * @throws \RuntimeException 95 | * 96 | * @param string $directory The directory where the repository should be clone into 97 | * @param string $repository The git repository 98 | * @param string $commitId The commit id 99 | */ 100 | public static function gitSynchronize($directory, $repository, $commitId) 101 | { 102 | $currentDirectory = getcwd(); 103 | $parentDirectory = dirname($directory); 104 | $projectDirectory = basename($directory); 105 | 106 | $status = null; 107 | $output = array(); 108 | chdir($parentDirectory); 109 | 110 | if (is_dir($projectDirectory)) { 111 | chdir($projectDirectory); 112 | exec('git remote update', $output, $status); 113 | if ($status) { 114 | throw new \RuntimeException("Running git pull $repository failed with $status\n"); 115 | } 116 | } else { 117 | exec("git clone $repository $projectDirectory -q", $output, $status); 118 | if ($status) { 119 | throw new \RuntimeException("Running git clone $repository failed with $status\n"); 120 | } 121 | chdir($projectDirectory); 122 | } 123 | 124 | exec("git checkout $commitId -q", $output, $status); 125 | if ($status) { 126 | throw new \RuntimeException("Running git clone $repository failed with $status\n"); 127 | } 128 | 129 | chdir($currentDirectory); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/Controller/ImageController.php: -------------------------------------------------------------------------------- 1 | viewHandler = $viewHandler; 72 | $this->accessChecker = $accessChecker; 73 | } 74 | 75 | private function processResults($images, $offset) 76 | { 77 | $data = array( 78 | 'offset' => $offset, 79 | 'total' => count($images), 80 | 'assets' => $images, 81 | ); 82 | 83 | $view = View::create($data); 84 | 85 | return $this->viewHandler->handle($view); 86 | } 87 | 88 | /** 89 | * Search for assets matching the query. 90 | * 91 | * This function currently only returns some fixture data to try the editor 92 | */ 93 | public function searchAction(Request $request) 94 | { 95 | $offset = (int) $request->query->get('offset', 0); 96 | $limit = (int) $request->query->get('limit', 8); 97 | $query = $request->query->get('query'); 98 | $images = $this->getImagesByCaption($query, $offset, $limit); 99 | 100 | return $this->processResults($images, $offset); 101 | } 102 | 103 | /** 104 | * Get images by a specified caption. 105 | * 106 | * @param string $name 107 | * @param int $offset 108 | * @param int $limit 109 | * 110 | * @return array 111 | */ 112 | protected function getImagesByCaption($name, $offset, $limit) 113 | { 114 | $images = $this->getObjectManager()->getRepository($this->class) 115 | ->setRootPath($this->rootPath) 116 | ->searchImages($name, $limit, $offset); 117 | 118 | return $images ? array_values($images->toArray()) : array(); 119 | } 120 | 121 | /** 122 | * TODO: returns empty response. 123 | * 124 | * @param Request $request 125 | * 126 | * @return Response 127 | */ 128 | public function showRelatedAction(Request $request) 129 | { 130 | $links = array(); 131 | $data = array( 132 | 'links' => $links, 133 | ); 134 | 135 | $view = View::create($data); 136 | 137 | return $this->viewHandler->handle($view); 138 | } 139 | 140 | protected function checkSecurityUpload(Request $request) 141 | { 142 | if (!$this->accessChecker->check($request)) { 143 | throw new AccessDeniedException(); 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/Controller/JsloaderController.php: -------------------------------------------------------------------------------- 1 | viewHandler = $viewHandler; 103 | $this->accessChecker = $accessChecker; 104 | $this->stanbolUrl = $stanbolUrl; 105 | $this->imageUploadEnabled = $imageUploadEnabled; 106 | $this->fixedToolbar = $fixedToolbar; 107 | $this->plainTextTypes = $plainTextTypes; 108 | $this->editorBasePath = $editorBasePath; 109 | $this->browserFileHelper = $browserFileHelper; 110 | } 111 | 112 | /** 113 | * Render javascript HTML tags for create.js and dependencies and bootstrap 114 | * javscript code. 115 | * 116 | * This bundle comes with templates for ckeditor, hallo and to develop on 117 | * the hallo coffeescript files. 118 | * 119 | * To use a different editor simply create a template following the naming 120 | * below: 121 | * CmfCreateBundle::includejsfiles-%editor%.html.twig 122 | * and pass the appropriate editor name. 123 | * 124 | * @param Request $request the request object for the AccessChecker 125 | * @param string $editor the name of the editor to load 126 | */ 127 | public function includeJSFilesAction(Request $request, $editor = 'ckeditor') 128 | { 129 | if (!$this->accessChecker->check($request)) { 130 | return new Response(''); 131 | } 132 | 133 | $view = new View(); 134 | 135 | $view->setTemplate(sprintf('CmfCreateBundle::includejsfiles-%s.html.twig', $editor)); 136 | 137 | if ($this->browserFileHelper) { 138 | $helper = $this->browserFileHelper->getEditorHelper($editor); 139 | $browseUrl = $helper ? $helper->getUrl() : false; 140 | } else { 141 | $browseUrl = false; 142 | } 143 | 144 | $view->setData(array( 145 | 'cmfCreateEditor' => $editor, 146 | 'cmfCreateStanbolUrl' => $this->stanbolUrl, 147 | 'cmfCreateImageUploadEnabled' => (bool) $this->imageUploadEnabled, 148 | 'cmfCreateFixedToolbar' => (bool) $this->fixedToolbar, 149 | 'cmfCreatePlainTextTypes' => json_encode($this->plainTextTypes), 150 | 'cmfCreateEditorBasePath' => $this->editorBasePath, 151 | 'cmfCreateBrowseUrl' => $browseUrl, 152 | ) 153 | ); 154 | 155 | return $this->viewHandler->handle($view); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/Controller/RestController.php: -------------------------------------------------------------------------------- 1 | viewHandler = $viewHandler; 78 | $this->rdfMapper = $rdfMapper; 79 | $this->typeFactory = $typeFactory; 80 | $this->restHandler = $restHandler; 81 | $this->accessChecker = $accessChecker; 82 | $this->forceRequestLocale = $forceRequestLocale; 83 | } 84 | 85 | protected function getModelBySubject(Request $request, $subject) 86 | { 87 | $model = $this->rdfMapper->getBySubject($subject); 88 | if (empty($model)) { 89 | throw new NotFoundHttpException($subject.' not found'); 90 | } 91 | 92 | if ($this->forceRequestLocale && $model instanceof TranslatableInterface) { 93 | $model->setLocale($request->getLocale()); 94 | } 95 | 96 | return $model; 97 | } 98 | 99 | /** 100 | * Handle arbitrary methods with the RestHandler. 101 | * 102 | * Except for the PUT operation to update a document, operations are 103 | * registered as workflows. 104 | * 105 | * @param Request $request 106 | * @param string $subject URL of the subject, ie: /cms/simple/news/news-name 107 | * 108 | * @return Response 109 | * 110 | * @throws AccessDeniedException if the action is not allowed by the access checker 111 | * 112 | * @see RestService::run 113 | * @since 1.2 114 | */ 115 | public function updateDocumentAction(Request $request, $subject) 116 | { 117 | if (!$this->accessChecker->check($request)) { 118 | throw new AccessDeniedException(); 119 | } 120 | 121 | $model = $this->getModelBySubject($request, $subject); 122 | $type = $this->typeFactory->getTypeByObject($model); 123 | 124 | $result = $this->restHandler->run($request->request->all(), $type, $subject, strtolower($request->getMethod())); 125 | $view = View::create($result)->setFormat('json'); 126 | 127 | return $this->viewHandler->handle($view, $request); 128 | } 129 | 130 | /** 131 | * Handle document POST (creation). 132 | * 133 | * @param Request $request 134 | * 135 | * @return Response 136 | * 137 | * @throws AccessDeniedException if the action is not allowed by the access checker 138 | */ 139 | public function postDocumentAction(Request $request) 140 | { 141 | if (!$this->accessChecker->check($request)) { 142 | throw new AccessDeniedException(); 143 | } 144 | 145 | $rdfType = trim($request->request->get('@type'), '<>'); 146 | $type = $this->typeFactory->getTypeByRdf($rdfType); 147 | 148 | $result = $this->restHandler->run($request->request->all(), $type, null, RestService::HTTP_POST); 149 | 150 | if (!is_null($result)) { 151 | $view = View::create($result)->setFormat('json'); 152 | 153 | return $this->viewHandler->handle($view, $request); 154 | } 155 | 156 | return Response::create('The document was not created', 500); 157 | } 158 | 159 | /** 160 | * Get available Workflows for a document. 161 | * 162 | * @param Request $request 163 | * @param string $subject 164 | * 165 | * @return Response 166 | * 167 | * @throws AccessDeniedException if getting workflows for this document is 168 | * not allowed by the access checker 169 | */ 170 | public function workflowsAction(Request $request, $subject) 171 | { 172 | if (!$this->accessChecker->check($request)) { 173 | throw new AccessDeniedException(); 174 | } 175 | 176 | $result = $this->restHandler->getWorkflows($subject); 177 | $view = View::create($result)->setFormat('json'); 178 | 179 | return $this->viewHandler->handle($view, $request); 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/DependencyInjection/CmfCreateExtension.php: -------------------------------------------------------------------------------- 1 | processConfiguration($configuration, $configs); 39 | 40 | // load config 41 | $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 42 | $loader->load('services.xml'); 43 | 44 | $container->setParameter('cmf_create.map', $config['map']); 45 | 46 | $container->setParameter('cmf_create.stanbol_url', $config['stanbol_url']); 47 | 48 | $container->setParameter('cmf_create.fixed_toolbar', $config['fixed_toolbar']); 49 | 50 | $container->setParameter('cmf_create.editor_base_path', $config['editor_base_path']); 51 | 52 | if (empty($config['plain_text_types'])) { 53 | $config['plain_text_types'] = array('dcterms:title', 'schema:headline'); 54 | } 55 | $container->setParameter('cmf_create.plain_text_types', $config['plain_text_types']); 56 | 57 | if ($config['auto_mapping']) { 58 | foreach ($container->getParameter('kernel.bundles') as $bundleShortName => $class) { 59 | $bundle = new \ReflectionClass($class); 60 | 61 | $rdfMappingDir = $container->getParameter('kernel.root_dir').'/Resources/'.$bundleShortName.'/rdf-mappings'; 62 | if (file_exists($rdfMappingDir)) { 63 | $config['rdf_config_dirs'][] = $rdfMappingDir; 64 | } 65 | 66 | $rdfMappingDir = dirname($bundle->getFilename()).'/Resources/rdf-mappings'; 67 | if (file_exists($rdfMappingDir)) { 68 | $config['rdf_config_dirs'][] = $rdfMappingDir; 69 | } 70 | } 71 | } 72 | 73 | $container->setParameter('cmf_create.rdf_config_dirs', $config['rdf_config_dirs']); 74 | 75 | if ($config['rest_force_request_locale']) { 76 | $bundles = $container->getParameter('kernel.bundles'); 77 | if (!isset($bundles['CmfCoreBundle'])) { 78 | throw new InvalidConfigurationException('You need to enable "CmfCoreBundle" when activating the "rest_force_request_locale" option'); 79 | } 80 | } 81 | $container->setParameter('cmf_create.rest.force_request_locale', $config['rest_force_request_locale']); 82 | 83 | $this->loadSecurity($config['security'], $loader, $container); 84 | 85 | if ($this->isConfigEnabled($container, $config['persistence']['phpcr'])) { 86 | $this->loadPhpcr($config['persistence']['phpcr'], $loader, $container); 87 | } else { 88 | // TODO: we should leverage the mediabundle here and not depend on phpcr 89 | $container->setParameter('cmf_create.image_enabled', false); 90 | } 91 | if ($this->isConfigEnabled($container, $config['persistence']['orm'])) { 92 | $this->loadOrm($config['persistence']['orm'], $loader, $container); 93 | } 94 | $container->setAlias('cmf_create.object_mapper', $config['object_mapper_service_id']); 95 | } 96 | 97 | protected function loadSecurity($config, XmlFileLoader $loader, ContainerBuilder $container) 98 | { 99 | $container->setParameter('cmf_create.security.role', $config['role']); 100 | if (isset($config['checker_service'])) { 101 | $service = $config['checker_service']; 102 | } elseif (false === $config['role']) { 103 | $service = 'cmf_create.security.always_allow_checker'; 104 | } else { 105 | $service = 'cmf_create.security.role_access_checker'; 106 | } 107 | $container->setAlias('cmf_create.security.checker', $service); 108 | } 109 | 110 | public function loadPhpcr($config, XmlFileLoader $loader, ContainerBuilder $container) 111 | { 112 | $container->setParameter('cmf_create.persistence.phpcr.manager_name', $config['manager_name']); 113 | 114 | $loader->load('persistence-phpcr.xml'); 115 | 116 | if ($config['image']['enabled']) { 117 | $loader->load('controller-image-phpcr.xml'); 118 | 119 | $container->setParameter('cmf_create.image_enabled', true); 120 | $container->setParameter('cmf_create.persistence.phpcr.image.class', $config['image']['model_class']); 121 | $container->setParameter('cmf_create.persistence.phpcr.image_basepath', $config['image']['basepath']); 122 | } else { 123 | $container->setParameter('cmf_create.image_enabled', false); 124 | } 125 | 126 | if ($config['delete']) { 127 | $restHandler = $container->getDefinition('cmf_create.rest.handler'); 128 | $restHandler->addMethodCall('setWorkflow', array(RestService::HTTP_DELETE, new Reference('cmf_create.persistence.phpcr.delete_workflow'))); 129 | } 130 | } 131 | 132 | public function loadOrm($config, XmlFileLoader $loader, ContainerBuilder $container) 133 | { 134 | $loader->load('persistence-orm.xml'); 135 | $container->setParameter('cmf_create.persistence.orm.manager_name', $config['manager_name']); 136 | } 137 | 138 | /** 139 | * Returns the base path for the XSD files. 140 | * 141 | * @return string The XSD base path 142 | */ 143 | public function getXsdValidationBasePath() 144 | { 145 | return __DIR__.'/../Resources/config/schema'; 146 | } 147 | 148 | public function getNamespace() 149 | { 150 | return 'http://cmf.symfony.com/schema/dic/create'; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/DependencyInjection/Compiler/MapperPass.php: -------------------------------------------------------------------------------- 1 | hasDefinition('cmf_create.chain_mapper')) { 27 | return; 28 | } 29 | 30 | $definition = $container->getDefinition('cmf_create.chain_mapper'); 31 | 32 | $tags = $container->findTaggedServiceIds('cmf_create.mapper'); 33 | if ($container->getAlias('cmf_create.object_mapper') == 'cmf_create.chain_mapper' && count($tags) == 0) { 34 | throw new InvalidConfigurationException('You need to either enable one of the persistence layers, set the cmf_create.object_mapper_service_id option, or tag a mapper with cmf_create.mapper'); 35 | } 36 | 37 | foreach ($tags as $id => $tags) { 38 | foreach ($tags as $attributes) { 39 | $definition->addMethodCall('registerMapper', array(new Reference($id), $attributes['alias'])); 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/DependencyInjection/Configuration.php: -------------------------------------------------------------------------------- 1 | root('cmf_create'); 31 | 32 | $rootNode 33 | ->fixXmlConfig('plain_text_type', 'plain_text_types') 34 | ->fixXmlConfig('rdf_config_dir', 'rdf_config_dirs') 35 | ->children() 36 | ->booleanNode('rest_force_request_locale')->defaultFalse()->end() 37 | ->arrayNode('map') 38 | ->useAttributeAsKey('name') 39 | ->prototype('scalar')->end() 40 | ->end() 41 | ->arrayNode('security') 42 | ->addDefaultsIfNotSet() 43 | ->children() 44 | ->scalarNode('checker_service')->end() 45 | ->scalarNode('role')->defaultValue('ROLE_ADMIN')->end() 46 | ->end() 47 | ->end() 48 | ->scalarNode('stanbol_url')->defaultValue('http://dev.iks-project.eu:8081')->end() 49 | ->booleanNode('fixed_toolbar')->defaultTrue()->end() 50 | ->scalarNode('editor_base_path')->defaultValue('/bundles/cmfcreate/vendor/ckeditor/')->end() 51 | ->arrayNode('plain_text_types') 52 | ->useAttributeAsKey('name') 53 | ->prototype('scalar')->end() 54 | ->end() 55 | ->arrayNode('rdf_config_dirs') 56 | ->useAttributeAsKey('dir') 57 | ->prototype('scalar')->end() 58 | ->end() 59 | ->booleanNode('auto_mapping')->defaultTrue()->end() 60 | ->scalarNode('object_mapper_service_id')->defaultValue('cmf_create.chain_mapper')->end() 61 | 62 | ->arrayNode('persistence') 63 | ->addDefaultsIfNotSet() 64 | ->children() 65 | ->arrayNode('phpcr') 66 | ->addDefaultsIfNotSet() 67 | ->canBeEnabled() 68 | ->children() 69 | ->scalarNode('manager_name')->defaultNull()->end() 70 | ->arrayNode('image') 71 | ->addDefaultsIfNotSet() 72 | ->canBeUnset() 73 | ->canBeEnabled() 74 | ->children() 75 | // if the CmfMediaBundle is present, it will prepend configuration 76 | // to enable this and set its model_class 77 | ->scalarNode('model_class')->cannotBeEmpty()->end() 78 | ->scalarNode('basepath')->defaultValue('/cms/media')->end() 79 | ->end() 80 | ->end() 81 | ->booleanNode('delete')->defaultValue(false)->end() 82 | ->end() 83 | ->end() 84 | ->arrayNode('orm') 85 | ->addDefaultsIfNotSet() 86 | ->canBeEnabled() 87 | ->children() 88 | ->scalarNode('manager_name')->defaultNull()->end() 89 | ->end() 90 | ->end() 91 | ->end() 92 | ->end() 93 | ->end() 94 | ; 95 | 96 | return $treeBuilder; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/Resources/config/controller-image-phpcr.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | %cmf_create.persistence.phpcr.manager_name% 11 | %cmf_create.persistence.phpcr.image.class% 12 | %cmf_create.persistence.phpcr.image_basepath% 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Resources/config/persistence-orm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | null 9 | 10 | 11 | 12 | 13 | 14 | %cmf_create.map% 15 | 16 | %cmf_create.persistence.orm.manager_name% 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Resources/config/persistence-phpcr.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | null 9 | 10 | 11 | 12 | 13 | 14 | %cmf_create.map% 15 | 16 | %cmf_create.persistence.phpcr.manager_name% 17 | 18 | 19 | 20 | 21 | 22 | %cmf_create.persistence.phpcr.manager_name% 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/Resources/config/routing/image.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | cmf_create.image.controller:uploadAction 9 | json 10 | default 11 | 12 | 13 | 14 | cmf_create.image.controller:searchAction 15 | json 16 | 17 | 18 | 19 | cmf_create.image.controller:showRelatedAction 20 | json 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/Resources/config/routing/rest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Resources/config/routing/rest_no_locale.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | cmf_create.rest.controller:postDocumentAction 9 | json 10 | 11 | 12 | 13 | cmf_create.rest.controller:updateDocumentAction 14 | json 15 | .+ 16 | 17 | 18 | 19 | cmf_create.rest.controller:workflowsAction 20 | json 21 | .+ 22 | 23 | 24 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/Resources/config/schema/create-1.0.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/Resources/config/services.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | %cmf_create.stanbol_url% 12 | %cmf_create.image_enabled% 13 | %cmf_create.fixed_toolbar% 14 | %cmf_create.plain_text_types% 15 | %cmf_create.editor_base_path% 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | %cmf_create.rdf_config_dirs% 26 | 27 | 28 | 29 | 30 | 31 | %cmf_create.map% 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | %cmf_create.rest.force_request_locale% 41 | 42 | 43 | 44 | %cmf_create.security.role% 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/Resources/meta/LICENSE: -------------------------------------------------------------------------------- 1 | CreateBundle 2 | 3 | The MIT License 4 | 5 | Copyright (c) 2011-2015 Symfony CMF 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /src/Resources/public/css/createStyle.css: -------------------------------------------------------------------------------- 1 | /* Create toolbar */ 2 | /******************/ 3 | a.create-ui-toggle { 4 | background-image: url("/bundles/cmfcreate/img/createbundle.png"); 5 | } 6 | 7 | /* General contenteditable before editing */ 8 | /*******************************************/ 9 | [contenteditable="true"]:hover{ 10 | cursor: pointer; 11 | } 12 | 13 | [contenteditable="true"] { 14 | outline: 1px solid lightgreen; 15 | position: relative; 16 | z-index: 1; 17 | } 18 | 19 | /* General contenteditable while editing */ 20 | /*****************************************/ 21 | [contenteditable].inEditMode { 22 | cursor: auto; 23 | outline: 3px solid black; 24 | } 25 | 26 | /* Create ui toolbar while editing */ 27 | /***********************************/ 28 | .create-ui-toolbar-wrapper.editing { 29 | background: rgba(160, 216, 56, 0.8); 30 | } 31 | -------------------------------------------------------------------------------- /src/Resources/public/css/halloCmfStyle.css: -------------------------------------------------------------------------------- 1 | body > .hallotoolbar { 2 | z-index: 500; 3 | margin-left: -13px; 4 | background: #000000; 5 | } 6 | 7 | /* Toolbar General */ 8 | /*******************/ 9 | 10 | .ui-state-active { 11 | background-color: #01ADD2; 12 | } 13 | 14 | .hallotoolbar .halloButtonrow-1:not(:last-child) { 15 | background-color: #272727; 16 | text-align: right; 17 | width: auto; 18 | float: right; 19 | border-top-left-radius: 5px; 20 | border-top-right-radius: 5px; 21 | } 22 | 23 | .hallotoolbar .halloButtonrow-1:last-child { 24 | border-top-right-radius: 5px; 25 | } 26 | 27 | .hallotoolbar .halloButtonrow:last-of-type { 28 | border-top-left-radius: 5px; 29 | } 30 | 31 | .hallotoolbar .halloButtonrow-2 .ui-buttonset { 32 | background: url('/bundles/cmfcreate/img/stripe.png') no-repeat right 5px; 33 | padding: 0 6px 0 5px; 34 | } 35 | 36 | /* Dialog styling */ 37 | /*******************/ 38 | .ui-dialog { 39 | -webkit-box-shadow: none; 40 | -moz-box-shadow: none; 41 | box-shadow: none; 42 | border: 3px solid black; 43 | border-radius: 5px; 44 | overflow: visible; 45 | background: #FFFFFF; 46 | } 47 | 48 | .ui-dialog .ui-dialog-titlebar { 49 | background: #000000; 50 | color: white; 51 | padding: 5px 10px; 52 | border: none; 53 | } 54 | 55 | .ui-dialog .ui-dialog-title { 56 | font-weight: normal; 57 | text-shadow: none; 58 | } 59 | 60 | .ui-dialog .tabs { 61 | margin-left: 0; 62 | margin-bottom: 0; 63 | } 64 | 65 | .ui-dialog .tabs li { 66 | line-height: 30px; 67 | } 68 | 69 | /* Image dialog */ 70 | .halloimage-dialog .tabs li { 71 | background: #01add2 url('/bundles/cmfcreate/img/divider.png') no-repeat right; 72 | } 73 | 74 | .halloimage-dialog .tabs li.halloimage-tab-suggestions span { 75 | background: url('/bundles/cmfcreate/img/tabicon_suggestions.png') no-repeat left; 76 | } 77 | .halloimage-dialog .tabs li.halloimage-tab-search span { 78 | background: url('/bundles/cmfcreate/img/tabicon_search.png') no-repeat left; 79 | } 80 | .halloimage-dialog .tabs li.halloimage-tab-upload span { 81 | background: url('/bundles/cmfcreate/img/tabicon_upload.png') no-repeat left; 82 | } 83 | 84 | .halloimage-dialog .tab-activeIndicator { 85 | background: url('/bundles/cmfcreate/img/arrow.png'); 86 | } 87 | 88 | .halloimage-dialog .rotationWrapper .hintArrow { 89 | background: transparent url('/bundles/cmfcreate/img/drop_left.png') no-repeat -2px -2px; 90 | } 91 | 92 | /* Drag n Drop */ 93 | [contenteditable] .tmpLine{ 94 | background-color: #ffffff; 95 | width: 98%; 96 | height: 2px; 97 | margin: 0 auto 10px auto; 98 | border-top: 2px solid #1cb8d6; 99 | border-bottom: 2px solid #1cb8d6; 100 | opacity: 1; 101 | padding: 1px; 102 | } 103 | 104 | .bigOverlay, .smallOverlay { 105 | display: none; 106 | position: absolute; 107 | top: 0; 108 | left: 0; 109 | background-color: rgba(28, 184, 214, 0.4); 110 | } 111 | 112 | .bigOverlayRight{ 113 | display : block; 114 | border-right : 3px dashed rgb(28, 184, 214); 115 | border-left : none; 116 | } 117 | 118 | .bigOverlayLeft{ 119 | display : block; 120 | border-left : 3px dashed rgb(28, 184, 214); 121 | border-right : none; 122 | } 123 | 124 | .smallOverlayLeft{ 125 | border-right : 3px dashed rgb(28, 184, 214); 126 | } 127 | 128 | .smallOverlayRight{ 129 | border-left : 3px dashed rgb(28, 184, 214); 130 | } 131 | 132 | .ui-draggable{ 133 | cursor: move; 134 | } 135 | 136 | .ui-draggable-dragging{ 137 | border: 3px solid white; 138 | } 139 | 140 | [contenteditable] img.ui-state-disabled { 141 | opacity: 1; 142 | } 143 | 144 | .customHelper{ 145 | background-size: cover; 146 | width: 100px; 147 | height: 100px; 148 | z-index: 1050; 149 | } 150 | 151 | .trashcan{ 152 | width: 50px; 153 | height: 50px; 154 | position: relative; 155 | top: 25px; 156 | left: 25px; 157 | background: rgba(0,0,0,0.8) url('/bundles/cmfcreate/img/trash.png') no-repeat 12px 12px; 158 | border-radius: 10px; 159 | cursor: none; 160 | } 161 | 162 | /** LINK DIALOG **/ 163 | .hallolink-dialog .ui-dialog-content { 164 | padding-top: 1em; 165 | } 166 | 167 | .hallolink-dialog form { 168 | display: table; 169 | margin: auto; 170 | } 171 | 172 | .hallolink-dialog form input[name=name] { 173 | width: 330px; 174 | margin-bottom: 7px; 175 | } 176 | 177 | .hallolink-dialog form input[name=url] { 178 | width: 330px; 179 | } 180 | 181 | .hallolink-dialog form input[type=submit] { 182 | position: relative; 183 | top: -1px; 184 | left: -1px; 185 | } 186 | 187 | /* Misc */ 188 | div.halloEditIndicator { 189 | z-index: 3; 190 | opacity: 1 !important; 191 | } 192 | -------------------------------------------------------------------------------- /src/Resources/public/css/overlay.css: -------------------------------------------------------------------------------- 1 | div[contenteditable] { 2 | position: relative; 3 | } 4 | 5 | .halloOverlay { 6 | background-color: #000000; 7 | opacity: 0.5; 8 | width: 100%; 9 | height: 100%; 10 | position: fixed; 11 | top: 0; 12 | left: 0; 13 | z-index: 250; 14 | } 15 | 16 | .halloBackground { 17 | position: absolute; 18 | background-color: #fff; 19 | z-index: 300; 20 | } -------------------------------------------------------------------------------- /src/Resources/public/img/arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/symfony-cmf/create-bundle/7b6018290628b1479d6a4a428846f88dc64fa2dc/src/Resources/public/img/arrow.png -------------------------------------------------------------------------------- /src/Resources/public/img/close_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/symfony-cmf/create-bundle/7b6018290628b1479d6a4a428846f88dc64fa2dc/src/Resources/public/img/close_button.png -------------------------------------------------------------------------------- /src/Resources/public/img/createbundle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/symfony-cmf/create-bundle/7b6018290628b1479d6a4a428846f88dc64fa2dc/src/Resources/public/img/createbundle.png -------------------------------------------------------------------------------- /src/Resources/public/img/divider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/symfony-cmf/create-bundle/7b6018290628b1479d6a4a428846f88dc64fa2dc/src/Resources/public/img/divider.png -------------------------------------------------------------------------------- /src/Resources/public/img/drop_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/symfony-cmf/create-bundle/7b6018290628b1479d6a4a428846f88dc64fa2dc/src/Resources/public/img/drop_left.png -------------------------------------------------------------------------------- /src/Resources/public/img/move_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/symfony-cmf/create-bundle/7b6018290628b1479d6a4a428846f88dc64fa2dc/src/Resources/public/img/move_button.png -------------------------------------------------------------------------------- /src/Resources/public/img/ok_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/symfony-cmf/create-bundle/7b6018290628b1479d6a4a428846f88dc64fa2dc/src/Resources/public/img/ok_button.png -------------------------------------------------------------------------------- /src/Resources/public/img/pager_arrows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/symfony-cmf/create-bundle/7b6018290628b1479d6a4a428846f88dc64fa2dc/src/Resources/public/img/pager_arrows.png -------------------------------------------------------------------------------- /src/Resources/public/img/stripe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/symfony-cmf/create-bundle/7b6018290628b1479d6a4a428846f88dc64fa2dc/src/Resources/public/img/stripe.png -------------------------------------------------------------------------------- /src/Resources/public/img/tabicon_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/symfony-cmf/create-bundle/7b6018290628b1479d6a4a428846f88dc64fa2dc/src/Resources/public/img/tabicon_search.png -------------------------------------------------------------------------------- /src/Resources/public/img/tabicon_suggestions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/symfony-cmf/create-bundle/7b6018290628b1479d6a4a428846f88dc64fa2dc/src/Resources/public/img/tabicon_suggestions.png -------------------------------------------------------------------------------- /src/Resources/public/img/tabicon_upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/symfony-cmf/create-bundle/7b6018290628b1479d6a4a428846f88dc64fa2dc/src/Resources/public/img/tabicon_upload.png -------------------------------------------------------------------------------- /src/Resources/public/img/trash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/symfony-cmf/create-bundle/7b6018290628b1479d6a4a428846f88dc64fa2dc/src/Resources/public/img/trash.png -------------------------------------------------------------------------------- /src/Resources/public/js/init-create-ckeditor.js: -------------------------------------------------------------------------------- 1 | jQuery(document).ready(function() { 2 | jQuery('body').midgardCreate({ 3 | url: function() { 4 | if (this.id) { 5 | if (this.id.charAt(0) == "<") { 6 | return cmfCreatePutDocument + this.id.substring(1, this.id.length - 1); 7 | } 8 | return cmfCreatePutDocument + this.id; 9 | } 10 | return cmfCreatePutDocument; 11 | }, 12 | workflows: { 13 | url: function(model) { 14 | return cmfCreateWorkflows + model.getSubjectUri(); 15 | } 16 | }, 17 | stanbolUrl: cmfCreateStanbolUrl, 18 | tags: true, 19 | editorWidgets: { 20 | 'default': 'ckeditor' 21 | }, 22 | editorOptions: { 23 | ckeditor: { 24 | widget: 'ckeditorWidget', 25 | options: { 26 | filebrowserImageUploadUrl: cmfCreateImageUpload 27 | } 28 | } 29 | }, 30 | collectionWidgets: { 31 | 'default': null, 32 | 'feature': 'midgardCollectionAdd' 33 | }, 34 | statechange: function (event, params) { 35 | if (params.hasOwnProperty('state') && params.state === 'edit') { 36 | $('.create-ui-toolbar-wrapper') 37 | .addClass('editing'); 38 | } 39 | 40 | if (params.hasOwnProperty('state') && params.state === 'browse') { 41 | $('.create-ui-toolbar-wrapper') 42 | .removeClass('editing'); 43 | } 44 | } 45 | }); 46 | 47 | if (cmfCreateBrowseUrl) { 48 | window.CKEDITOR.config.filebrowserBrowseUrl = cmfCreateBrowseUrl; 49 | } 50 | 51 | window.CKEDITOR.basePath = window.CKEDITOR_BASEPATH; 52 | }); 53 | -------------------------------------------------------------------------------- /src/Resources/public/js/init-create-common.js: -------------------------------------------------------------------------------- 1 | jQuery(document).ready(function() { 2 | jQuery('body').midgardCreate('configureEditor', 'title', 'editWidget', { 3 | }); 4 | 5 | jQuery('body').midgardCreate('widget').midgardWorkflows('setActionType', 'confirm_destroy', function (model, workflow, callback) { 6 | jQuery('body').midgardNotifications('create', { 7 | bindTo: jQuery('#midgardcreate-workflow_delete'), 8 | gravity: 'T', 9 | body: 'Delete ' + model.getSubjectUri() + '?', 10 | timeout: 0, 11 | actions: [ 12 | { name: 'Yes', label: 'Yes', cb: function () { 13 | jQuery('body').midgardCreate('widget').midgardStorage('saveRemote', model, { success: function(m, response) { 14 | m.destroy(); 15 | }}); 16 | }, className: 'create-ui-btn' }, 17 | { name: 'No', label: 'No', cb: function () { }, className: 'create-ui-btn' } 18 | ] 19 | }) 20 | }); 21 | 22 | jQuery(cmfCreatePlainTextTypes).each(function(index, value) { 23 | jQuery('body').midgardCreate('setEditorForProperty', value, 'title'); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/Resources/public/js/init-create-hallo.js: -------------------------------------------------------------------------------- 1 | jQuery(document).ready(function() { 2 | jQuery('body').midgardCreate({ 3 | url: function() { 4 | if (this.id) { 5 | if (this.id.charAt(0) == "<") { 6 | return cmfCreatePutDocument + this.id.substring(1, this.id.length - 1); 7 | } 8 | return cmfCreatePutDocument + this.id; 9 | } 10 | return cmfCreatePutDocument; 11 | }, 12 | workflows: { 13 | url: function(model) { 14 | return cmfCreateWorkflows + model.getSubjectUri(); 15 | } 16 | }, 17 | stanbolUrl: cmfCreateStanbolUrl, 18 | tags: true 19 | }); 20 | 21 | jQuery('body').midgardCreate('configureEditor', 'default', 'halloWidget', { 22 | plugins: { 23 | 'halloformat': {'formattings': {'strikeThrough': false, 'underline': false}}, 24 | 'halloblock': {}, 25 | 'hallolists': {'lists': {'ordered': false}}, 26 | 'hallojustify': {}, 27 | 'halloimage': { 28 | search: function (query, limit, offset, successCallback) { 29 | limit = limit || 8; 30 | offset = offset || 0; 31 | jQuery.ajax({ 32 | type: "GET", 33 | url: cmfCreateImageSearch, 34 | data: "query="+query+"&offset="+offset+"&limit="+limit, 35 | success: successCallback 36 | }); 37 | }, 38 | // TODO: this only brings an empty suggestions tab instead of calling the function 39 | // suggestions: function(tags, limit, offset, successCallback) { 40 | // limit = limit || 8; 41 | // offset = offset || 0; 42 | // return jQuery.ajax({ 43 | // type: "GET", 44 | // url: "/app_dev.php/symfony-cmf/vie/assets/list/", 45 | // data: "tags=" + tags + "&offset=" + offset + "&limit=" + limit, 46 | // success: successCallback 47 | // }); 48 | // }, 49 | uploadUrl: cmfCreateImageUpload, 50 | 'vie': this.vie 51 | }, 52 | 'hallolink': { 'relatedUrl': cmfCreateLinkRelatedPath }, 53 | 'hallooverlay': {}, 54 | 'halloindicator': {} 55 | }, 56 | toolbarState: cmfCreateHalloFixedToolbar, 57 | parentElement: cmfCreateHalloParentElement 58 | }); 59 | 60 | 61 | jQuery('body').bind('halloenabled', null, function () { 62 | $('.create-ui-toolbar-wrapper') 63 | .addClass('editing'); 64 | }); 65 | 66 | jQuery('body').bind('hallodisabled', null, function () { 67 | $('.create-ui-toolbar-wrapper') 68 | .removeClass('editing'); 69 | }); 70 | }); 71 | -------------------------------------------------------------------------------- /src/Resources/public/vendor/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /src/Resources/views/includecssfiles.html.twig: -------------------------------------------------------------------------------- 1 | {% stylesheets filter='cssrewrite' 2 | 'bundles/cmfcreate/vendor/create/themes/midgard-tags/tags.css' 3 | 'bundles/cmfcreate/vendor/create/themes/create-ui/css/create-ui.css' 4 | 'bundles/cmfcreate/vendor/create/examples/font-awesome/css/font-awesome.css' 5 | 'bundles/cmfcreate/vendor/create/themes/midgard-notifications/midgardnotif.css' 6 | 7 | 'bundles/cmfcreate/css/halloCmfStyle.css' 8 | 'bundles/cmfcreate/css/createStyle.css' 9 | 'bundles/cmfcreate/css/overlay.css' 10 | 11 | %} 12 | 13 | {% endstylesheets %} 14 | -------------------------------------------------------------------------------- /src/Resources/views/includejsfiles-ckeditor.html.twig: -------------------------------------------------------------------------------- 1 | {% include "CmfCreateBundle::includejsfiles-create.html.twig" %} 2 | 3 | 4 | {% javascripts output="js/ckeditor.js" 5 | '@CmfCreateBundle/Resources/public/vendor/ckeditor/ckeditor.js' 6 | '@CmfCreateBundle/Resources/public/js/init-create-ckeditor.js' 7 | '@CmfCreateBundle/Resources/public/js/init-create-common.js' 8 | %} 9 | 10 | {% endjavascripts %} 11 | -------------------------------------------------------------------------------- /src/Resources/views/includejsfiles-create.html.twig: -------------------------------------------------------------------------------- 1 | {# basic js files needed for vie #} 2 | 3 | 23 | 24 | {% javascripts output="js/create.js" 25 | '@CmfCreateBundle/Resources/public/vendor/create/lib/jquery/jquery.js' 26 | '@CmfCreateBundle/Resources/public/vendor/create/lib/jquery-ui/jquery-ui.js' 27 | '@CmfCreateBundle/Resources/public/vendor/create/lib/underscore/underscore.js' 28 | '@CmfCreateBundle/Resources/public/vendor/create/lib/backbone/backbone.js' 29 | '@CmfCreateBundle/Resources/public/vendor/create/lib/rangy/rangy-core.js' 30 | '@CmfCreateBundle/Resources/public/vendor/create/lib/vie/vie.js' 31 | '@CmfCreateBundle/Resources/public/vendor/create/lib/jquery-rdfquery/jquery.rdfquery.core.js' 32 | '@CmfCreateBundle/Resources/public/vendor/create/lib/jquery-rdfquery/jquery.rdfquery.rules.js' 33 | '@CmfCreateBundle/Resources/public/vendor/create/lib/jquery.tagsinput/jquery.tagsinput.js' 34 | '@CmfCreateBundle/Resources/public/vendor/create/lib/annotate/annotate.js' 35 | 36 | '@CmfCreateBundle/Resources/public/vendor/create/dist/create.js' 37 | %} 38 | 39 | {% endjavascripts %} 40 | 41 | {# 42 | to develop create use this instead of create-min 43 | '@CmfCreateBundle/Resources/public/vendor/create/src/*.js' 44 | 45 | to develop on vie, clone the vie bundle into vendor and add the following instead of vie-min.js 46 | (explicitly listed as the order is relevant) 47 | '@CmfCreateBundle/Resources/public/vendor/vie/lib/rdfquery/latest/jquery.rdfquery.debug.js' 48 | '@CmfCreateBundle/Resources/public/vendor/vie/src/VIE.js' 49 | '@CmfCreateBundle/Resources/public/vendor/vie/src/Able.js' 50 | '@CmfCreateBundle/Resources/public/vendor/vie/src/Util.js' 51 | '@CmfCreateBundle/Resources/public/vendor/vie/src/Entity.js' 52 | '@CmfCreateBundle/Resources/public/vendor/vie/src/Collection.js' 53 | '@CmfCreateBundle/Resources/public/vendor/vie/src/Type.js' 54 | '@CmfCreateBundle/Resources/public/vendor/vie/src/Attribute.js' 55 | '@CmfCreateBundle/Resources/public/vendor/vie/src/Namespace.js' 56 | '@CmfCreateBundle/Resources/public/vendor/vie/src/Classic.js' 57 | '@CmfCreateBundle/Resources/public/vendor/vie/src/service/*.js' 58 | '@CmfCreateBundle/Resources/public/vendor/vie/src/view/*.js' 59 | 60 | to develop on hallo, clone the hallo bundle into vendor and add the following instead of hallo.js 61 | and set up assetic to handle coffee script files 62 | '@CmfCreateBundle/Resources/public/js/init-vie-hallo.js' 63 | '@CmfCreateBundle/Resources/public/vendor/hallo/hallo.coffee' 64 | '@CmfCreateBundle/Resources/public/vendor/hallo/plugins/*.coffee' 65 | #} 66 | -------------------------------------------------------------------------------- /src/Resources/views/includejsfiles-hallo-coffee.html.twig: -------------------------------------------------------------------------------- 1 | {% include "CmfCreateBundle::includejsfiles-create.html.twig" %} 2 | 3 | {# hallo.js is already included in the create deps #} 4 | {% javascripts output="js/hallo-coffee.js" 5 | '@CmfCreateBundle/Resources/public/js/init-create-hallo.js' 6 | '@CmfCreateBundle/Resources/public/vendor/hallo/src/hallo.coffee' 7 | '@CmfCreateBundle/Resources/public/vendor/hallo/src/toolbar/fixed.coffee' 8 | '@CmfCreateBundle/Resources/public/vendor/hallo/src/widgets/*.coffee' 9 | '@CmfCreateBundle/Resources/public/vendor/hallo/src/plugins/*.coffee' 10 | '@CmfCreateBundle/Resources/public/vendor/hallo/src/plugins/image/*.coffee' 11 | %} 12 | 13 | {% endjavascripts %} 14 | -------------------------------------------------------------------------------- /src/Resources/views/includejsfiles-hallo.html.twig: -------------------------------------------------------------------------------- 1 | {% include "CmfCreateBundle::includejsfiles-create.html.twig" %} 2 | 3 | 12 | 13 | {# hallo.js is already included in the create deps #} 14 | {% javascripts output="js/hallo-extra.js" 15 | '@CmfCreateBundle/Resources/public/vendor/create/lib/jquery-htmlclean/jquery.htmlClean.js' 16 | '@CmfCreateBundle/Resources/public/vendor/create/lib/hallo/hallo.js' 17 | '@CmfCreateBundle/Resources/public/js/init-create-hallo.js' 18 | '@CmfCreateBundle/Resources/public/js/init-create-common.js' 19 | %} 20 | 21 | {% endjavascripts %} 22 | -------------------------------------------------------------------------------- /src/Security/AccessCheckerInterface.php: -------------------------------------------------------------------------------- 1 | requiredRole = $requiredRole; 65 | $this->tokenStorage = $tokenStorage; 66 | $this->authorizationChecker = $authorizationChecker; 67 | $this->logger = $logger; 68 | } 69 | 70 | /** 71 | * Actions may be performed if there is a securityContext having a token 72 | * and granting the required role. 73 | * 74 | * {@inheritdoc} 75 | */ 76 | public function check(Request $request) 77 | { 78 | try { 79 | return $this->tokenStorage && $this->authorizationChecker 80 | && $this->tokenStorage->getToken() 81 | && $this->authorizationChecker->isGranted($this->requiredRole) 82 | ; 83 | } catch (\Exception $e) { 84 | if ($this->logger) { 85 | $this->logger->error($e, array('exception' => $e)); 86 | } 87 | // ignore and return false 88 | } 89 | 90 | return false; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/Workflow/DoctrinePhpcrDeleteWorkflow.php: -------------------------------------------------------------------------------- 1 | 24 | */ 25 | class DoctrinePhpcrDeleteWorkflow implements WorkflowInterface 26 | { 27 | /** 28 | * @var ObjectManager 29 | */ 30 | protected $om; 31 | 32 | public function __construct(ManagerRegistry $registry, $name = null) 33 | { 34 | $this->om = $registry->getManager($name); 35 | } 36 | 37 | /** 38 | * Get toolbar config for the given object, if the workflow is applicable 39 | * and allowed. 40 | * 41 | * @see http://createjs.org/guide/#workflows 42 | * 43 | * @param mixed $object 44 | * 45 | * @return array|null array to return for this workflow, or null if 46 | * workflow is not allowed 47 | */ 48 | public function getToolbarConfig($object) 49 | { 50 | return array( 51 | 'name' => 'delete', 52 | 'label' => 'delete', 53 | 'action' => array( 54 | 'type' => 'confirm_destroy', 55 | ), 56 | 'type' => 'button', 57 | ); 58 | } 59 | 60 | /** 61 | * Execute this workflow. 62 | * 63 | * The object will only be set if there is a subject parameter in $_GET 64 | * that can be found by the mapper tied to the RestService. 65 | * 66 | * @param mixed $object 67 | * 68 | * @return array 69 | */ 70 | public function run($object) 71 | { 72 | $this->om->remove($object); 73 | $this->om->flush(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /tests/Unit/Security/AlwaysAllowCheckerTest.php: -------------------------------------------------------------------------------- 1 | prophesize('Symfony\Component\HttpFoundation\Request'); 21 | 22 | $checker = new AlwaysAllowChecker(); 23 | $this->assertTrue($checker->check($request->reveal())); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/Unit/Security/RoleAccessCheckerTest.php: -------------------------------------------------------------------------------- 1 | request = $this->prophesize('Symfony\Component\HttpFoundation\Request')->reveal(); 26 | $this->tokenStorage = $this->prophesize('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); 27 | $this->authorizationChecker = $this->prophesize('Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface'); 28 | $this->checker = new RoleAccessChecker('THE_ROLE', $this->tokenStorage->reveal(), $this->authorizationChecker->reveal()); 29 | } 30 | 31 | public function testFalseWithoutSecurityServices() 32 | { 33 | $checker = new RoleAccessChecker('THE_ROLE'); 34 | $this->assertFalse($checker->check($this->request), 'Always false without token storage'); 35 | 36 | $checker = new RoleAccessChecker('THE_ROLE', $this->tokenStorage->reveal()); 37 | $this->assertFalse($checker->check($this->request), 'Always false without authorization checker'); 38 | } 39 | 40 | public function testFalseWithoutTokenAvailable() 41 | { 42 | $this->assertFalse($this->checker->check($this->request)); 43 | } 44 | 45 | public function testGranted() 46 | { 47 | $token = $this->prophesize('Symfony\Component\Security\Authentication\Token\TokenInterface')->reveal(); 48 | $this->tokenStorage->getToken()->willReturn($token); 49 | $this->authorizationChecker->isGranted('THE_ROLE')->willReturn(true); 50 | 51 | $this->assertTrue($this->checker->check($this->request)); 52 | } 53 | 54 | public function testNotGranted() 55 | { 56 | $token = $this->prophesize('Symfony\Component\Security\Authentication\Token\TokenInterface')->reveal(); 57 | $this->tokenStorage->getToken()->willReturn($token); 58 | $this->authorizationChecker->isGranted('THE_ROLE')->willReturn(false); 59 | 60 | $this->assertFalse($this->checker->check($this->request)); 61 | } 62 | 63 | public function testException() 64 | { 65 | $token = $this->prophesize('Symfony\Component\Security\Authentication\Token\TokenInterface')->reveal(); 66 | $this->tokenStorage->getToken()->willReturn($token); 67 | $this->authorizationChecker->isGranted('THE_ROLE')->willThrow(new \Exception()); 68 | 69 | $this->assertFalse($this->checker->check($this->request)); 70 | } 71 | } 72 | --------------------------------------------------------------------------------