diff --git a/Controller/DefaultController.php b/Controller/DefaultController.php index a66abbb..985d06a 100644 --- a/Controller/DefaultController.php +++ b/Controller/DefaultController.php @@ -9,6 +9,7 @@ Soloist\Bundle\CoreBundle\Entity\Node; use Symfony\Bundle\FrameworkBundle\Controller\Controller; + class DefaultController extends Controller { public function indexAction() @@ -53,4 +54,5 @@ public function pageShortcutAction($page, $path_image, $description) 'description' => $description, ); } + } diff --git a/Controller/NavigationController.php b/Controller/NavigationController.php index f5feaa4..e144dd7 100644 --- a/Controller/NavigationController.php +++ b/Controller/NavigationController.php @@ -3,7 +3,8 @@ namespace Soloist\Bundle\CoreBundle\Controller; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; -use Soloist\Bundle\CoreBundle\Entity\Node; +use Soloist\Bundle\CoreBundle\Entity\Node, + DoctrineExtensions\Taggable\Taggable; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class NavigationController extends Controller @@ -41,4 +42,34 @@ public function showPartAction($node, $depth = null) 'current' => $node ); } + + /** + * Show similars elements + * + * @param Taggable $node + * @return Respons + */ + public function showSimilarAction(Taggable $node) + { + if (!$node instanceof Taggable) { + throw new InvalidArgumentException('Sorry ! I need tags to search similar content. Therefore your element must implements "DoctrineExtensions\Taggable\Taggable".'); + } + $type = $node->getType(); + + if ($type != 'page') { + throw new InvalidArgumentException('Sorry ! This node is currently not supported.'); + } + + $tagManager = $this->get('fpn_tag.tag_manager'); + $tagManager->loadTagging($node); + + $em = $this->getDoctrine()->getManager(); + $repo = $em->getRepository('SoloistCoreBundle:Node'); + + $similarElements = $repo->getSimilarResults($node); + + return $this->render('SoloistCoreBundle:Navigation:Similar/'. $type . '.html.twig', array( + 'nodes' => $similarElements + )); + } } diff --git a/Entity/Node.php b/Entity/Node.php index 91c0a23..198ff99 100644 --- a/Entity/Node.php +++ b/Entity/Node.php @@ -224,4 +224,20 @@ public function getUpdatedAt() public function postLoad() { } + + public function getGlobalId() + { + return 'core-' . $this->getType() . '-' . $this->getId(); + } + + /** + * Get tag type + * This method is a part of the Taggable interface + * + * @return string + */ + public function getTaggableType() + { + return 'soloist_node'; + } } diff --git a/Entity/Page.php b/Entity/Page.php index 1a4bcb2..4f17061 100644 --- a/Entity/Page.php +++ b/Entity/Page.php @@ -3,8 +3,9 @@ namespace Soloist\Bundle\CoreBundle\Entity; use Doctrine\Common\Collections\ArrayCollection; +use DoctrineExtensions\Taggable\Taggable; -class Page extends Node +class Page extends Node implements Taggable { /** @@ -27,9 +28,22 @@ class Page extends Node */ protected $blocks; + /** + * Tags managed by FPNTagBundle + * @var \Doctrine\Common\Collections\Collection + */ + protected $tags; + + /** + * Tas as text + * @var string + */ + public $tagsAsText; + public function __construct() { $this->blocks = new ArrayCollection; + $this->tags = new ArrayCollection; } /** @@ -113,4 +127,24 @@ public function postLoad() $this->blocks = $blocks; } + /** + * Get tags + * @return ArrayCollection + */ + public function getTags() + { + $this->tags = $this->tags ?: new ArrayCollection(); + + return $this->tags; + } + + /** + * Get id of the current entity + * @return integer + */ + public function getTaggableId() + { + return $this->getId(); + } + } diff --git a/Entity/Repository/Node.php b/Entity/Repository/Node.php index 70af8d2..aaf2df4 100644 --- a/Entity/Repository/Node.php +++ b/Entity/Repository/Node.php @@ -4,6 +4,9 @@ use Doctrine\ORM\Query\Expr; use Gedmo\Tree\Entity\Repository\NestedTreeRepository; +use DoctrineExtensions\Taggable\Taggable; + +use Doctrine\ORM\Query\ResultSetMappingBuilder; class Node extends NestedTreeRepository { @@ -27,4 +30,63 @@ public function findRoot() ->getSingleResult() ; } + + /** + * Get similar results + * NEED a taggable node + * Sql draft available here: https://gist.github.com/3105206/70ab5aaa6654890433d8e5d9671f320a695d3627 + * Notice that the only node who will work is tha page + * + * @param Taggable $resource + * @param integer $limit + * @return array + */ + public function getSimilarResults(Taggable $resource, $limit = 5) + { + $tagsList = ''; + $count = $resource->getTags()->count(); + + if ($count < 1) { + return array(); + } + + foreach ($resource->getTags() as $tag) { + if (!empty($tagsList)) { + $tagsList .= ', '; + } + $tagsList .= '\'' . $tag->getSlug() . '\''; + } + + $part = << 0); + + + $sql .= "\n" . 'LIMIT ' . $limit; + + $rsm = new ResultSetMappingBuilder($this->_em); + $rsm->addRootEntityFromClassMetadata('SoloistCoreBundle:Node', 'n'); + + $query = $this->_em->createNativeQuery($sql, $rsm); + + return $query->getResult(); + } } diff --git a/Entity/Tag.php b/Entity/Tag.php new file mode 100644 index 0000000..18af0a6 --- /dev/null +++ b/Entity/Tag.php @@ -0,0 +1,10 @@ +em = $em; + } + /** + * Listen to the RequestCategories event from blog bundle + * + * @param \Soloist\Bundle\BlogBundle\EventListener\Event\RequestCategories $event + */ + public function onRequestCategories(RequestCategories $event) + { + $repo = $this->em->getRepository('SoloistCoreBundle:Category'); + $categories = $repo->findAll(); + + foreach($categories as $category) { + $event->addCategory($category->getGlobalId(), $category->getTitle()); + } + } +} diff --git a/Form/Handler/Node.php b/Form/Handler/Node.php index aaae3c4..798a1bc 100644 --- a/Form/Handler/Node.php +++ b/Form/Handler/Node.php @@ -7,7 +7,9 @@ use Symfony\Component\HttpFoundation\Request, Symfony\Component\Form\FormFactory, - Symfony\Component\Form\Form; + Symfony\Component\Form\Form, + FPN\TagBundle\Entity\TagManager, + DoctrineExtensions\Taggable\Taggable; use Soloist\Bundle\CoreBundle\Node\Factory as NodeFactory, Soloist\Bundle\CoreBundle\Entity\Node as NodeEntity, @@ -31,20 +33,39 @@ class Node */ protected $nodeFactory; - public function __construct(NodeFactory $nodeFactory, EntityManager $em, FormFactory $factory) + /** + * @var FPN\TagBundle\Entity\TagManager + */ + protected $tagManager; + + public function __construct(NodeFactory $nodeFactory, EntityManager $em, FormFactory $factory, TagManager $tagManager) { $this->em = $em; $this->factory = $factory; $this->nodeFactory = $nodeFactory; + $this->tagManager = $tagManager; } public function create(Form $form, Request $request) { $form->bindRequest($request); + if ($form->isValid()) { - $this->em->persist($form->getData()); + $data = $form->getData(); + + if ($data instanceof Taggable) { + + $tags = $this->tagManager->splitTagNames($data->tagsAsText); + + $tags = $this->tagManager->loadOrCreateTags($tags); + $this->tagManager->addTags($tags, $data); + } + + $this->em->persist($data); $this->em->flush(); + $tagManager->saveTagging($data); + return true; } @@ -53,10 +74,25 @@ public function create(Form $form, Request $request) public function update(Form $form, Request $request) { + $data = $form->getData(); + $form->bindRequest($request); if ($form->isValid()) { + + // if entity is taggable, we should remove old tags + // and add new + if ($data instanceof Taggable) { + + $tags = $this->tagManager->splitTagNames($data->tagsAsText); + + $tags = $this->tagManager->loadOrCreateTags($tags); + $this->tagManager->addTags($tags, $data); + } + $this->em->flush(); + $tagManager->saveTagging($data); + return true; } @@ -66,6 +102,19 @@ public function update(Form $form, Request $request) public function getCreateForm($type, $pageType = null) { $node = $this->nodeFactory->getNode($type, $pageType); + + if ($node instanceof Taggable) { + $this->tagManager->loadTagging($node); + $text = ''; + foreach($node->getTags() as $tag) { + if($text !== '') { + $text .= ', '; + } + $text .= $tag->getSlug(); + } + $node->tagsAsText = $text; + } + $form = $this->nodeFactory->getFormType($type); return $this->factory->create($form, $node); diff --git a/Form/Type/PageType.php b/Form/Type/PageType.php index d31fba4..14954e3 100644 --- a/Form/Type/PageType.php +++ b/Form/Type/PageType.php @@ -37,6 +37,7 @@ public function buildForm(FormBuilderInterface $builder, array $options) 'choice_list' => new SimpleChoiceList($this->factory->getPageTypes()) )) ->add('blocks', new BlockCollectionType, array('block_factory' => $this->factory)) + ->add('tagsAsText', 'text') ; } diff --git a/Resources/config/doctrine/Tag.orm.xml b/Resources/config/doctrine/Tag.orm.xml new file mode 100644 index 0000000..5c33129 --- /dev/null +++ b/Resources/config/doctrine/Tag.orm.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/Resources/config/doctrine/Tagging.orm.xml b/Resources/config/doctrine/Tagging.orm.xml new file mode 100644 index 0000000..33a6479 --- /dev/null +++ b/Resources/config/doctrine/Tagging.orm.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/Resources/config/services.xml b/Resources/config/services.xml index d6e4ca5..5dd4eae 100644 --- a/Resources/config/services.xml +++ b/Resources/config/services.xml @@ -16,6 +16,7 @@ Soloist\Bundle\CoreBundle\Twig\Extension Soloist\Bundle\CoreBundle\Form\Type\JsonArrayType Soloist\Bundle\CoreBundle\Router + Soloist\Bundle\CoreBundle\EventListener\BlogListener @@ -29,6 +30,7 @@ + @@ -47,6 +49,11 @@ + + + + + diff --git a/Resources/views/Navigation/Similar/page.html.twig b/Resources/views/Navigation/Similar/page.html.twig new file mode 100644 index 0000000..bdd53dd --- /dev/null +++ b/Resources/views/Navigation/Similar/page.html.twig @@ -0,0 +1,7 @@ +
+ +