From a24101efbe5442b72cf0414107bce0986cd75d53 Mon Sep 17 00:00:00 2001 From: Olexandr Lensky Date: Tue, 17 Dec 2013 14:14:36 +0200 Subject: [PATCH 1/4] updated bundle for extending --- Admin/PostAdmin.php | 6 +- .../EntitiesToStringTransformer.php | 28 +-- Bridge/Doctrine/Form/Type/TagsType.php | 15 +- Controller/CommentController.php | 13 +- Controller/PostController.php | 62 +++---- Controller/TagController.php | 23 ++- DependencyInjection/Configuration.php | 83 +++++++++ DependencyInjection/StfalconBlogExtension.php | 32 +++- Entity/Post.php | 84 ++------- Entity/PostManager.php | 171 ++++++++++++++++++ Entity/Tag.php | 49 +---- Entity/TagManager.php | 127 +++++++++++++ Resources/config/admin.xml | 23 +++ Resources/config/orm.xml | 24 +++ Resources/config/service.xml | 39 ---- Resources/config/services.xml | 18 ++ Resources/doc/index.md | 19 +- 17 files changed, 586 insertions(+), 230 deletions(-) create mode 100644 DependencyInjection/Configuration.php create mode 100644 Entity/PostManager.php create mode 100644 Entity/TagManager.php create mode 100644 Resources/config/admin.xml create mode 100644 Resources/config/orm.xml delete mode 100644 Resources/config/service.xml create mode 100644 Resources/config/services.xml diff --git a/Admin/PostAdmin.php b/Admin/PostAdmin.php index 53eb350..1ebf52d 100644 --- a/Admin/PostAdmin.php +++ b/Admin/PostAdmin.php @@ -13,8 +13,7 @@ protected function configureFormFields(FormMapper $formMapper) ->add('title') ->add('slug') ->add('text') - ->add('tags', 'tags') - ; + ->add('tags', 'tags'); } protected function configureListFields(ListMapper $listMapper) @@ -22,7 +21,6 @@ protected function configureListFields(ListMapper $listMapper) $listMapper ->addIdentifier('slug') ->add('title') - ->add('created') - ; + ->add('created'); } } \ No newline at end of file diff --git a/Bridge/Doctrine/Form/DataTransformer/EntitiesToStringTransformer.php b/Bridge/Doctrine/Form/DataTransformer/EntitiesToStringTransformer.php index a3108f3..2c1303a 100644 --- a/Bridge/Doctrine/Form/DataTransformer/EntitiesToStringTransformer.php +++ b/Bridge/Doctrine/Form/DataTransformer/EntitiesToStringTransformer.php @@ -2,6 +2,7 @@ namespace Stfalcon\Bundle\BlogBundle\Bridge\Doctrine\Form\DataTransformer; +use Stfalcon\Bundle\BlogBundle\Entity\TagManager; use Symfony\Component\Form\DataTransformerInterface; use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\ArrayCollection; @@ -16,20 +17,18 @@ class EntitiesToStringTransformer implements DataTransformerInterface { /** - * @var Doctrine\ORM\EntityManager + * @var TagManager */ - protected $em; + protected $manager; /** * Constructor injection. Set entity manager to object * - * @param Doctrine\ORM\EntityManager $em Entity manager object - * - * @return void + * @param TagManager $manager Tag manager */ - public function __construct(\Doctrine\ORM\EntityManager $em) + public function __construct(TagManager $manager) { - $this->em = $em; + $this->manager = $manager; } /** @@ -38,6 +37,8 @@ public function __construct(\Doctrine\ORM\EntityManager $em) * @param Collection|null $collection A collection of entities or NULL * * @return string|null An string of tags or NULL + * + * @throws \Symfony\Component\Form\Exception\UnexpectedTypeException */ public function transform($collection) { @@ -51,7 +52,7 @@ public function transform($collection) $array = array(); foreach ($collection as $entity) { - array_push($array, $entity->getText()); + $array[] = $entity->getText(); } return implode(', ', $array); @@ -63,6 +64,8 @@ public function transform($collection) * @param string|null $data Input string data * * @return Collection|null + * + * @throws \Symfony\Component\Form\Exception\UnexpectedTypeException */ public function reverseTransform($data) { @@ -77,11 +80,10 @@ public function reverseTransform($data) } foreach ($this->_stringToArray($data) as $text) { - $tag = $this->em->getRepository("StfalconBlogBundle:Tag") - ->findOneBy(array('text' => $text)); + $tag = $this->manager->findTagBy(array('text' => $text)); if (!$tag) { - $tag = new \Stfalcon\Bundle\BlogBundle\Entity\Tag($text); - $this->em->persist($tag); + $tag = $this->manager->create($text); + $this->manager->save($tag); } $collection->add($tag); } @@ -93,6 +95,8 @@ public function reverseTransform($data) * Convert string of tags to array * * @param string $string + * + * @return array */ private function _stringToArray($string) { diff --git a/Bridge/Doctrine/Form/Type/TagsType.php b/Bridge/Doctrine/Form/Type/TagsType.php index 580c2af..17c51ca 100644 --- a/Bridge/Doctrine/Form/Type/TagsType.php +++ b/Bridge/Doctrine/Form/Type/TagsType.php @@ -2,6 +2,7 @@ namespace Stfalcon\Bundle\BlogBundle\Bridge\Doctrine\Form\Type; +use Stfalcon\Bundle\BlogBundle\Entity\TagManager; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Bridge\Doctrine\RegistryInterface; @@ -15,18 +16,16 @@ class TagsType extends AbstractType { - protected $registry; + protected $tagManager; /** * Constructor injection * - * @param RegistryInterface $registry Doctrine registry object - * - * @return void + * @param TagManager $manager Tag manager */ - public function __construct(RegistryInterface $registry) + public function __construct(TagManager $manager) { - $this->registry = $registry; + $this->tagManager = $manager; } /** @@ -39,8 +38,8 @@ public function __construct(RegistryInterface $registry) */ public function buildForm(FormBuilderInterface $builder, array $options) { - $builder->prependClientTransformer( - new EntitiesToStringTransformer($this->registry->getEntityManager()) + $builder->addModelTransformer( + new EntitiesToStringTransformer($this->tagManager) ); } diff --git a/Controller/CommentController.php b/Controller/CommentController.php index 23bb1f4..bb24ba0 100644 --- a/Controller/CommentController.php +++ b/Controller/CommentController.php @@ -5,7 +5,8 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Symfony\Component\HttpFoundation\Response; -use Stfalcon\Bundle\BlogBundle\Entity\Post; + +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * Controller for actions with DISQUS comments @@ -18,16 +19,22 @@ class CommentController extends Controller /** * Synchronization comments count with disqus * - * @param Post $post Post object + * @param string $slug Slug of post * * @return Response * @Route("/blog/post/{slug}/disqus-sync", name="blog_post_disqus_sync") + * + * @throws NotFoundHttpException */ - public function disqusSyncAction(Post $post) + public function disqusSyncAction($slug) { // @todo. нужно доставать полный список ЗААПРУВЛЕННЫХ комментариев или // колличество комментариев к записи (если такой метод появится в API disqus) // после чего обновлять их колличество в БД + $post = $this->get('stfalcon_blog.post.manager')->findPostBy(array('slug' => $slug)); + if (!$post) { + throw new NotFoundHttpException(); + } $post->setCommentsCount($post->getCommentsCount() + 1); $em = $this->get('doctrine.orm.entity_manager'); diff --git a/Controller/PostController.php b/Controller/PostController.php index fba49b8..841ccde 100644 --- a/Controller/PostController.php +++ b/Controller/PostController.php @@ -5,8 +5,7 @@ use Symfony\Component\HttpFoundation\Response; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; - -use Stfalcon\Bundle\BlogBundle\Entity\Post; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * PostController @@ -15,42 +14,32 @@ */ class PostController extends AbstractController { - - private function _getRequestArrayWithDisqusShortname($array) - { - $config = $this->container->getParameter('stfalcon_blog.config'); - return array_merge( - $array, - array('disqus_shortname' => $config['disqus_shortname']) - ); - } - /** * List of posts for admin * + * @param int $page Page number + * + * @return array + * * @Route("/blog/{title}/{page}", name="blog", * requirements={"page"="\d+", "title"="page"}, * defaults={"page"="1", "title"="page"}) * @Template() - * - * @param int $page Page number - * - * @return array */ public function indexAction($page) { - $allPosts = $this->get('doctrine')->getEntityManager() - ->getRepository("StfalconBlogBundle:Post")->getAllPosts(); - $posts= $this->get('knp_paginator')->paginate($allPosts, $page, 10); + $allPostsQuery = $this->get('stfalcon_blog.post.manager')->findAllPostsAsQuery(); + $posts= $this->get('knp_paginator')->paginate($allPostsQuery, $page, 10); if ($this->has('application_default.menu.breadcrumbs')) { $breadcrumbs = $this->get('application_default.menu.breadcrumbs'); $breadcrumbs->addChild('Блог')->setCurrent(true); } - return $this->_getRequestArrayWithDisqusShortname(array( - 'posts' => $posts - )); + return array( + 'posts' => $posts, + 'disqus_shortname' => $this->container->getParameter('stfalcon_blog.disqus_shortname') + ); } /** @@ -59,21 +48,28 @@ public function indexAction($page) * @Route("/blog/post/{slug}", name="blog_post_view") * @Template() * - * @param Post $post + * @param string $slug * * @return array + * + * @throws NotFoundHttpException */ - public function viewAction(Post $post) + public function viewAction($slug) { + $post = $this->get('stfalcon_blog.post.manager')->findPostBy(array('slug' => $slug)); + if (!$post) { + throw new NotFoundHttpException(); + } if ($this->has('application_default.menu.breadcrumbs')) { $breadcrumbs = $this->get('application_default.menu.breadcrumbs'); $breadcrumbs->addChild('Блог', array('route' => 'blog')); $breadcrumbs->addChild($post->getTitle())->setCurrent(true); } - return $this->_getRequestArrayWithDisqusShortname(array( - 'post' => $post - )); + return array( + 'post' => $post, + 'disqus_shortname' => $this->container->getParameter('stfalcon_blog.disqus_shortname') + ); } /** @@ -87,14 +83,11 @@ public function rssAction() { $feed = new \Zend\Feed\Writer\Feed(); - $config = $this->container->getParameter('stfalcon_blog.config'); - - $feed->setTitle($config['rss']['title']); - $feed->setDescription($config['rss']['description']); + $feed->setTitle($this->container->getParameter('stfalcon_blog.rss.title')); + $feed->setDescription($this->container->getParameter('stfalcon_blog.rss.description')); $feed->setLink($this->generateUrl('blog_rss', array(), true)); - $posts = $this->get('doctrine')->getEntityManager() - ->getRepository("StfalconBlogBundle:Post")->getAllPosts(); + $posts = $this->get('stfalcon_blog.post.manager')->findAllPosts(); foreach ($posts as $post) { $entry = new \Zend\Feed\Writer\Entry(); $entry->setTitle($post->getTitle()); @@ -117,8 +110,7 @@ public function rssAction() */ public function lastAction($count = 1) { - $posts = $this->get('doctrine')->getEntityManager() - ->getRepository("StfalconBlogBundle:Post")->getLastPosts($count); + $posts = $this->get('stfalcon_blog.post.manager')->findLastPosts($count); return array('posts' => $posts); } diff --git a/Controller/TagController.php b/Controller/TagController.php index a4969d8..b4780da 100644 --- a/Controller/TagController.php +++ b/Controller/TagController.php @@ -5,7 +5,7 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; -use Stfalcon\Bundle\BlogBundle\Entity\Tag; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * TagController @@ -23,15 +23,23 @@ class TagController extends AbstractController * defaults={"page"="1", "title"="page"}) * @Template() * - * @param Tag $tag - * @param int $page page number + * @param string $text text of tag + * @param int $page page number * * @return array + * + * @throws NotFoundHttpException */ - public function viewAction(Tag $tag, $page) + public function viewAction($text, $page) { + $tag = $this->get('stfalcon_blog.tag.manager')->findTagBy(array('text' => $text)); + if (!$tag) { + throw new NotFoundHttpException(); + } + + $postsQuery = $this->get('stfalcon_blog.post.manager')->findPostsByTagAsQuery($tag); $posts = $this->get('knp_paginator') - ->paginate($tag->getPosts(), $page, 10); + ->paginate($postsQuery, $page, 10); if ($this->has('menu.breadcrumbs')) { $breadcrumbs = $this->get('menu.breadcrumbs'); @@ -39,10 +47,11 @@ public function viewAction(Tag $tag, $page) $breadcrumbs->addChild($tag->getText())->setIsCurrent(true); } - return $this->_getRequestDataWithDisqusShortname(array( + return array( 'tag' => $tag, 'posts' => $posts, - )); + 'disqus_shortname' => $this->container->getParameter('stfalcon_blog.disqus_shortname') + ); } } \ No newline at end of file diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php new file mode 100644 index 0000000..2f67b5e --- /dev/null +++ b/DependencyInjection/Configuration.php @@ -0,0 +1,83 @@ +root('stfalcon_blog'); + + $rootNode->children() + ->scalarNode('disqus_shortname')->isRequired()->cannotBeEmpty()->end() + ->arrayNode('rss') + ->addDefaultsIfNotSet() + ->canBeUnset() + ->children() + ->scalarNode('title')->defaultNull()->end() + ->scalarNode('description')->defaultNull()->end() + ->end() + ->end(); + + + $this->addPostSection($rootNode); + $this->addTagSection($rootNode); + + return $treeBuilder; + } + + private function addPostSection(ArrayNodeDefinition $node) + { + $node + ->children() + ->arrayNode('post') + ->children() + ->scalarNode('entity')->isRequired()->cannotBeEmpty()->end() + ->scalarNode('manager')->defaultValue('stfalcon_blog.post.manager.default')->end() + ->arrayNode('admin') + ->addDefaultsIfNotSet() + ->children() + ->scalarNode('class')->defaultValue('Stfalcon\\Bundle\\BlogBundle\\Admin\\PostAdmin')->end() + ->scalarNode('controller')->defaultValue('SonataAdminBundle:CRUD')->end() + ->end() + ->end() + ->end() + ->end() + ->end(); + } + + private function addTagSection(ArrayNodeDefinition $node) + { + $node + ->children() + ->arrayNode('tag') + ->children() + ->scalarNode('entity')->isRequired()->cannotBeEmpty()->end() + ->scalarNode('manager')->defaultValue('stfalcon_blog.tag.manager.default')->end() + ->arrayNode('admin') + ->addDefaultsIfNotSet() + ->children() + ->scalarNode('class')->defaultValue('Stfalcon\\Bundle\\BlogBundle\\Admin\\TagAdmin')->end() + ->scalarNode('controller')->defaultValue('SonataAdminBundle:CRUD')->end() + ->end() + ->end() + ->end() + ->end() + ->end(); + } +} diff --git a/DependencyInjection/StfalconBlogExtension.php b/DependencyInjection/StfalconBlogExtension.php index 43c814a..7531afe 100644 --- a/DependencyInjection/StfalconBlogExtension.php +++ b/DependencyInjection/StfalconBlogExtension.php @@ -6,6 +6,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\Config\FileLocator; +use Symfony\Component\Config\Definition\Processor; /** * This is the class that loads and manages StfalconBlogBundle configuration @@ -27,15 +28,34 @@ class StfalconBlogExtension extends Extension */ public function load(array $configs, ContainerBuilder $container) { - $config = array(); - foreach ($configs as $c) { - $config = array_merge($config, $c); - } + $processor = new Processor(); + $configuration = new Configuration(); - $container->setParameter('stfalcon_blog.config', $config); + $config = $processor->processConfiguration($configuration, $configs); $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); - $loader->load('service.xml'); + + $container->setParameter('stfalcon_blog.disqus_shortname', $config['disqus_shortname']); + $container->setParameter('stfalcon_blog.rss.title', $config['rss']['title']); + $container->setParameter('stfalcon_blog.rss.description', $config['rss']['description']); + + $loader->load('orm.xml'); + $container->setParameter('stfalcon_blog.post.entity', $config['post']['entity']); + $container->setAlias('stfalcon_blog.post.manager', $config['post']['manager']); + unset($config['post']['manager']); + + $container->setParameter('stfalcon_blog.tag.entity', $config['tag']['entity']); + $container->setAlias('stfalcon_blog.tag.manager', $config['tag']['manager']); + unset($config['tag']['manager']); + + $loader->load('admin.xml'); + + $container->setParameter('stfalcon_blog.post.admin.class', $config['post']['admin']['class']); + $container->setParameter('stfalcon_blog.post.admin.controller', $config['post']['admin']['controller']); + + $container->setParameter('stfalcon_blog.tag.admin.class', $config['tag']['admin']['class']); + $container->setParameter('stfalcon_blog.tag.admin.controller', $config['tag']['admin']['controller']); + $loader->load('services.xml'); } } \ No newline at end of file diff --git a/Entity/Post.php b/Entity/Post.php index 6ac668b..91e38dd 100644 --- a/Entity/Post.php +++ b/Entity/Post.php @@ -11,21 +11,10 @@ * Post entity * * @author Stepan Tanasiychuk - * @ORM\Table(name="blog_posts") - * @ORM\Entity(repositoryClass="Stfalcon\Bundle\BlogBundle\Repository\PostRepository") + * @ORM\MappedSuperclass */ class Post { - /** - * Post id - * - * @var integer $id - * @ORM\Column(name="id", type="integer") - * @ORM\Id - * @ORM\GeneratedValue(strategy="AUTO") - */ - private $id; - /** * Post title * @@ -33,7 +22,7 @@ class Post * @Assert\NotBlank() * @ORM\Column(name="title", type="string", length=255) */ - private $title = ''; + protected $title = ''; /** * @var string $slug @@ -42,37 +31,31 @@ class Post * @Assert\MinLength(3) * @ORM\Column(name="slug", type="string", length=128, unique=true) */ - private $slug; + protected $slug; /** * Post text * - * @var text $text + * @var string $text * @Assert\NotBlank() * @ORM\Column(name="text", type="text") */ - private $text; + protected $text; /** * Post text as HTML code * - * @var text $textAsHtml + * @var string $textAsHtml * @ORM\Column(name="text_as_html", type="text") */ - private $textAsHtml; + protected $textAsHtml; /** * Tags for post * * @var ArrayCollection - * @Assert\NotBlank() - * @ORM\ManyToMany(targetEntity="Stfalcon\Bundle\BlogBundle\Entity\Tag") - * @ORM\JoinTable(name="blog_posts_tags", - * joinColumns={@ORM\JoinColumn(name="post_id", referencedColumnName="id")}, - * inverseJoinColumns={@ORM\JoinColumn(name="tag_id", referencedColumnName="id")} - * ) */ - private $tags; + protected $tags; /** * @var \DateTime $created @@ -80,7 +63,7 @@ class Post * @ORM\Column(type="datetime") * @Gedmo\Timestampable(on="create") */ - private $created; + protected $created; /** * @var \DateTime $updated @@ -88,56 +71,14 @@ class Post * @ORM\Column(type="datetime") * @Gedmo\Timestampable(on="update") */ - private $updated; + protected $updated; /** * @var int $commentsCount * * @ORM\Column(type="integer") */ - private $commentsCount = 0; - - /** - * Initialization properties for new post entity - * - * @return void - */ - public function __construct() - { - $this->tags = new ArrayCollection(); - } - - /** - * Get post id - * - * @return int - */ - public function getId() - { - return $this->id; - } - - /** - * Set tags to post - * - * @param $tags Tags collection - * - * @return void - */ - public function setTags($tags) - { - $this->tags = $tags; - } - - /** - * Get all tags - * - * @return ArrayCollection - */ - public function getTags() - { - return $this->tags; - } + protected $commentsCount = 0; /** * Set post title @@ -233,6 +174,7 @@ private function _transformTextAsHtml($text) '/
\r?\n?(.*?)\r?\n?\<\/pre>/is',
             function($data) {
                 $geshi = new \GeSHi($data[2], $data[1]);
+
                 return $geshi->parse_code();
             }, $text
         );
@@ -313,6 +255,6 @@ public function getCommentsCount()
      */
     public function __toString()
     {
-        return $this->getTitle();
+        return $this->getTitle()?$this->getTitle():'';
     }
 }
\ No newline at end of file
diff --git a/Entity/PostManager.php b/Entity/PostManager.php
new file mode 100644
index 0000000..08b6efb
--- /dev/null
+++ b/Entity/PostManager.php
@@ -0,0 +1,171 @@
+objectManager = $om;
+        $metadata = $om->getClassMetadata($class);
+        $this->class = $metadata->getName();
+        $this->repository = $om->getRepository($class);
+    }
+
+    /**
+     * Create new category
+     *
+     * @return mixed
+     */
+    public function create()
+    {
+        return new $this->class;
+    }
+
+    /**
+     * Remove category
+     *
+     * @param mixed $category
+     */
+    public function delete($category)
+    {
+        $this->objectManager->remove($category);
+        $this->objectManager->flush();
+    }
+
+    /**
+     * Save category
+     *
+     * @param mixed $category
+     */
+    public function save($category)
+    {
+        $this->objectManager->persist($category);
+        $this->objectManager->flush();
+    }
+
+    /**
+     * Get class name
+     *
+     * @return string
+     */
+    public function getClass()
+    {
+        return $this->class;
+    }
+
+    /**
+     * @return EntityRepository
+     */
+    public function getRepository()
+    {
+        return $this->repository;
+    }
+
+    /**
+     * Find one post by id
+     *
+     * @param int $id
+     *
+     * @return object
+     */
+    public function findPost($id)
+    {
+        return $this->repository->find($id);
+    }
+
+    /**
+     * Find one post by criteria
+     *
+     * @param array $criteria
+     *
+     * @return object
+     */
+    public function findPostBy(array $criteria)
+    {
+        return $this->repository->findOneBy($criteria);
+    }
+
+    /**
+     * Find posts by criteria
+     *
+     * @param array $criteria
+     *
+     * @return array
+     */
+    public function findPostsBy(array $criteria)
+    {
+        return $this->repository->findBy($criteria);
+    }
+
+    /**
+     * Find all posts
+     *
+     * @return mixed
+     */
+    public function findAllPosts()
+    {
+        return $this->findAllPostsAsQuery()->getResult();
+    }
+
+    /**
+     * Find all posts as query
+     *
+     * @return mixed
+     */
+    public function findAllPostsAsQuery()
+    {
+        return $this->repository->createQueryBuilder('p')
+            ->orderBy('p.created', 'DESC')
+            ->getQuery();
+    }
+
+    /**
+     * Find posts by tag as query
+     *
+     * @param mixed $tag
+     *
+     * @return mixed
+     */
+    public function findPostsByTagAsQuery($tag)
+    {
+        return $this->repository->createQueryBuilder('p')
+            ->join('p.tags', 't')
+            ->where('t = :tag')
+            ->orderBy('p.created', 'DESC')
+            ->setParameter('tag', $tag)
+            ->getQuery();
+    }
+
+    /**
+     * Get last posts
+     *
+     * @param integer $count Max count of returned posts
+     *
+     * @return array
+     */
+    public function findLastPosts($count = null)
+    {
+        $query = $this->findAllPostsAsQuery();
+        if ((int) $count) {
+            $query->setMaxResults($count);
+        }
+
+        return $query->getResult();
+    }
+}
diff --git a/Entity/Tag.php b/Entity/Tag.php
index 6a3a5a4..b1fb1b9 100644
--- a/Entity/Tag.php
+++ b/Entity/Tag.php
@@ -10,49 +10,24 @@
  * Stfalcon\Bundle\BlogBundle\Entity\Tag
  *
  * @author Stepan Tanasiychuk 
- * @ORM\Table(name="blog_tags")
- * @ORM\Entity
+ *
+ * @ORM\MappedSuperclass
  */
 class Tag
 {
-    /**
-     * Tag id
-     *
-     * @var integer $id
-     * @ORM\Column(name="id", type="integer")
-     * @ORM\Id
-     * @ORM\GeneratedValue(strategy="AUTO")
-     */
-    private $id;
-
     /**
      * Tag text
      *
-     * @var text $text
+     * @var string $text
      * @Assert\NotBlank()
      * @ORM\Column(name="text", type="string", length=255)
      */
-    private $text = '';
+    protected $text = '';
 
     /**
-     * @var Doctrine\Common\Collections\ArrayCollection
-     *
-     * @ORM\ManyToMany(targetEntity="Stfalcon\Bundle\BlogBundle\Entity\Post", mappedBy="tags")
-     */
-    private $posts;
-
-    /**
-     * Entity constructor
-     *
-     * @param string $text A tag text
-     *
-     * @return void
+     * @var ArrayCollection
      */
-    public function  __construct($text = null)
-    {
-        $this->text = $text;
-        $this->posts = new ArrayCollection();
-    }
+    protected $posts;
 
     /**
      * Get Tag id
@@ -86,16 +61,6 @@ public function getText()
         return $this->text;
     }
 
-    /**
-     * Get posts for this tag
-     *
-     * @return ArrayCollection
-     */
-    public function getPosts()
-    {
-        return $this->posts;
-    }
-
     /**
      * This method allows a class to decide how it will react when it is treated like a string
      *
@@ -103,6 +68,6 @@ public function getPosts()
      */
     public function __toString()
     {
-        return $this->getText();
+        return $this->getText()?$this->getText():'';
     }
 }
\ No newline at end of file
diff --git a/Entity/TagManager.php b/Entity/TagManager.php
new file mode 100644
index 0000000..33e7508
--- /dev/null
+++ b/Entity/TagManager.php
@@ -0,0 +1,127 @@
+objectManager = $om;
+        $metadata = $om->getClassMetadata($class);
+        $this->class = $metadata->getName();
+        $this->repository = $om->getRepository($class);
+    }
+
+    /**
+     * Create new category
+     *
+     * @param string|null $text
+     *
+     * @return mixed
+     */
+    public function create($text = null)
+    {
+        return new $this->class($text);
+    }
+
+    /**
+     * Remove category
+     *
+     * @param mixed $category
+     */
+    public function delete($category)
+    {
+        $this->objectManager->remove($category);
+        $this->objectManager->flush();
+    }
+
+    /**
+     * Save category
+     *
+     * @param mixed $category
+     */
+    public function save($category)
+    {
+        $this->objectManager->persist($category);
+        $this->objectManager->flush();
+    }
+
+    /**
+     * Get class name
+     *
+     * @return string
+     */
+    public function getClass()
+    {
+        return $this->class;
+    }
+
+    /**
+     * @return EntityRepository
+     */
+    public function getRepository()
+    {
+        return $this->repository;
+    }
+
+    /**
+     * Find one tag by id
+     *
+     * @param int $id
+     *
+     * @return object
+     */
+    public function findTag($id)
+    {
+        return $this->repository->find($id);
+    }
+
+    /**
+     * Find one tag by criteria
+     *
+     * @param array $criteria
+     *
+     * @return object
+     */
+    public function findTagBy(array $criteria)
+    {
+        return $this->repository->findOneBy($criteria);
+    }
+
+    /**
+     * Find tags by criteria
+     *
+     * @param array $criteria
+     *
+     * @return array
+     */
+    public function findTagsBy(array $criteria)
+    {
+        return $this->repository->findBy($criteria);
+    }
+
+    /**
+     * Find all tags
+     *
+     * @return mixed
+     */
+    public function findAllTags()
+    {
+        return $this->repository->findAll();
+    }
+}
diff --git a/Resources/config/admin.xml b/Resources/config/admin.xml
new file mode 100644
index 0000000..97ac8df
--- /dev/null
+++ b/Resources/config/admin.xml
@@ -0,0 +1,23 @@
+
+
+
+
+    
+        
+            
+            
+            %stfalcon_blog.post.entity%
+            %stfalcon_blog.post.admin.controller%
+        
+
+        
+            
+            
+            %stfalcon_blog.tag.entity%
+            %stfalcon_blog.tag.admin.controller%
+        
+    
+
+
diff --git a/Resources/config/orm.xml b/Resources/config/orm.xml
new file mode 100644
index 0000000..215789e
--- /dev/null
+++ b/Resources/config/orm.xml
@@ -0,0 +1,24 @@
+
+
+
+
+    
+        Stfalcon\Bundle\BlogBundle\Entity\PostManager
+        Stfalcon\Bundle\BlogBundle\Entity\TagManager
+    
+
+    
+        
+            
+            %stfalcon_blog.post.entity%
+        
+
+        
+            
+            %stfalcon_blog.tag.entity%
+        
+    
+
+
diff --git a/Resources/config/service.xml b/Resources/config/service.xml
deleted file mode 100644
index c9c2597..0000000
--- a/Resources/config/service.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
-    
-        Stfalcon\Bundle\BlogBundle\Admin\PostAdmin
-        Stfalcon\Bundle\BlogBundle\Entity\Post
-
-        Stfalcon\Bundle\BlogBundle\Admin\TagAdmin
-        Stfalcon\Bundle\BlogBundle\Entity\Tag
-    
-
-    
-        
-            
-            
-            %stfalcon_blog.admin.post.entity%
-            
-        
-        
-            
-            
-            %stfalcon_blog.admin.tag.entity%
-            
-        
-
-        
-            
-            
-        
-
-        
-            
-            
-        
-    
-
\ No newline at end of file
diff --git a/Resources/config/services.xml b/Resources/config/services.xml
new file mode 100644
index 0000000..88b8b3c
--- /dev/null
+++ b/Resources/config/services.xml
@@ -0,0 +1,18 @@
+
+
+
+
+    
+        
+            
+            
+        
+
+        
+            
+            
+        
+    
+
\ No newline at end of file
diff --git a/Resources/doc/index.md b/Resources/doc/index.md
index 551fc42..53100ad 100644
--- a/Resources/doc/index.md
+++ b/Resources/doc/index.md
@@ -106,10 +106,23 @@ In YAML:
 # app/config/config.yml
 # StfalconBlogBundle Configuration
 stfalcon_blog:
