Commit 2ce6e695 authored by Hermann Mayer's avatar Hermann Mayer

Added merge support for article/tag controller to handle the entites correctly.…

Added merge support for article/tag controller to handle the entites correctly. (Merge, Edit, Sortable) Rewritten the form-field (collection), and added support for mulptiple lists.
parent 9290248a
......@@ -13,4 +13,6 @@ php app/console doctrine:schema:create || exit 1
yes | php app/console doctrine:fixtures:load || exit 1
rm -rf app/cache/dev
if [[ "$1" != 'cache:noclean' ]]; then
rm -rf app/cache/dev
fi
......@@ -82,6 +82,9 @@ class ArticleController extends Controller
$entity->setAuthor($user);
$em = $this->getDoctrine()->getManager();
$entity = $this->mergeEntity($request, $em, $form, $entity);
$em->persist($entity);
$em->flush();
......@@ -128,6 +131,11 @@ class ArticleController extends Controller
$entity = $em->getRepository('JityHomepageBundle:Article')->find($id);
// First clear all tags, they will be new added
foreach ($entity->getTags() as $tag) {
$entity->removeTag($tag);
}
if (!$entity) {
throw $this->createNotFoundException('Unable to find Article entity.');
}
......@@ -142,6 +150,8 @@ class ArticleController extends Controller
$user = $this->container->get('security.context')->getToken()->getUser();
$entity->setAuthor($user);
$entity = $this->mergeEntity($request, $em, $editForm, $entity);
$em->persist($entity);
$em->flush();
......@@ -155,6 +165,46 @@ class ArticleController extends Controller
));
}
/**
* mergeEntity
*
* Add collection merge support. So unique elements
* will be connected instead of new inserted and
* changes to the connected entites will be merged.
*
* @param Request $request
* @param mixed $em
* @param mixed $form
* @param mixed $entity
* @access private
* @return void
*/
private function mergeEntity(Request $request, $em, $form, $entity)
{
$postData = $request->get($form->getName());
foreach ($entity->getTags() as $tag) {
if (null !== $tag->getId()) {
$entity->removeTag($tag);
// $tag = $em->getRepository('JityHomepageBundle:Tag')->find($tag->getId());
$tag = $em->merge($tag);
array_walk($postData['tags'], function($item, $key) use($tag)
{
if ($item['name'] == $tag->getName()) {
$tag->match = $item['match'];
}
});
$entity->addTag($tag, $tag->match);
}
}
return $entity;
}
/**
* Deletes a Article entity.
*
......@@ -179,6 +229,13 @@ class ArticleController extends Controller
return $this->redirect($this->generateUrl('author_article'));
}
/**
* createDeleteForm
*
* @param mixed $id
* @access private
* @return void
*/
private function createDeleteForm($id)
{
return $this->createFormBuilder(array('id' => $id))
......
<?php
namespace Jity\HomepageBundle\Controller;
use Jity\HomepageBundle\Entity\Section;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* TagController
*
* @uses Controller
* @version $id$
* @author Hermann Mayer <hermann.mayer92@gmail.com>
*/
class TagController extends Controller
{
/**
* indexAction
*
* @access public
* @return void
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
// Use DQL because its more powerfull and only one query is needed
$q = $em->createQueryBuilder()
->select('t.id, t.name')
->from('JityHomepageBundle:Tag', 't')
->getQuery()
;
return new Response(
json_encode($q->getArrayResult())
);
}
/**
* showAction
*
* @param mixed $id
* @access public
* @return void
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('JityHomepageBundle:Tag')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Section entity.');
}
$serializer = $this->container->get('serializer');
return new Response(
$serializer->serialize($entity, 'json')
);
}
}
......@@ -376,6 +376,22 @@ erreichen, oder über Google+.
->addComment($comment)
;
// Build Home Page
$test = new Article();
$test
->setTitle('Blubber Test')
->setContent('21')
->setCategory($this->getReference('default-category'))
->setSidebar($this->getReference('blog-sidebar'))
->setNavigation($this->getReference('blog-navigation'))
->setAuthor($this->getReference('admin-user'))
->setIcon('icon-font')
;
$manager->persist($test);
/*
* --------------------------------------------------------------------
*/
......
......@@ -115,8 +115,7 @@ abstract class AbstractPage
*/
public function __construct()
{
$this->medias = new \Doctrine\Common\Collections\ArrayCollection();
$this->navigations = new \Doctrine\Common\Collections\ArrayCollection();
$this->abstractPageTag = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
......@@ -411,6 +410,11 @@ abstract class AbstractPage
{
// Build new relation object to handle join entity correct
$rel = new \Jity\HomepageBundle\Entity\AbstractPageTag($this, $tag);
if (null === $match) {
$match = $tag->match;
}
$rel->setMatch($match);
// Add relation object to collection
......@@ -433,6 +437,8 @@ abstract class AbstractPage
$rel->getTag()->removePage($this);
}
}
return $this;
}
/**
......
......@@ -23,6 +23,8 @@ class Article extends AbstractPage
*/
public function __construct()
{
parent::__construct();
$this->comments = new \Doctrine\Common\Collections\ArrayCollection();
}
......
......@@ -42,6 +42,7 @@ class Tag
/**
* @var match
* @Exclude
*/
public $match;
......@@ -51,13 +52,26 @@ class Tag
*/
public function __construct($name = null)
{
$this->pages = new \Doctrine\Common\Collections\ArrayCollection();
$this->abstractPageTag = new \Doctrine\Common\Collections\ArrayCollection();
if (!empty($name)) {
$this->setName($name);
}
}
/**
* setId
*
* @param mixed $id
* @return void
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* Get id
*
......
......@@ -60,8 +60,28 @@ class ArticleType extends AbstractType
'property' => 'name',
'label' => 'Navigation'
))
// ->add('tags')
->add('tags', 'collection', array(
'type' => new TagType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => true,
'label' => 'Zutreffende Tags',
'label_attr' => array(
'class' => 'form_embedded_label'
),
'attr' => array(
'class' => 'sortable-existing'
),
'lists' => array (
'element' => 'match',
'values' => array(100, 66, 33),
'labels' => array(
100 => '<h3>Sehr zutreffend</h3>',
66 => '<h3>Trifft zu</h3>',
33 => '<h3>Trifft entfernt zu</h3>',
)
)
))
;
}
......
<?php
namespace Jity\HomepageBundle\Form\Extension;
use Symfony\Component\Form\AbstractTypeExtension,
Symfony\Component\Form\FormInterface,
Symfony\Component\Form\FormView,
Symfony\Component\Form\FormBuilderInterface,
JMS\DiExtraBundle\Annotation as DI;
/**
* SortableListsTypeExtensionextends
*
* @DI\Service("form.type_extension.sortable_lists")
* @DI\Tag("form.type_extension", attributes={"alias" = "form"})
*
* @uses AbstractTypeExtension
* @version $id$
* @author Hermann Mayer <hermann.mayer92@gmail.com>
*/
class SortableListsTypeExtension extends AbstractTypeExtension
{
/**
* buildForm
*
* @param FormBuilderInterface $builder
* @param array $options
* @access public
* @return void
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->setAttribute('lists', $options['lists']);
}
/**
* buildView
*
* @param FormView $view
* @param FormInterface $form
* @param array $options
* @access public
* @return void
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->set('lists', $form->getAttribute('lists'));
}
/**
* getDefaultOptions
*
* @access public
* @return void
*/
public function getDefaultOptions()
{
return array(
'lists' => null,
);
}
/**
* getExtendedType
*
* @access public
* @return void
*/
public function getExtendedType()
{
return 'form';
}
}
<?php
namespace Jity\HomepageBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class TagType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('id', 'hidden')
->add('name', null, array(
'label' => 'Name'
))
->add('match', 'hidden')
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Jity\HomepageBundle\Entity\Tag'
));
}
public function getName()
{
return 'jity_homepagebundle_tagtype';
}
}
......@@ -33,6 +33,10 @@ JityHomepageBundle_author_section:
resource: "@JityHomepageBundle/Resources/config/routing/section.yml"
prefix: /author/section
JityHomepageBundle_author_tag:
resource: "@JityHomepageBundle/Resources/config/routing/tag.yml"
prefix: /author/tag
JityHomepageBundle_user:
resource: "@JityHomepageBundle/Resources/config/routing/user.yml"
prefix: /user
......
author_tag:
pattern: /
defaults: { _controller: "JityHomepageBundle:Tag:index", label: "Tags", parent: "author_dashboard", _format: "json" }
author_tag_show:
pattern: /{id}/show
defaults: { _controller: "JityHomepageBundle:Tag:show", label: "Details", parent: "author_tag", _format: "json" }
......@@ -25,7 +25,7 @@ Jity\HomepageBundle\Entity\Contact:
- NotBlank: { message: "Diese Angabe muss noch ausgefüllt werden." }
- Length: { min: 2, minMessage: "Diese Angabe muss mindestens {{ limit }} Zeichen lang sein." }
Jity\HomepageBundle\Entity\Page:
Jity\HomepageBundle\Entity\AbstractPage:
properties:
title:
- NotBlank: { message: "Diese Angabe muss noch ausgefüllt werden." }
......
......@@ -287,11 +287,18 @@ hr {
border-top-width: 2px;
border-top-style: solid;
border-radius: 6px 6px 6px 6px;
margin-top: 30px;
margin-top: 15px;
margin-bottom: 15px;
padding: 20px;
position: relative;
padding-left: 25px;
padding-right: 59px;
padding-bottom: 1px;
background-repeat: no-repeat;
background-position: right bottom;
}
......@@ -534,3 +541,7 @@ code, pre {
font-weight: 300;
}
.label, .badge {
cursor: pointer;
}
.collection {
min-height: 50px;
border-radius: 6px;
padding: 0 20px 0 20px;
/* padding: 20px; */
/* padding-bottom: 1px; */
box-shadow: inset 2px 2px 5px rgba(0, 0, 0, 0.35), 7px 7px 15px rgba(0, 0, 0, 0.15);
border-style: solid;
border-width: 1px;
border-top-color: rgba(0, 0, 0, 0.5);
border-left-color: rgba(0, 0, 0, 0.5);
border-right-color: rgba(255, 255, 255, 0.15);
border-bottom-color: rgba(255, 255, 255, 0.15);
margin-top: 10px;
margin-bottom: 10px;
}
.ui-state-highlight {
/* margin: 30px; */
margin: 15px 0 15px 0;
}
#tags-list-100 {
/* background-color: rgba(185, 74, 72, 0.2); */
background-color: rgba(90, 0, 0, 0.2);
}
#tags-list-66 {
background-color: rgba(185, 109, 73, 0.2);
}
#tags-list-33 {
background-color: rgba(51, 51, 51, 0.5);
}
/* #tag-lists > div { */
/* margin-bottom: 20px; */
/* } */
......@@ -163,6 +163,7 @@ input[type="url"], input[type="search"], input[type="tel"], input[type="color"],
#previewCage {
border-top-color: #722C0F;
background-color: #282624;
}
pre {
......@@ -205,7 +206,7 @@ hr {
.ui-state-highlight {
box-shadow: inset 0px 0px 20px #000000;
background-color: #181818;
background-color: rgba(0, 0, 0, 0.1); /* #181818 */
border-bottom-color: #515151;
border-right-color: #515151;
}
......
......@@ -8,9 +8,7 @@
<legend>Neuen Artikel erstellen</legend>
<div class="">
{{ form_widget(form) }}
</div>
{{ form_widget(form) }}
<div class="form-actions">
<button type="submit" class="btn btn-primary">
......
{% render 'JityHomepageBundle:Editor:build' with {'syncElement': 'textarea[name="jity_homepagebundle_articletype[content]"]'} %}
{% render 'JityHomepageBundle:Editor:icons' with {'syncElement': 'input[name="jity_homepagebundle_articletype[icon]"]'} %}
{% render 'JityHomepageBundle:Editor:modal' with {
'name': 'confirm',
'label': '',
'enableJS': true,
'buttons': [
{
'id': 1,
},
{
'id': 2,
},
],
'body': '',
} %}
<a name="preview"></a>
<div id="previewCage"></div>
......@@ -22,6 +36,182 @@ $(document).ready(function() {
return false;
});
$('.form_embedded_label').html($('.form_embedded_label').html() + '<div class="pull-right">'
+ '<a href="#" title="Neues Element hinzufügen" class="btn btn-small btn-danger" id="tags_btn_add">'
+ '<i class="icon-white icon-plus"></i>'
+ '</a>'
+ '</div>'
);
// Start sortable ui for the collection
collections.initSortable();
tags = {
init: function() {
// $('textarea[data-target="#editor_modal"]').bind('focus', function(){
// editor.setSyncElement('textarea[id="' + $(this).attr('id') + '"]');
// });
$('.btn-remove').click(function (e){
// Dont do anything on link clicking
e.preventDefault();
// Configure and run the modal
confirmModal
.setLabel('Bestätigung der Löschaktion')
.setBody('Möchten Sie dieses Element wirklich löschen?')
.setButtons([
{
id: 1,
class: 'btn-danger',
icon: 'icon-share-alt',
value: 'Abbrechen'
},
{
id: 2,
class: 'btn-primary',
icon: 'icon-ok',
value: 'Löschen',
data: this,
click: function (data){
var el = $(data).closest('.sortable');
el.slideUp(function() {
// At end of sliding remove element from dom
el.remove();
tags.emptyMessage();
});
}
}
])
.show()
;
});
this.emptyMessage();
},
emptyMessage: function() {
var list = $('.collection');
if (0 == list.children('div').length) {
if (0 != $('#no_sections_msg').length) {
return;
}
// Hide our list labels
$('#jity_homepagebundle_articletype_tags').find('h3').hide();
list.hide();
$(
'<p id="no_sections_msg">'
+ '<img class="pull-right" src="{{ asset('bundles/jityhomepage/img/help/no-section-arrow.png') }}" />'
+ '<br>Noch sind keine Sektionen mit dieser Sidebar verbunden.<br>'
+ 'Das soll natürlich nicht so bleiben, deshalb können Sie ganz bequem über<br>'
+ 'diesen Knopf neue Sektionen anlegen, oder bestehende verbinden.'
+ '</p>'
).insertBefore(list.first()).hide().fadeIn();
} else {
$('#no_sections_msg').remove();
$('#jity_homepagebundle_articletype_tags').find('h3').show();
list.show();
}
},
fetchAndAdd: function(id) {
// Build the path for the request
var path = '{{ path('author_tag_show', {id: "__id__"}) }}'.replace(/__id__/g, id);
// Get the requested data and write it to a new section
$.get(
path,
function(data) {
collections.add(
{class: "sortable-existing"},
[
data.id,
data.name
],
$('#tags-list-100')
);
tags.init();
}
);
}
}
tags.init();
$('#tags_btn_add').click(function (e){
// Dont do anything on link clicking
e.preventDefault();
// Configure and run the modal
confirmModal
.setLabel('Was möchten Sie tun?')
.setBody(
' <div>'
+ ' <legend class="h2">Bestehende Sektion</legend>'
+ ' Sie können an dieser Stelle problemlos bereits bestehende Tags hinzufügen und diese sortieren.<br><br>'
+ ' <select id="tags_new_select" style="margin-bottom: 0px;">'
+ ' </select>'
+ ' <a class="btn btn-primary" href="#" onclick="tags.fetchAndAdd($(\'#tags_new_select\').find(\':selected\').val()); confirmModal.hide(); return false;">'
+ ' <i class="icon-white icon-ok"></i>'
+ ' Hinzufügen'
+ ' </a>'
+ ' </div><br>'
+ ' <div>'
+ ' <legend class="h2">Neue Sektion</legend>'