Skip to content

Commit

Permalink
Implemented multipage articles (#122)
Browse files Browse the repository at this point in the history
* Implemented page document and API (#114)

* implemented basic page document

* added index pages to article

* fixed serialization context of article and article-page (#118)

* Add interface to manage article-pages (#116)

* introduced css grunt job

* added article-router

* added page dropdown

* added logic to create and update pages

* renamed adapter

* Added article title to page form (#123)

* added article title

* fixed selector for css stye

* fixed jquery selector of grid-row

* added page to content-navigation (#125)

* Fixed create article from ghost (#126)

* fixed create article from ghost

* hide new page link for new articls

* fixed code style

* added delete page button (#132)

* added translations (#128)

* added route-behavior to article-page (#131)

* Fixed priorities of subscriber (#137)

* fixed priorities of subscriber

* added tag to find routePath property

* Fixed title property (article-title) and add page title property (#141)

* fixed title property (article-title) and add page title property

* added node-name-slugifier

* Changed generating route only on publish (#138)

* use publish event to generate routes

* refactored because of sulu changes

* Added page-number argument to website-article-controller (#142)

* added serialization of pages

* added pages data to article-document

* fixed comments

* Added synchronize children between draft and live (#139)

* added synchronice children between draft and live

* fixed preview for new pages

* fixed serialization for preview

* fixed testcases

* Fixed versioning and remove-draft of article-pages (#145)

* fixed versioning of article-pages

* added upgrade note

* added constraint for jackalope/jackalope

* implemented duplicate article (#146)

* Fixed preview-serialization of article pages (#154)

* fixed preview-serialization of article pages

* change view of renderArticle

* fixed type change on list (#156)

* Fixed metadata for article to sync remove (#155)

* fixed metadata for article

* fixed routable-subscriber to remove all routes (locales)

* removed article-page copy locale (#157)

* fixed code-style

* fixed test-setup
  • Loading branch information
wachterjohannes authored and alexander-schranz committed Apr 25, 2017
1 parent 4cd0e89 commit ff79b7f
Show file tree
Hide file tree
Showing 94 changed files with 5,773 additions and 543 deletions.
9 changes: 5 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@ matrix:
include:
- php: 5.5
env:
- SULU_VERSION="~1.5.3"
# - SULU_VERSION="~1.6.0"
- COMPOSER_FLAGS="--prefer-lowest --prefer-dist --no-interaction"
- ES_VERSION="2.4.4"
- ES_DOWNLOAD_URL="https://download.elastic.co/elasticsearch/elasticsearch/elasticsearch-${ES_VERSION}.zip"
- php: 7.0
env:
- COMPOSER_FLAGS="--prefer-dist --no-interaction"
- SULU_VERSION="dev-develop"
# - SULU_VERSION="dev-develop"
- CODE_COVERAGE="--coverage-clover=coverage.clover"
- php: 7.0
env:
- COMPOSER_FLAGS="--prefer-dist --no-interaction"
- SULU_VERSION="~1.5.3"
# - SULU_VERSION="~1.6.0"
- SYMFONY__PHPCR__TRANSPORT=jackrabbit
addons:
apt:
Expand All @@ -58,7 +58,8 @@ before_install:
- ./elasticsearch-*/bin/elasticsearch -d

install:
- travis_retry composer require sulu/sulu:$SULU_VERSION $COMPOSER_FLAGS
# - travis_retry composer require sulu/sulu:$SULU_VERSION $COMPOSER_FLAGS
- travis_retry composer update $COMPOSER_FLAGS
- composer info -i
- ./Tests/app/console doctrine:database:create
- ./Tests/app/console doctrine:schema:update --force
Expand Down
8 changes: 7 additions & 1 deletion Admin/ArticleContentNavigationProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@ class ArticleContentNavigationProvider implements ContentNavigationProviderInter
public function getNavigationItems(array $options = [])
{
$details = new ContentNavigationItem('sulu_article.edit.details');
$details->setAction('details');

$action = 'details';
if (array_key_exists('page', $options) && (int) $options['page'] !== 1) {
$action = 'page:' . $options['page'] . '/' . $action;
}

$details->setAction($action);
$details->setPosition(10);
$details->setComponent('articles/edit/details@suluarticle');

Expand Down
2 changes: 1 addition & 1 deletion Content/ArticleSelectionContentType.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
use Sulu\Component\Content\SimpleContentType;

/**
* This class provides article selection.
* Provides article_selection content-type.
*/
class ArticleSelectionContentType extends SimpleContentType
{
Expand Down
36 changes: 30 additions & 6 deletions Controller/ArticleController.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
use Sulu\Component\Rest\ListBuilder\ListRepresentation;
use Sulu\Component\Rest\RequestParametersTrait;
use Sulu\Component\Rest\RestController;
use Sulu\Component\Security\Authorization\PermissionTypes;
use Sulu\Component\Security\Authorization\SecurityCondition;
use Sulu\Component\Security\SecuredControllerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
Expand Down Expand Up @@ -204,7 +206,9 @@ public function getAction($uuid, Request $request)

return $this->handleView(
$this->view($document)->setSerializationContext(
SerializationContext::create()->setSerializeNull(true)->setGroups(['defaultPage'])
SerializationContext::create()
->setSerializeNull(true)
->setGroups(['defaultPage', 'defaultArticle', 'smallArticlePage'])
)
);
}
Expand All @@ -229,7 +233,9 @@ public function postAction(Request $request)

return $this->handleView(
$this->view($document)->setSerializationContext(
SerializationContext::create()->setSerializeNull(true)->setGroups(['defaultPage'])
SerializationContext::create()
->setSerializeNull(true)
->setGroups(['defaultPage', 'defaultArticle', 'smallArticlePage'])
)
);
}
Expand Down Expand Up @@ -265,7 +271,9 @@ public function putAction(Request $request, $uuid)

return $this->handleView(
$this->view($document)->setSerializationContext(
SerializationContext::create()->setSerializeNull(true)->setGroups(['defaultPage'])
SerializationContext::create()
->setSerializeNull(true)
->setGroups(['defaultPage', 'defaultArticle', 'smallArticlePage'])
)
);
}
Expand Down Expand Up @@ -345,7 +353,19 @@ public function postTriggerAction($uuid, Request $request)
break;
case 'copy-locale':
$destLocales = $this->getRequestParameter($request, 'dest', true);
$data = $this->getMapper()->copyLanguage($uuid, $userId, null, $locale, explode(',', $destLocales));
$destLocales = explode(',', $destLocales);

$securityChecker = $this->get('sulu_security.security_checker');
foreach ($destLocales as $destLocale) {
$securityChecker->checkPermission(
new SecurityCondition($this->getSecurityContext(), $destLocale),
PermissionTypes::EDIT
);
}

$this->getMapper()->copyLanguage($uuid, $userId, null, $locale, $destLocales);

$data = $this->getDocumentManager()->find($uuid, $locale);
break;
case 'copy':
/** @var ArticleDocument $document */
Expand All @@ -360,8 +380,12 @@ public function postTriggerAction($uuid, Request $request)
}

// prepare view
$view = $this->view($data, $data !== null ? 200 : 204);
$view->setSerializationContext(SerializationContext::create()->setGroups(['defaultPage']));
$view = $this->view($data);
$view->setSerializationContext(
SerializationContext::create()
->setSerializeNull(true)
->setGroups(['defaultPage', 'defaultArticle', 'smallArticlePage'])
);
} catch (RestException $exc) {
$view = $this->view($exc->toArray(), 400);
}
Expand Down
259 changes: 259 additions & 0 deletions Controller/ArticlePageController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
<?php

/*
* This file is part of Sulu.
*
* (c) MASSIVE ART WebServices GmbH
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Sulu\Bundle\ArticleBundle\Controller;

use FOS\RestBundle\Routing\ClassResourceInterface;
use JMS\Serializer\SerializationContext;
use Sulu\Bundle\ArticleBundle\Admin\ArticleAdmin;
use Sulu\Bundle\ArticleBundle\Document\ArticlePageDocument;
use Sulu\Bundle\ArticleBundle\Document\Form\ArticlePageDocumentType;
use Sulu\Bundle\ArticleBundle\Exception\ArticlePageNotFoundException;
use Sulu\Bundle\ArticleBundle\Exception\ParameterNotAllowedException;
use Sulu\Component\Content\Form\Exception\InvalidFormException;
use Sulu\Component\Content\Mapper\ContentMapperInterface;
use Sulu\Component\DocumentManager\DocumentManagerInterface;
use Sulu\Component\Rest\Exception\MissingParameterException;
use Sulu\Component\Rest\RequestParametersTrait;
use Sulu\Component\Rest\RestController;
use Sulu\Component\Security\SecuredControllerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
* Provides API for article-pages.
*/
class ArticlePageController extends RestController implements ClassResourceInterface, SecuredControllerInterface
{
const DOCUMENT_TYPE = 'article_page';

use RequestParametersTrait;

/**
* Returns single article-page.
*
* @param string $articleUuid
* @param string $uuid
* @param Request $request
*
* @return Response
*
* @throws ArticlePageNotFoundException
*/
public function getAction($articleUuid, $uuid, Request $request)
{
$locale = $this->getRequestParameter($request, 'locale', true);
$document = $this->getDocumentManager()->find(
$uuid,
$locale,
[
'load_ghost_content' => true,
'load_shadow_content' => false,
]
);

if ($articleUuid !== $document->getParent()->getUuid()) {
// it is required that the parent will be called to resolve the proxy.
// this wont be done in the serialization process.

throw new ArticlePageNotFoundException($uuid, $articleUuid);
}

return $this->handleView(
$this->view($document)->setSerializationContext(
SerializationContext::create()
->setSerializeNull(true)
->setGroups(['defaultPage', 'defaultArticlePage', 'smallArticle'])
)
);
}

/**
* Create article-page.
*
* @param string $articleUuid
* @param Request $request
*
* @return Response
*/
public function postAction($articleUuid, Request $request)
{
$action = $request->get('action');
$document = $this->getDocumentManager()->create(self::DOCUMENT_TYPE);
$locale = $this->getRequestParameter($request, 'locale', true);
$data = $request->request->all();

$this->persistDocument($data, $document, $locale, $articleUuid);
$this->handleActionParameter($action, $document->getParent(), $locale);
$this->getDocumentManager()->flush();

return $this->handleView(
$this->view($document)->setSerializationContext(
SerializationContext::create()
->setSerializeNull(true)
->setGroups(['defaultPage', 'defaultArticlePage', 'smallArticle'])
)
);
}

/**
* Update article-page.
*
* @param string $articleUuid
* @param string $uuid
* @param Request $request
*
* @return Response
*/
public function putAction($articleUuid, $uuid, Request $request)
{
$locale = $this->getRequestParameter($request, 'locale', true);
$action = $request->get('action');
$data = $request->request->all();

$document = $this->getDocumentManager()->find(
$uuid,
$locale,
[
'load_ghost_content' => false,
'load_shadow_content' => false,
]
);

$this->get('sulu_hash.request_hash_checker')->checkHash($request, $document, $document->getUuid());

$this->persistDocument($data, $document, $locale, $articleUuid);
$this->handleActionParameter($action, $document->getParent(), $locale);
$this->getDocumentManager()->flush();

return $this->handleView(
$this->view($document)->setSerializationContext(
SerializationContext::create()
->setSerializeNull(true)
->setGroups(['defaultPage', 'defaultArticlePage', 'smallArticle'])
)
);
}

/**
* Delete article-page.
*
* @param string $articleUuid
* @param string $uuid
* @param Request $request
*
* @return Response
*/
public function deleteAction($articleUuid, $uuid, Request $request)
{
$locale = $this->getRequestParameter($request, 'locale', true);

$documentManager = $this->getDocumentManager();
$document = $documentManager->find($uuid, $locale);
$documentManager->remove($document);
$documentManager->flush();

return $this->handleView($this->view(null));
}

/**
* {@inheritdoc}
*/
public function getSecurityContext()
{
return ArticleAdmin::SECURITY_CONTEXT;
}

/**
* Persists the document using the given information.
*
* @param array $data
* @param object $document
* @param string $locale
* @param string $articleUuid
*
* @throws InvalidFormException
* @throws MissingParameterException
* @throws ParameterNotAllowedException
*/
private function persistDocument($data, $document, $locale, $articleUuid)
{
if (array_key_exists('title', $data)) {
throw new ParameterNotAllowedException('title', ArticlePageDocument::class);
}

$article = $this->getDocumentManager()->find($articleUuid, $locale);
if (!array_key_exists('template', $data)) {
$data['template'] = $article->getStructureType();
}

$form = $this->createForm(
ArticlePageDocumentType::class,
$document,
[
// disable csrf protection, since we can't produce a token, because the form is cached on the client
'csrf_protection' => false,
]
);
$form->submit($data, false);

$document->setParent($article);

if (!$form->isValid()) {
throw new InvalidFormException($form);
}

$this->getDocumentManager()->persist(
$document,
$locale,
[
'user' => $this->getUser()->getId(),
'clear_missing_content' => false,
'auto_name' => false,
'auto_rename' => false,
]
);
}

/**
* Returns document-manager.
*
* @return DocumentManagerInterface
*/
protected function getDocumentManager()
{
return $this->get('sulu_document_manager.document_manager');
}

/**
* @return ContentMapperInterface
*/
protected function getMapper()
{
return $this->get('sulu.content.mapper');
}

/**
* Delegates actions by given actionParameter, which can be retrieved from the request.
*
* @param string $actionParameter
* @param object $document
* @param string $locale
*/
private function handleActionParameter($actionParameter, $document, $locale)
{
switch ($actionParameter) {
case 'publish':
$this->getDocumentManager()->publish($document, $locale);
break;
}
}
}
Loading

0 comments on commit ff79b7f

Please sign in to comment.