-    disqus_shortname: "your-disqus-shortname-goes-here"
+    disqus_shortname:     ~ # Required
     rss:
-        title: "your-blog-title-goes-here"
-        description: "your-blog-description-goes-here"
+        title:                ~
+        description:          ~
+    post:
+        entity:               ~ # Required
+        manager:              stfalcon_blog.post.manager.default
+        admin:
+            class:                Stfalcon\Bundle\BlogBundle\Admin\PostAdmin
+            controller:           SonataAdminBundle:CRUD
+    tag:
+        entity:               ~ # Required
+        manager:              stfalcon_blog.tag.manager.default
+        admin:
+            class:                Stfalcon\Bundle\BlogBundle\Admin\TagAdmin
+            controller:           SonataAdminBundle:CRUD
+
 
 # Sonata Configuration
 sonata_block:

From 8ba494b694919ee4d4905e98e418d3d2409e5c95 Mon Sep 17 00:00:00 2001
From: Olexandr Lensky 
Date: Thu, 19 Dec 2013 16:51:47 +0200
Subject: [PATCH 2/4] Changed for use repository

---
 .../EntitiesToStringTransformer.php           |  25 ++-
 Bridge/Doctrine/Form/Type/TagsType.php        |  18 +-
 Controller/AbstractController.php             |  30 ---
 Controller/CommentController.php              |   2 +-
 Controller/PostController.php                 |  11 +-
 Controller/TagController.php                  |   7 +-
 DependencyInjection/Configuration.php         |  83 ---------
 DependencyInjection/StfalconBlogExtension.php |  35 ++--
 Entity/PostManager.php                        | 171 ------------------
 Entity/TagManager.php                         | 127 -------------
 Repository/PostRepository.php                 |  56 +++---
 Repository/TagRepository.php                  |   2 +-
 Resources/config/admin.xml                    |   8 +
 Resources/config/orm.xml                      |  16 +-
 Resources/config/services.xml                 |   5 +-
 Resources/doc/index.md                        |   4 +-
 16 files changed, 111 insertions(+), 489 deletions(-)
 delete mode 100644 Controller/AbstractController.php
 delete mode 100644 DependencyInjection/Configuration.php
 delete mode 100644 Entity/PostManager.php
 delete mode 100644 Entity/TagManager.php

diff --git a/Bridge/Doctrine/Form/DataTransformer/EntitiesToStringTransformer.php b/Bridge/Doctrine/Form/DataTransformer/EntitiesToStringTransformer.php
index 2c1303a..fdc59e3 100644
--- a/Bridge/Doctrine/Form/DataTransformer/EntitiesToStringTransformer.php
+++ b/Bridge/Doctrine/Form/DataTransformer/EntitiesToStringTransformer.php
@@ -2,6 +2,7 @@
 
 namespace Stfalcon\Bundle\BlogBundle\Bridge\Doctrine\Form\DataTransformer;
 
+use Doctrine\ORM\EntityManager;
 use Stfalcon\Bundle\BlogBundle\Entity\TagManager;
 use Symfony\Component\Form\DataTransformerInterface;
 use Doctrine\Common\Collections\Collection;
@@ -17,18 +18,22 @@ class EntitiesToStringTransformer implements DataTransformerInterface
 {
 
     /**
-     * @var TagManager
+     * @var EntityManager $em
      */
-    protected $manager;
+    protected $em;
+    /** @var  string $class */
+    protected $class;
 
     /**
-     * Constructor injection. Set entity manager to object
+     * Constructor injection
      *
-     * @param TagManager $manager Tag manager
+     * @param EntityManager $em
+     * @param string        $class
      */
-    public function __construct(TagManager $manager)
+    public function __construct(EntityManager $em, $class)
     {
-        $this->manager = $manager;
+        $this->em = $em;
+        $this->class = $class;
     }
 
     /**
@@ -78,12 +83,12 @@ public function reverseTransform($data)
         if (!is_string($data)) {
             throw new UnexpectedTypeException($data, 'string');
         }
-
+        $repository = $this->em->getRepository($this->class);
         foreach ($this->_stringToArray($data) as $text) {
-            $tag = $this->manager->findTagBy(array('text' => $text));
+            $tag = $repository->findOneBy(array('text' => $text));
             if (!$tag) {
-                $tag = $this->manager->create($text);
-                $this->manager->save($tag);
+                $tag = new $this->class($text);
+                $this->em->persist($tag);
             }
             $collection->add($tag);
         }
diff --git a/Bridge/Doctrine/Form/Type/TagsType.php b/Bridge/Doctrine/Form/Type/TagsType.php
index 17c51ca..b1a523b 100644
--- a/Bridge/Doctrine/Form/Type/TagsType.php
+++ b/Bridge/Doctrine/Form/Type/TagsType.php
@@ -2,7 +2,7 @@
 
 namespace Stfalcon\Bundle\BlogBundle\Bridge\Doctrine\Form\Type;
 
-use Stfalcon\Bundle\BlogBundle\Entity\TagManager;
+use Doctrine\ORM\EntityManager;
 use Symfony\Component\Form\AbstractType;
 use Symfony\Component\Form\FormBuilderInterface;
 use Symfony\Bridge\Doctrine\RegistryInterface;
@@ -15,17 +15,21 @@
  */
 class TagsType extends AbstractType
 {
-
-    protected $tagManager;
+    /** @var  EntityManager $em */
+    protected $em;
+    /** @var  string $class */
+    protected $class;
 
     /**
      * Constructor injection
      *
-     * @param TagManager $manager Tag manager
+     * @param EntityManager $em
+     * @param string        $class
      */
-    public function __construct(TagManager $manager)
+    public function __construct(EntityManager $em, $class)
     {
-        $this->tagManager = $manager;
+        $this->em = $em;
+        $this->class = $class;
     }
 
     /**
@@ -39,7 +43,7 @@ public function __construct(TagManager $manager)
     public function buildForm(FormBuilderInterface $builder, array $options)
     {
         $builder->addModelTransformer(
-            new EntitiesToStringTransformer($this->tagManager)
+            new EntitiesToStringTransformer($this->em, $this->class)
         );
     }
 
diff --git a/Controller/AbstractController.php b/Controller/AbstractController.php
deleted file mode 100644
index 6d2a2c6..0000000
--- a/Controller/AbstractController.php
+++ /dev/null
@@ -1,30 +0,0 @@
-
- */
-class AbstractController extends Controller
-{
-
-    /**
-     * Added disqus_shortname to request data array
-     *
-     * @param array $requestData
-     * @return array
-     */
-    protected function _getRequestDataWithDisqusShortname($requestData)
-    {
-        $config = $this->container->getParameter('stfalcon_blog.config');
-        return array_merge(
-            $requestData,
-            array('disqus_shortname' => $config['disqus_shortname'])
-        );
-    }
-
-}
\ No newline at end of file
diff --git a/Controller/CommentController.php b/Controller/CommentController.php
index bb24ba0..42d112b 100644
--- a/Controller/CommentController.php
+++ b/Controller/CommentController.php
@@ -31,7 +31,7 @@ public function disqusSyncAction($slug)
         // @todo. нужно доставать полный список ЗААПРУВЛЕННЫХ комментариев или
         // колличество комментариев к записи (если такой метод появится в API disqus)
         // после чего обновлять их колличество в БД
-        $post = $this->get('stfalcon_blog.post.manager')->findPostBy(array('slug' => $slug));
+        $post = $this->get('stfalcon_blog.post.repository')->findOneBy(array('slug' => $slug));
         if (!$post) {
             throw new NotFoundHttpException();
         }
diff --git a/Controller/PostController.php b/Controller/PostController.php
index 841ccde..88a1afd 100644
--- a/Controller/PostController.php
+++ b/Controller/PostController.php
@@ -3,6 +3,7 @@
 namespace Stfalcon\Bundle\BlogBundle\Controller;
 
 use Symfony\Component\HttpFoundation\Response;
+use Symfony\Bundle\FrameworkBundle\Controller\Controller;
 use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
 use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@@ -12,7 +13,7 @@
  *
  * @author Stepan Tanasiychuk 
  */
-class PostController extends AbstractController
+class PostController extends Controller
 {
     /**
      * List of posts for admin
@@ -28,7 +29,7 @@ class PostController extends AbstractController
      */
     public function indexAction($page)
     {
-        $allPostsQuery = $this->get('stfalcon_blog.post.manager')->findAllPostsAsQuery();
+        $allPostsQuery = $this->get('stfalcon_blog.post.repository')->findAllPostsAsQuery();
         $posts= $this->get('knp_paginator')->paginate($allPostsQuery, $page, 10);
 
         if ($this->has('application_default.menu.breadcrumbs')) {
@@ -56,7 +57,7 @@ public function indexAction($page)
      */
     public function viewAction($slug)
     {
-        $post = $this->get('stfalcon_blog.post.manager')->findPostBy(array('slug' => $slug));
+        $post = $this->get('stfalcon_blog.post.repository')->findOneBy(array('slug' => $slug));
         if (!$post) {
             throw new NotFoundHttpException();
         }
@@ -87,7 +88,7 @@ public function rssAction()
         $feed->setDescription($this->container->getParameter('stfalcon_blog.rss.description'));
         $feed->setLink($this->generateUrl('blog_rss', array(), true));
 
-        $posts = $this->get('stfalcon_blog.post.manager')->findAllPosts();
+        $posts = $this->get('stfalcon_blog.post.repository')->findAllPosts();
         foreach ($posts as $post) {
             $entry = new \Zend\Feed\Writer\Entry();
             $entry->setTitle($post->getTitle());
@@ -110,7 +111,7 @@ public function rssAction()
      */
     public function lastAction($count = 1)
     {
-        $posts = $this->get('stfalcon_blog.post.manager')->findLastPosts($count);
+        $posts = $this->get('stfalcon_blog.post.repository')->findLastPosts($count);
 
         return array('posts' => $posts);
     }
diff --git a/Controller/TagController.php b/Controller/TagController.php
index b4780da..6c6ed13 100644
--- a/Controller/TagController.php
+++ b/Controller/TagController.php
@@ -4,6 +4,7 @@
 
 use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
 use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
+use Symfony\Bundle\FrameworkBundle\Controller\Controller;
 
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 
@@ -12,7 +13,7 @@
  *
  * @author Stepan Tanasiychuk 
  */
-class TagController extends AbstractController
+class TagController extends Controller
 {
 
     /**
@@ -32,12 +33,12 @@ class TagController extends AbstractController
      */
     public function viewAction($text, $page)
     {
-        $tag = $this->get('stfalcon_blog.tag.manager')->findTagBy(array('text' => $text));
+        $tag = $this->get('stfalcon_blog.tag.repository')->findOneBy(array('text' => $text));
         if (!$tag) {
             throw new NotFoundHttpException();
         }
 
-        $postsQuery = $this->get('stfalcon_blog.post.manager')->findPostsByTagAsQuery($tag);
+        $postsQuery = $this->get('stfalcon_blog.post.repository')->findPostsByTagAsQuery($tag);
         $posts = $this->get('knp_paginator')
             ->paginate($postsQuery, $page, 10);
 
diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php
deleted file mode 100644
index 2f67b5e..0000000
--- a/DependencyInjection/Configuration.php
+++ /dev/null
@@ -1,83 +0,0 @@
-root('stfalcon_blog');
-
-        $rootNode->children()
-            ->scalarNode('disqus_shortname')->isRequired()->cannotBeEmpty()->end()
-            ->arrayNode('rss')
-                ->addDefaultsIfNotSet()
-                ->canBeUnset()
-                ->children()
-                    ->scalarNode('title')->defaultNull()->end()
-                    ->scalarNode('description')->defaultNull()->end()
-                ->end()
-            ->end();
-
-
-        $this->addPostSection($rootNode);
-        $this->addTagSection($rootNode);
-
-        return $treeBuilder;
-    }
-
-    private function addPostSection(ArrayNodeDefinition $node)
-    {
-        $node
-            ->children()
-                ->arrayNode('post')
-                    ->children()
-                        ->scalarNode('entity')->isRequired()->cannotBeEmpty()->end()
-                        ->scalarNode('manager')->defaultValue('stfalcon_blog.post.manager.default')->end()
-                        ->arrayNode('admin')
-                            ->addDefaultsIfNotSet()
-                            ->children()
-                                ->scalarNode('class')->defaultValue('Stfalcon\\Bundle\\BlogBundle\\Admin\\PostAdmin')->end()
-                                ->scalarNode('controller')->defaultValue('SonataAdminBundle:CRUD')->end()
-                            ->end()
-                        ->end()
-                    ->end()
-                ->end()
-            ->end();
-    }
-
-    private function addTagSection(ArrayNodeDefinition $node)
-    {
-        $node
-            ->children()
-                ->arrayNode('tag')
-                    ->children()
-                        ->scalarNode('entity')->isRequired()->cannotBeEmpty()->end()
-                        ->scalarNode('manager')->defaultValue('stfalcon_blog.tag.manager.default')->end()
-                        ->arrayNode('admin')
-                            ->addDefaultsIfNotSet()
-                            ->children()
-                                ->scalarNode('class')->defaultValue('Stfalcon\\Bundle\\BlogBundle\\Admin\\TagAdmin')->end()
-                                ->scalarNode('controller')->defaultValue('SonataAdminBundle:CRUD')->end()
-                            ->end()
-                        ->end()
-                    ->end()
-                ->end()
-            ->end();
-    }
-}
diff --git a/DependencyInjection/StfalconBlogExtension.php b/DependencyInjection/StfalconBlogExtension.php
index 7531afe..0d9ab1f 100644
--- a/DependencyInjection/StfalconBlogExtension.php
+++ b/DependencyInjection/StfalconBlogExtension.php
@@ -28,10 +28,7 @@ class StfalconBlogExtension extends Extension
      */
     public function load(array $configs, ContainerBuilder $container)
     {
-        $processor = new Processor();
-        $configuration = new Configuration();
-
-        $config = $processor->processConfiguration($configuration, $configs);
+        $config = $configs[0];
 
         $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
 
@@ -39,22 +36,30 @@ public function load(array $configs, ContainerBuilder $container)
         $container->setParameter('stfalcon_blog.rss.title', $config['rss']['title']);
         $container->setParameter('stfalcon_blog.rss.description', $config['rss']['description']);
 
-        $loader->load('orm.xml');
         $container->setParameter('stfalcon_blog.post.entity', $config['post']['entity']);
-        $container->setAlias('stfalcon_blog.post.manager', $config['post']['manager']);
-        unset($config['post']['manager']);
-
         $container->setParameter('stfalcon_blog.tag.entity', $config['tag']['entity']);
-        $container->setAlias('stfalcon_blog.tag.manager', $config['tag']['manager']);
-        unset($config['tag']['manager']);
 
+        if (isset($config['post']['repository'])) {
+            $container->setParameter('stfalcon_blog.post.repository', $config['post']['repository']);
+        }
+        if (isset($config['tag']['repository'])) {
+            $container->setParameter('stfalcon_blog.tag.repository', $config['tag']['repository']);
+        }
+        $loader->load('orm.xml');
         $loader->load('admin.xml');
 
-        $container->setParameter('stfalcon_blog.post.admin.class', $config['post']['admin']['class']);
-        $container->setParameter('stfalcon_blog.post.admin.controller', $config['post']['admin']['controller']);
-
-        $container->setParameter('stfalcon_blog.tag.admin.class', $config['tag']['admin']['class']);
-        $container->setParameter('stfalcon_blog.tag.admin.controller', $config['tag']['admin']['controller']);
+        if (isset($config['post']['admin']['class'])) {
+            $container->setParameter('stfalcon_blog.post.admin.class', $config['post']['admin']['class']);
+        }
+        if (isset($config['post']['admin']['controller'])) {
+            $container->setParameter('stfalcon_blog.post.admin.controller', $config['post']['admin']['controller']);
+        }
+        if (isset($config['tag']['admin']['class'])) {
+            $container->setParameter('stfalcon_blog.tag.admin.class', $config['tag']['admin']['class']);
+        }
+        if (isset($config['tag']['admin']['controller'])) {
+            $container->setParameter('stfalcon_blog.tag.admin.controller', $config['tag']['admin']['controller']);
+        }
         $loader->load('services.xml');
     }
 
diff --git a/Entity/PostManager.php b/Entity/PostManager.php
deleted file mode 100644
index 08b6efb..0000000
--- a/Entity/PostManager.php
+++ /dev/null
@@ -1,171 +0,0 @@
-objectManager = $om;
-        $metadata = $om->getClassMetadata($class);
-        $this->class = $metadata->getName();
-        $this->repository = $om->getRepository($class);
-    }
-
-    /**
-     * Create new category
-     *
-     * @return mixed
-     */
-    public function create()
-    {
-        return new $this->class;
-    }
-
-    /**
-     * Remove category
-     *
-     * @param mixed $category
-     */
-    public function delete($category)
-    {
-        $this->objectManager->remove($category);
-        $this->objectManager->flush();
-    }
-
-    /**
-     * Save category
-     *
-     * @param mixed $category
-     */
-    public function save($category)
-    {
-        $this->objectManager->persist($category);
-        $this->objectManager->flush();
-    }
-
-    /**
-     * Get class name
-     *
-     * @return string
-     */
-    public function getClass()
-    {
-        return $this->class;
-    }
-
-    /**
-     * @return EntityRepository
-     */
-    public function getRepository()
-    {
-        return $this->repository;
-    }
-
-    /**
-     * Find one post by id
-     *
-     * @param int $id
-     *
-     * @return object
-     */
-    public function findPost($id)
-    {
-        return $this->repository->find($id);
-    }
-
-    /**
-     * Find one post by criteria
-     *
-     * @param array $criteria
-     *
-     * @return object
-     */
-    public function findPostBy(array $criteria)
-    {
-        return $this->repository->findOneBy($criteria);
-    }
-
-    /**
-     * Find posts by criteria
-     *
-     * @param array $criteria
-     *
-     * @return array
-     */
-    public function findPostsBy(array $criteria)
-    {
-        return $this->repository->findBy($criteria);
-    }
-
-    /**
-     * Find all posts
-     *
-     * @return mixed
-     */
-    public function findAllPosts()
-    {
-        return $this->findAllPostsAsQuery()->getResult();
-    }
-
-    /**
-     * Find all posts as query
-     *
-     * @return mixed
-     */
-    public function findAllPostsAsQuery()
-    {
-        return $this->repository->createQueryBuilder('p')
-            ->orderBy('p.created', 'DESC')
-            ->getQuery();
-    }
-
-    /**
-     * Find posts by tag as query
-     *
-     * @param mixed $tag
-     *
-     * @return mixed
-     */
-    public function findPostsByTagAsQuery($tag)
-    {
-        return $this->repository->createQueryBuilder('p')
-            ->join('p.tags', 't')
-            ->where('t = :tag')
-            ->orderBy('p.created', 'DESC')
-            ->setParameter('tag', $tag)
-            ->getQuery();
-    }
-
-    /**
-     * Get last posts
-     *
-     * @param integer $count Max count of returned posts
-     *
-     * @return array
-     */
-    public function findLastPosts($count = null)
-    {
-        $query = $this->findAllPostsAsQuery();
-        if ((int) $count) {
-            $query->setMaxResults($count);
-        }
-
-        return $query->getResult();
-    }
-}
diff --git a/Entity/TagManager.php b/Entity/TagManager.php
deleted file mode 100644
index 33e7508..0000000
--- a/Entity/TagManager.php
+++ /dev/null
@@ -1,127 +0,0 @@
-objectManager = $om;
-        $metadata = $om->getClassMetadata($class);
-        $this->class = $metadata->getName();
-        $this->repository = $om->getRepository($class);
-    }
-
-    /**
-     * Create new category
-     *
-     * @param string|null $text
-     *
-     * @return mixed
-     */
-    public function create($text = null)
-    {
-        return new $this->class($text);
-    }
-
-    /**
-     * Remove category
-     *
-     * @param mixed $category
-     */
-    public function delete($category)
-    {
-        $this->objectManager->remove($category);
-        $this->objectManager->flush();
-    }
-
-    /**
-     * Save category
-     *
-     * @param mixed $category
-     */
-    public function save($category)
-    {
-        $this->objectManager->persist($category);
-        $this->objectManager->flush();
-    }
-
-    /**
-     * Get class name
-     *
-     * @return string
-     */
-    public function getClass()
-    {
-        return $this->class;
-    }
-
-    /**
-     * @return EntityRepository
-     */
-    public function getRepository()
-    {
-        return $this->repository;
-    }
-
-    /**
-     * Find one tag by id
-     *
-     * @param int $id
-     *
-     * @return object
-     */
-    public function findTag($id)
-    {
-        return $this->repository->find($id);
-    }
-
-    /**
-     * Find one tag by criteria
-     *
-     * @param array $criteria
-     *
-     * @return object
-     */
-    public function findTagBy(array $criteria)
-    {
-        return $this->repository->findOneBy($criteria);
-    }
-
-    /**
-     * Find tags by criteria
-     *
-     * @param array $criteria
-     *
-     * @return array
-     */
-    public function findTagsBy(array $criteria)
-    {
-        return $this->repository->findBy($criteria);
-    }
-
-    /**
-     * Find all tags
-     *
-     * @return mixed
-     */
-    public function findAllTags()
-    {
-        return $this->repository->findAll();
-    }
-}
diff --git a/Repository/PostRepository.php b/Repository/PostRepository.php
index d0e21e2..402b5b1 100644
--- a/Repository/PostRepository.php
+++ b/Repository/PostRepository.php
@@ -9,46 +9,41 @@
  *
  * @author Stepan Tanasiychuk 
  */
-class PostRepository extends EntityRepository
+abstract class PostRepository extends EntityRepository
 {
 
     /**
-     * Get all posts
+     * Find all posts
      *
      * @return array
      */
-    public function getAllPosts()
+    public function findAllPosts()
     {
-        $query = $this->getEntityManager()->createQuery('
-            SELECT
-                p
-            FROM
-                StfalconBlogBundle:Post p
-            ORDER BY
-                p.created DESC
-            ');
+        $query = $this->findAllPostsAsQuery();
 
         return $query->getResult();
     }
 
     /**
-     * Get last posts
+     * @return mixed
+     */
+    public function findAllPostsAsQuery()
+    {
+        return $this->createQueryBuilder('p')
+            ->orderBy('p.created', 'DESC')
+            ->getQuery();
+    }
+
+    /**
+     * Find last posts
      *
      * @param integer $count Max count of returned posts
      *
      * @return array
      */
-    public function getLastPosts($count = null)
+    public function findLastPosts($count = null)
     {
-        $query = $this->getEntityManager()->createQuery('
-            SELECT
-                p
-            FROM
-                StfalconBlogBundle:Post p
-            ORDER BY
-                p.created DESC
-            ');
-
+        $query = $this->findAllPostsAsQuery();
         if ((int) $count) {
             $query->setMaxResults($count);
         }
@@ -56,4 +51,21 @@ public function getLastPosts($count = null)
         return $query->getResult();
     }
 
+    /**
+     * Find posts by tag as query
+     *
+     * @param mixed $tag
+     *
+     * @return mixed
+     */
+    public function findPostsByTagAsQuery($tag)
+    {
+        return $this->createQueryBuilder('p')
+            ->join('p.tags', 't')
+            ->where('t = :tag')
+            ->orderBy('p.created', 'DESC')
+            ->setParameter('tag', $tag)
+            ->getQuery();
+    }
+
 }
\ No newline at end of file
diff --git a/Repository/TagRepository.php b/Repository/TagRepository.php
index 3330591..408fe09 100644
--- a/Repository/TagRepository.php
+++ b/Repository/TagRepository.php
@@ -9,6 +9,6 @@
  *
  * @author Stepan Tanasiychuk 
  */
-class TagRepository extends EntityRepository
+abstract class TagRepository extends EntityRepository
 {
 }
\ No newline at end of file
diff --git a/Resources/config/admin.xml b/Resources/config/admin.xml
index 97ac8df..14862fa 100644
--- a/Resources/config/admin.xml
+++ b/Resources/config/admin.xml
@@ -4,6 +4,14 @@
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
 
+    
+        Stfalcon\Bundle\BlogBundle\Admin\PostAdmin
+        Stfalcon\Bundle\BlogBundle\Admin\TagAdmin
+
+        SonataAdminBundle:CRUD
+        SonataAdminBundle:CRUD
+    
+
     
         
             
diff --git a/Resources/config/orm.xml b/Resources/config/orm.xml
index 215789e..58fb72f 100644
--- a/Resources/config/orm.xml
+++ b/Resources/config/orm.xml
@@ -3,20 +3,16 @@
 
-
-    
-        Stfalcon\Bundle\BlogBundle\Entity\PostManager
-        Stfalcon\Bundle\BlogBundle\Entity\TagManager
-    
-
     
-        
-            
+        
             %stfalcon_blog.post.entity%
         
 
-        
-            
+        
             %stfalcon_blog.tag.entity%
         
     
diff --git a/Resources/config/services.xml b/Resources/config/services.xml
index 88b8b3c..ef92819 100644
--- a/Resources/config/services.xml
+++ b/Resources/config/services.xml
@@ -6,13 +6,14 @@
 
     
         
-            
+            
             
         
 
         
             
-            
+            
+            %stfalcon_blog.tag.entity%
         
     
 
\ No newline at end of file
diff --git a/Resources/doc/index.md b/Resources/doc/index.md
index 53100ad..ebaa8b9 100644
--- a/Resources/doc/index.md
+++ b/Resources/doc/index.md
@@ -112,13 +112,13 @@ stfalcon_blog:
         description:          ~
     post:
         entity:               ~ # Required
-        manager:              stfalcon_blog.post.manager.default
+        repository:           ~ # Required
         admin:
             class:                Stfalcon\Bundle\BlogBundle\Admin\PostAdmin
             controller:           SonataAdminBundle:CRUD
     tag:
         entity:               ~ # Required
-        manager:              stfalcon_blog.tag.manager.default
+        repository:           ~ # Required
         admin:
             class:                Stfalcon\Bundle\BlogBundle\Admin\TagAdmin
             controller:           SonataAdminBundle:CRUD

From 0f370bd65e4ab636fb6eece71953b172f904d3b1 Mon Sep 17 00:00:00 2001
From: Olexandr Lensky 
Date: Thu, 9 Jan 2014 17:56:52 +0200
Subject: [PATCH 3/4] added ID for entities

---
 Entity/Post.php | 15 +++++++++++++++
 Entity/Tag.php  |  7 +++++++
 2 files changed, 22 insertions(+)

diff --git a/Entity/Post.php b/Entity/Post.php
index 91e38dd..3ca9457 100644
--- a/Entity/Post.php
+++ b/Entity/Post.php
@@ -15,6 +15,13 @@
  */
 class Post
 {
+    /**
+     * @ORM\Id
+     * @ORM\Column(type="integer")
+     * @ORM\GeneratedValue(strategy="AUTO")
+     */
+    protected $id;
+
     /**
      * Post title
      *
@@ -80,6 +87,14 @@ class Post
      */
     protected $commentsCount = 0;
 
+    /**
+     * @return mixed
+     */
+    public function getId()
+    {
+        return $this->id;
+    }
+
     /**
      * Set post title
      *
diff --git a/Entity/Tag.php b/Entity/Tag.php
index b1fb1b9..68ac8d6 100644
--- a/Entity/Tag.php
+++ b/Entity/Tag.php
@@ -15,6 +15,13 @@
  */
 class Tag
 {
+    /**
+     * @ORM\Id
+     * @ORM\Column(type="integer")
+     * @ORM\GeneratedValue(strategy="AUTO")
+     */
+    protected $id;
+
     /**
      * Tag text
      *

From 1f8744875e07de4b45d709e95aca9bc8497aefd2 Mon Sep 17 00:00:00 2001
From: Olexandr Lensky 
Date: Fri, 17 Jan 2014 17:56:34 +0200
Subject: [PATCH 4/4] changes entities

---
 DependencyInjection/StfalconBlogExtension.php |  11 +-
 Entity/BasePost.php                           | 275 ++++++++++++++++++
 Entity/BaseTag.php                            |  80 +++++
 Entity/Post.php                               | 264 ++---------------
 Entity/Tag.php                                |  64 ++--
 Repository/PostRepository.php                 |   2 +-
 Repository/TagRepository.php                  |   2 +-
 Resources/config/orm.xml                      |   9 +
 8 files changed, 411 insertions(+), 296 deletions(-)
 create mode 100644 Entity/BasePost.php
 create mode 100644 Entity/BaseTag.php

diff --git a/DependencyInjection/StfalconBlogExtension.php b/DependencyInjection/StfalconBlogExtension.php
index 0d9ab1f..d7e425c 100644
--- a/DependencyInjection/StfalconBlogExtension.php
+++ b/DependencyInjection/StfalconBlogExtension.php
@@ -35,9 +35,13 @@ public function load(array $configs, ContainerBuilder $container)
         $container->setParameter('stfalcon_blog.disqus_shortname', $config['disqus_shortname']);
         $container->setParameter('stfalcon_blog.rss.title', $config['rss']['title']);
         $container->setParameter('stfalcon_blog.rss.description', $config['rss']['description']);
-
-        $container->setParameter('stfalcon_blog.post.entity', $config['post']['entity']);
-        $container->setParameter('stfalcon_blog.tag.entity', $config['tag']['entity']);
+        $loader->load('orm.xml');
+        if (isset($config['post']['entity'])) {
+            $container->setParameter('stfalcon_blog.post.entity', $config['post']['entity']);
+        }
+        if (isset($config['tag']['entity'])) {
+            $container->setParameter('stfalcon_blog.tag.entity', $config['tag']['entity']);
+        }
 
         if (isset($config['post']['repository'])) {
             $container->setParameter('stfalcon_blog.post.repository', $config['post']['repository']);
@@ -45,7 +49,6 @@ public function load(array $configs, ContainerBuilder $container)
         if (isset($config['tag']['repository'])) {
             $container->setParameter('stfalcon_blog.tag.repository', $config['tag']['repository']);
         }
-        $loader->load('orm.xml');
         $loader->load('admin.xml');
 
         if (isset($config['post']['admin']['class'])) {
diff --git a/Entity/BasePost.php b/Entity/BasePost.php
new file mode 100644
index 0000000..faf599c
--- /dev/null
+++ b/Entity/BasePost.php
@@ -0,0 +1,275 @@
+
+ * @ORM\MappedSuperclass
+ */
+class BasePost
+{
+    /**
+     * @ORM\Id
+     * @ORM\Column(type="integer")
+     * @ORM\GeneratedValue(strategy="AUTO")
+     */
+    protected $id;
+
+    /**
+     * Post title
+     *
+     * @var string $title
+     * @Assert\NotBlank()
+     * @ORM\Column(name="title", type="string", length=255)
+     */
+    protected $title = '';
+
+    /**
+     * @var string $slug
+     *
+     * @Assert\NotBlank()
+     * @Assert\MinLength(3)
+     * @ORM\Column(name="slug", type="string", length=128, unique=true)
+     */
+    protected $slug;
+
+    /**
+     * Post text
+     *
+     * @var string $text
+     * @Assert\NotBlank()
+     * @ORM\Column(name="text", type="text")
+     */
+    protected $text;
+
+    /**
+     * Post text as HTML code
+     *
+     * @var string $textAsHtml
+     * @ORM\Column(name="text_as_html", type="text")
+     */
+    protected $textAsHtml;
+
+    /**
+     * Tags for post
+     *
+     * @var ArrayCollection
+     */
+    protected $tags;
+
+    /**
+     * @var \DateTime $created
+     *
+     * @ORM\Column(type="datetime")
+     * @Gedmo\Timestampable(on="create")
+     */
+    protected $created;
+
+    /**
+     * @var \DateTime $updated
+     *
+     * @ORM\Column(type="datetime")
+     * @Gedmo\Timestampable(on="update")
+     */
+    protected $updated;
+
+    /**
+     * @var int $commentsCount
+     *
+     * @ORM\Column(type="integer")
+     */
+    protected $commentsCount = 0;
+
+    /**
+     * @return mixed
+     */
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    /**
+     * Set post title
+     *
+     * @param string $title Text of the title
+     *
+     * @return void
+     */
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    /**
+     * Get post title
+     *
+     * @return string
+     */
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    /**
+     * Set post slug
+     *
+     * @param string $slug Unique text identifier
+     *
+     * @return void
+     */
+    public function setSlug($slug)
+    {
+        $this->slug = $slug;
+    }
+
+    /**
+     * Get post slug
+     *
+     * @return string
+     */
+    public function getSlug()
+    {
+        return $this->slug;
+    }
+
+    /**
+     * Set post text
+     *
+     * @param string $text Text for post
+     *
+     * @return void
+     */
+    public function setText($text)
+    {
+        $this->text = $text;
+        $this->textAsHtml = $this->_transformTextAsHtml($text);
+    }
+
+    /**
+     * Get post text
+     *
+     * @return string
+     */
+    public function getText()
+    {
+        return $this->text;
+    }
+
+    /**
+     * Get post text as HTML code
+     *
+     * @return string
+     */
+    public function getTextAsHtml()
+    {
+        return $this->textAsHtml;
+    }
+
+
+    /**
+     * Transform post text to html
+     *
+     * @param string $text Source post text
+     *
+     * @return string Post text as html
+     */
+    private function _transformTextAsHtml($text)
+    {
+        // update text html code
+        require_once __DIR__ . '/../Resources/vendor/geshi/geshi.php';
+
+        $text = preg_replace_callback(
+            '/
\r?\n?(.*?)\r?\n?\<\/pre>/is',
+            function($data) {
+                $geshi = new \GeSHi($data[2], $data[1]);
+
+                return $geshi->parse_code();
+            }, $text
+        );
+
+        return $text;
+    }
+
+    /**
+     * Set time when post created
+     *
+     * @param \DateTime $created A time when post created
+     *
+     * @return void
+     */
+    public function setCreated(\DateTime $created)
+    {
+        $this->created = $created;
+    }
+
+    /**
+     * Get time when post created
+     *
+     * @return \DateTime
+     */
+    public function getCreated()
+    {
+        return $this->created;
+    }
+
+    /**
+     * Set time when post updated
+     *
+     * @param \DateTime $updated A time when post updated
+     *
+     * @return void
+     */
+    public function setUpdated(\DateTime $updated)
+    {
+        $this->updated = $updated;
+    }
+
+    /**
+     * Get time when post updated
+     *
+     * @return \DateTime
+     */
+    public function getUpdated()
+    {
+        return $this->updated;
+    }
+
+    /**
+     * Set comments count for post
+     *
+     * @param int $commentsCount A count of comments for post
+     *
+     * @return void
+     */
+    public function setCommentsCount($commentsCount)
+    {
+        $this->commentsCount = $commentsCount;
+    }
+
+    /**
+     * Get comments count for post
+     *
+     * @return int
+     */
+    public function getCommentsCount()
+    {
+        return $this->commentsCount;
+    }
+
+    /**
+     * This method allows a class to decide how it will react when it is treated like a string
+     *
+     * @return string
+     */
+    public function __toString()
+    {
+        return $this->getTitle()?$this->getTitle():'';
+    }
+}
\ No newline at end of file
diff --git a/Entity/BaseTag.php b/Entity/BaseTag.php
new file mode 100644
index 0000000..b7c1240
--- /dev/null
+++ b/Entity/BaseTag.php
@@ -0,0 +1,80 @@
+
+ *
+ * @ORM\MappedSuperclass
+ */
+class BaseTag
+{
+    /**
+     * @ORM\Id
+     * @ORM\Column(type="integer")
+     * @ORM\GeneratedValue(strategy="AUTO")
+     */
+    protected $id;
+
+    /**
+     * Tag text
+     *
+     * @var string $text
+     * @Assert\NotBlank()
+     * @ORM\Column(name="text", type="string", length=255)
+     */
+    protected $text = '';
+
+    /**
+     * @var ArrayCollection
+     */
+    protected $posts;
+
+    /**
+     * Get Tag id
+     *
+     * @return int
+     */
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    /**
+     * Set Tag text
+     *
+     * @param string $text A tag text
+     *
+     * @return void
+     */
+    public function setText($text)
+    {
+        $this->text = $text;
+    }
+
+    /**
+     * Get Tag text
+     *
+     * @return string
+     */
+    public function getText()
+    {
+        return $this->text;
+    }
+
+    /**
+     * This method allows a class to decide how it will react when it is treated like a string
+     *
+     * @return string
+     */
+    public function __toString()
+    {
+        return $this->getText()?$this->getText():'';
+    }
+}
\ No newline at end of file
diff --git a/Entity/Post.php b/Entity/Post.php
index 3ca9457..1fcffe8 100644
--- a/Entity/Post.php
+++ b/Entity/Post.php
@@ -3,273 +3,51 @@
 namespace Stfalcon\Bundle\BlogBundle\Entity;
 
 use Doctrine\Common\Collections\ArrayCollection;
-use Doctrine\ORM\Mapping as ORM;
 use Symfony\Component\Validator\Constraints as Assert;
-use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
 
 /**
- * Post entity
- *
- * @author Stepan Tanasiychuk 
- * @ORM\MappedSuperclass
+ * @ORM\Table(name="blog_posts_base")
+ * @ORM\Entity(repositoryClass="Stfalcon\Bundle\BlogBundle\Repository\PostRepository")
  */
-class Post
+class Post extends BasePost
 {
-    /**
-     * @ORM\Id
-     * @ORM\Column(type="integer")
-     * @ORM\GeneratedValue(strategy="AUTO")
-     */
-    protected $id;
-
-    /**
-     * Post title
-     *
-     * @var string $title
-     * @Assert\NotBlank()
-     * @ORM\Column(name="title", type="string", length=255)
-     */
-    protected $title = '';
-
-    /**
-     * @var string $slug
-     *
-     * @Assert\NotBlank()
-     * @Assert\MinLength(3)
-     * @ORM\Column(name="slug", type="string", length=128, unique=true)
-     */
-    protected $slug;
-
-    /**
-     * Post text
-     *
-     * @var string $text
-     * @Assert\NotBlank()
-     * @ORM\Column(name="text", type="text")
-     */
-    protected $text;
-
-    /**
-     * Post text as HTML code
-     *
-     * @var string $textAsHtml
-     * @ORM\Column(name="text_as_html", type="text")
-     */
-    protected $textAsHtml;
-
     /**
      * Tags for post
      *
      * @var ArrayCollection
+     * @Assert\NotBlank()
+     * @ORM\ManyToMany(targetEntity="Tag")
+     * @ORM\JoinTable(name="blog_posts_tags_base",
+     *      joinColumns={@ORM\JoinColumn(name="post_id", referencedColumnName="id")},
+     *      inverseJoinColumns={@ORM\JoinColumn(name="tag_id", referencedColumnName="id")}
+     *      )
      */
     protected $tags;
 
     /**
-     * @var \DateTime $created
-     *
-     * @ORM\Column(type="datetime")
-     * @Gedmo\Timestampable(on="create")
-     */
-    protected $created;
-
-    /**
-     * @var \DateTime $updated
-     *
-     * @ORM\Column(type="datetime")
-     * @Gedmo\Timestampable(on="update")
-     */
-    protected $updated;
-
-    /**
-     * @var int $commentsCount
-     *
-     * @ORM\Column(type="integer")
-     */
-    protected $commentsCount = 0;
-
-    /**
-     * @return mixed
-     */
-    public function getId()
-    {
-        return $this->id;
-    }
-
-    /**
-     * Set post title
-     *
-     * @param string $title Text of the title
-     *
-     * @return void
-     */
-    public function setTitle($title)
-    {
-        $this->title = $title;
-    }
-
-    /**
-     * Get post title
-     *
-     * @return string
-     */
-    public function getTitle()
-    {
-        return $this->title;
-    }
-
-    /**
-     * Set post slug
-     *
-     * @param string $slug Unique text identifier
-     *
-     * @return void
-     */
-    public function setSlug($slug)
-    {
-        $this->slug = $slug;
-    }
-
-    /**
-     * Get post slug
-     *
-     * @return string
+     * Initialization properties for new post entity
      */
-    public function getSlug()
+    public function __construct()
     {
-        return $this->slug;
+        $this->tags = new ArrayCollection();
     }
 
     /**
-     * Set post text
-     *
-     * @param string $text Text for post
+     * Get tags for this post
      *
-     * @return void
+     * @return ArrayCollection
      */
-    public function setText($text)
+    public function getTags()
     {
-        $this->text = $text;
-        $this->textAsHtml = $this->_transformTextAsHtml($text);
+        return $this->tags;
     }
 
     /**
-     * Get post text
-     *
-     * @return string
-     */
-    public function getText()
-    {
-        return $this->text;
-    }
-
-    /**
-     * Get post text as HTML code
-     *
-     * @return string
-     */
-    public function getTextAsHtml()
-    {
-        return $this->textAsHtml;
-    }
-
-
-    /**
-     * Transform post text to html
-     *
-     * @param string $text Source post text
-     *
-     * @return string Post text as html
-     */
-    private function _transformTextAsHtml($text)
-    {
-        // update text html code
-        require_once __DIR__ . '/../Resources/vendor/geshi/geshi.php';
-
-        $text = preg_replace_callback(
-            '/
\r?\n?(.*?)\r?\n?\<\/pre>/is',
-            function($data) {
-                $geshi = new \GeSHi($data[2], $data[1]);
-
-                return $geshi->parse_code();
-            }, $text
-        );
-
-        return $text;
-    }
-
-    /**
-     * Set time when post created
-     *
-     * @param \DateTime $created A time when post created
-     *
-     * @return void
-     */
-    public function setCreated(\DateTime $created)
-    {
-        $this->created = $created;
-    }
-
-    /**
-     * Get time when post created
-     *
-     * @return \DateTime
-     */
-    public function getCreated()
-    {
-        return $this->created;
-    }
-
-    /**
-     * Set time when post updated
-     *
-     * @param \DateTime $updated A time when post updated
-     *
-     * @return void
-     */
-    public function setUpdated(\DateTime $updated)
-    {
-        $this->updated = $updated;
-    }
-
-    /**
-     * Get time when post updated
-     *
-     * @return \DateTime
-     */
-    public function getUpdated()
-    {
-        return $this->updated;
-    }
-
-    /**
-     * Set comments count for post
-     *
-     * @param int $commentsCount A count of comments for post
-     *
-     * @return void
-     */
-    public function setCommentsCount($commentsCount)
-    {
-        $this->commentsCount = $commentsCount;
-    }
-
-    /**
-     * Get comments count for post
-     *
-     * @return int
-     */
-    public function getCommentsCount()
-    {
-        return $this->commentsCount;
-    }
-
-    /**
-     * This method allows a class to decide how it will react when it is treated like a string
-     *
-     * @return string
+     * @param ArrayCollection $tags
      */
-    public function __toString()
+    public function setTags($tags)
     {
-        return $this->getTitle()?$this->getTitle():'';
+        $this->tags = $tags;
     }
-}
\ No newline at end of file
+}
diff --git a/Entity/Tag.php b/Entity/Tag.php
index 68ac8d6..5b2b8e9 100644
--- a/Entity/Tag.php
+++ b/Entity/Tag.php
@@ -3,78 +3,48 @@
 namespace Stfalcon\Bundle\BlogBundle\Entity;
 
 use Doctrine\Common\Collections\ArrayCollection;
-use Doctrine\ORM\Mapping as ORM;
 use Symfony\Component\Validator\Constraints as Assert;
+use Doctrine\ORM\Mapping as ORM;
 
 /**
- * Stfalcon\Bundle\BlogBundle\Entity\Tag
- *
- * @author Stepan Tanasiychuk 
- *
- * @ORM\MappedSuperclass
+ * @ORM\Table(name="blog_tags")
+ * @ORM\Entity(repositoryClass="Stfalcon\Bundle\BlogBundle\Repository\TagRepository")
  */
-class Tag
+class Tag extends BaseTag
 {
-    /**
-     * @ORM\Id
-     * @ORM\Column(type="integer")
-     * @ORM\GeneratedValue(strategy="AUTO")
-     */
-    protected $id;
-
-    /**
-     * Tag text
-     *
-     * @var string $text
-     * @Assert\NotBlank()
-     * @ORM\Column(name="text", type="string", length=255)
-     */
-    protected $text = '';
-
     /**
      * @var ArrayCollection
-     */
-    protected $posts;
-
-    /**
-     * Get Tag id
      *
-     * @return int
+     * @ORM\ManyToMany(targetEntity="Post", mappedBy="tags")
      */
-    public function getId()
-    {
-        return $this->id;
-    }
+    protected $posts;
 
     /**
-     * Set Tag text
+     * Entity constructor
      *
      * @param string $text A tag text
-     *
-     * @return void
      */
-    public function setText($text)
+    public function  __construct($text = null)
     {
         $this->text = $text;
+        $this->posts = new ArrayCollection();
     }
 
     /**
-     * Get Tag text
+     * Get posts for this tag
      *
-     * @return string
+     * @return ArrayCollection
      */
-    public function getText()
+    public function getPosts()
     {
-        return $this->text;
+        return $this->posts;
     }
 
     /**
-     * This method allows a class to decide how it will react when it is treated like a string
-     *
-     * @return string
+     * @param ArrayCollection $posts
      */
-    public function __toString()
+    public function setPosts($posts)
     {
-        return $this->getText()?$this->getText():'';
+        $this->posts = $posts;
     }
-}
\ No newline at end of file
+}
diff --git a/Repository/PostRepository.php b/Repository/PostRepository.php
index 402b5b1..cd6b328 100644
--- a/Repository/PostRepository.php
+++ b/Repository/PostRepository.php
@@ -9,7 +9,7 @@
  *
  * @author Stepan Tanasiychuk 
  */
-abstract class PostRepository extends EntityRepository
+class PostRepository extends EntityRepository
 {
 
     /**
diff --git a/Repository/TagRepository.php b/Repository/TagRepository.php
index 408fe09..3330591 100644
--- a/Repository/TagRepository.php
+++ b/Repository/TagRepository.php
@@ -9,6 +9,6 @@
  *
  * @author Stepan Tanasiychuk 
  */
-abstract class TagRepository extends EntityRepository
+class TagRepository extends EntityRepository
 {
 }
\ No newline at end of file
diff --git a/Resources/config/orm.xml b/Resources/config/orm.xml
index 58fb72f..ab941fa 100644
--- a/Resources/config/orm.xml
+++ b/Resources/config/orm.xml
@@ -3,6 +3,15 @@
 
+
+    
+        Stfalcon\Bundle\BlogBundle\Entity\Post
+        Stfalcon\Bundle\BlogBundle\Entity\Tag
+
+        Stfalcon\Bundle\BlogBundle\Repository\PostRepository
+        Stfalcon\Bundle\BlogBundle\Repository\TagRepository
+    
+