├── Resources ├── doc │ ├── index.md │ ├── search.md │ ├── sphinx.md │ └── installation │ │ └── index.md ├── public │ ├── css │ │ ├── admin.css │ │ ├── main.css │ │ └── admin-login.css │ ├── img │ │ ├── like.png │ │ ├── default.png │ │ ├── not-like.png │ │ ├── social │ │ │ ├── rss.png │ │ │ ├── digg.png │ │ │ ├── dzone.png │ │ │ ├── gmail.png │ │ │ ├── home.png │ │ │ ├── mail.png │ │ │ ├── vimeo.png │ │ │ ├── zabox.png │ │ │ ├── behance.png │ │ │ ├── blogger.png │ │ │ ├── dribbble.png │ │ │ ├── facebook.png │ │ │ ├── flickr.png │ │ │ ├── forrst.png │ │ │ ├── google+.png │ │ │ ├── joyoge.png │ │ │ ├── lastfm.png │ │ │ ├── linkedin.png │ │ │ ├── netvibes.png │ │ │ ├── newsvine.png │ │ │ ├── picasa.png │ │ │ ├── reddit.png │ │ │ ├── tumblr.png │ │ │ ├── twitter.png │ │ │ ├── webblend.png │ │ │ ├── youtube.png │ │ │ ├── delicious.png │ │ │ ├── designbump.png │ │ │ ├── feedburner.png │ │ │ ├── friendfeed.png │ │ │ ├── friendster.png │ │ │ ├── pinterest.png │ │ │ ├── posterous.png │ │ │ ├── technorati.png │ │ │ ├── wordpress.png │ │ │ ├── designfloat.png │ │ │ ├── grooveshark.png │ │ │ ├── livejournal.png │ │ │ └── stumbleupon.png │ │ └── ajax-loader.gif │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff │ └── js │ │ ├── admin.js │ │ ├── cookie.js │ │ └── blog.js ├── views │ ├── layout.flash.html.twig │ ├── Post │ │ ├── view.botton.html.twig │ │ ├── view.related.html.twig │ │ ├── view.header.html.twig │ │ ├── view.tags.html.twig │ │ ├── index.item.html.twig │ │ ├── tag.html.twig │ │ ├── view.comment.html.twig │ │ ├── view.social.html.twig │ │ ├── index.html.twig │ │ └── view.html.twig │ ├── SiteMap │ │ ├── search.xml.twig │ │ ├── tag.xml.twig │ │ ├── post.xml.twig │ │ ├── archive.xml.twig │ │ └── index.xml.twig │ ├── Pagination │ │ ├── sortable_link.html.twig │ │ └── sliding.html.twig │ ├── Widget │ │ ├── banner.html.twig │ │ ├── links.html.twig │ │ ├── tags.html.twig │ │ ├── most.html.twig │ │ ├── latestPostRelated.html.twig │ │ ├── latestPost.html.twig │ │ ├── latestComment.html.twig │ │ ├── latestCommentRelated.html.twig │ │ └── postViewRelated.html.twig │ ├── Page │ │ ├── faq.html.twig │ │ ├── about.html.twig │ │ └── cookies.html.twig │ ├── Comment │ │ ├── index.html.twig │ │ ├── message.html.twig │ │ └── form.html.twig │ ├── Tag │ │ ├── all.html.twig │ │ └── index.html.twig │ ├── Search │ │ ├── form.html.twig │ │ └── index.html.twig │ ├── Report │ │ ├── mostViewed.html.twig │ │ ├── mostCommented.html.twig │ │ ├── mostRated.html.twig │ │ └── postedItems.html.twig │ ├── Feed │ │ └── index.xml.twig │ ├── Archive │ │ ├── index.html.twig │ │ └── page.html.twig │ ├── Profile │ │ └── edit.html.twig │ └── User │ │ └── register.html.twig └── config │ ├── sphinx.xml │ ├── imagine.xml │ ├── twig.xml │ ├── manager.xml │ └── search.xml ├── .gitignore ├── .travis.yml ├── Tests └── Functional │ └── PostControllerTest.php ├── .formatter.yml ├── Event ├── PostEvents.php ├── RatingEvents.php ├── PostEvent.php └── RatingEvent.php ├── BlogBundle.php ├── Model ├── CommentStatus.php ├── Gravatar.php ├── LinkStatus.php └── PostStatus.php ├── Entity ├── Repository │ ├── ImageRepository.php │ ├── AuthorRepository.php │ ├── PostHistoryRepository.php │ ├── PostClickRepository.php │ ├── PostViewRepository.php │ ├── BannerRepository.php │ ├── LinkRepository.php │ └── CommentRepository.php ├── User.php ├── Image.php ├── Profile.php ├── Author.php ├── Tag.php ├── Comment.php ├── PostHistory.php └── Banner.php ├── composer.json ├── EventListener ├── PostListener.php └── RatingPostListener.php ├── phpunit.xml.dist ├── Twig └── TwigExtension.php ├── Form ├── Model │ ├── CommentModel.php │ ├── SearchModel.php │ └── ProfileModel.php ├── Type │ ├── CommentType.php │ ├── SearchType.php │ └── ProfileType.php └── Handler │ ├── SearchHandler.php │ ├── ProfileHandler.php │ └── CommentHandler.php ├── Search ├── SearchInterface.php ├── AbstractSearch.php ├── MySQL.php └── Sphinx.php ├── Controller ├── PageController.php ├── RatingController.php ├── RedirectController.php ├── SearchController.php ├── ProfileController.php ├── CommentController.php ├── FeedController.php ├── WidgetController.php ├── TagController.php ├── SiteMapController.php ├── ArchiveController.php └── PostController.php ├── Manager ├── SanitizerManager.php ├── ProfileManager.php ├── RatingManager.php ├── PostManager.php ├── SearchManager.php └── AbstractManager.php ├── README.md ├── .scrutinizer.yml └── DependencyInjection ├── BlogExtension.php └── Configuration.php /Resources/doc/index.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Resources/public/css/admin.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Resources/public/css/main.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Resources/public/css/admin-login.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Resources/views/layout.flash.html.twig: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Resources/views/Post/view.botton.html.twig: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Resources/views/SiteMap/search.xml.twig: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Resources/public/img/like.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/like.png -------------------------------------------------------------------------------- /Resources/public/img/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/default.png -------------------------------------------------------------------------------- /Resources/public/img/not-like.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/not-like.png -------------------------------------------------------------------------------- /Resources/public/img/social/rss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/rss.png -------------------------------------------------------------------------------- /Resources/public/img/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/ajax-loader.gif -------------------------------------------------------------------------------- /Resources/public/img/social/digg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/digg.png -------------------------------------------------------------------------------- /Resources/public/img/social/dzone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/dzone.png -------------------------------------------------------------------------------- /Resources/public/img/social/gmail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/gmail.png -------------------------------------------------------------------------------- /Resources/public/img/social/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/home.png -------------------------------------------------------------------------------- /Resources/public/img/social/mail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/mail.png -------------------------------------------------------------------------------- /Resources/public/img/social/vimeo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/vimeo.png -------------------------------------------------------------------------------- /Resources/public/img/social/zabox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/zabox.png -------------------------------------------------------------------------------- /Resources/public/img/social/behance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/behance.png -------------------------------------------------------------------------------- /Resources/public/img/social/blogger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/blogger.png -------------------------------------------------------------------------------- /Resources/public/img/social/dribbble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/dribbble.png -------------------------------------------------------------------------------- /Resources/public/img/social/facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/facebook.png -------------------------------------------------------------------------------- /Resources/public/img/social/flickr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/flickr.png -------------------------------------------------------------------------------- /Resources/public/img/social/forrst.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/forrst.png -------------------------------------------------------------------------------- /Resources/public/img/social/google+.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/google+.png -------------------------------------------------------------------------------- /Resources/public/img/social/joyoge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/joyoge.png -------------------------------------------------------------------------------- /Resources/public/img/social/lastfm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/lastfm.png -------------------------------------------------------------------------------- /Resources/public/img/social/linkedin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/linkedin.png -------------------------------------------------------------------------------- /Resources/public/img/social/netvibes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/netvibes.png -------------------------------------------------------------------------------- /Resources/public/img/social/newsvine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/newsvine.png -------------------------------------------------------------------------------- /Resources/public/img/social/picasa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/picasa.png -------------------------------------------------------------------------------- /Resources/public/img/social/reddit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/reddit.png -------------------------------------------------------------------------------- /Resources/public/img/social/tumblr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/tumblr.png -------------------------------------------------------------------------------- /Resources/public/img/social/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/twitter.png -------------------------------------------------------------------------------- /Resources/public/img/social/webblend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/webblend.png -------------------------------------------------------------------------------- /Resources/public/img/social/youtube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/youtube.png -------------------------------------------------------------------------------- /Resources/public/img/social/delicious.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/delicious.png -------------------------------------------------------------------------------- /Resources/public/img/social/designbump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/designbump.png -------------------------------------------------------------------------------- /Resources/public/img/social/feedburner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/feedburner.png -------------------------------------------------------------------------------- /Resources/public/img/social/friendfeed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/friendfeed.png -------------------------------------------------------------------------------- /Resources/public/img/social/friendster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/friendster.png -------------------------------------------------------------------------------- /Resources/public/img/social/pinterest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/pinterest.png -------------------------------------------------------------------------------- /Resources/public/img/social/posterous.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/posterous.png -------------------------------------------------------------------------------- /Resources/public/img/social/technorati.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/technorati.png -------------------------------------------------------------------------------- /Resources/public/img/social/wordpress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/wordpress.png -------------------------------------------------------------------------------- /Resources/views/Pagination/sortable_link.html.twig: -------------------------------------------------------------------------------- 1 | {{ title }} 2 | -------------------------------------------------------------------------------- /Resources/public/img/social/designfloat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/designfloat.png -------------------------------------------------------------------------------- /Resources/public/img/social/grooveshark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/grooveshark.png -------------------------------------------------------------------------------- /Resources/public/img/social/livejournal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/livejournal.png -------------------------------------------------------------------------------- /Resources/public/img/social/stumbleupon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/img/social/stumbleupon.png -------------------------------------------------------------------------------- /Resources/public/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /Resources/public/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /Resources/views/Widget/banner.html.twig: -------------------------------------------------------------------------------- 1 | {% if banner %} 2 |
3 | {{ banner.content | raw }} 4 |
5 | {% endif %} 6 | -------------------------------------------------------------------------------- /Resources/public/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desarrolla2/BlogBundle/HEAD/Resources/public/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /Resources/views/Post/view.related.html.twig: -------------------------------------------------------------------------------- 1 | {# 2 |

Entradas relacionadas

3 | {{ render(controller('BlogBundle:Widget:postViewRelated', { 'post': post })) }} 4 | #} 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bin 2 | /build 3 | /composer.lock 4 | /phpunit.xml 5 | /Tests/Controller/App/cache 6 | /Tests/Controller/App/logs 7 | /vendor/* 8 | /.idea 9 | *~ 10 | *.swp 11 | composer.lock -------------------------------------------------------------------------------- /Resources/views/Post/view.header.html.twig: -------------------------------------------------------------------------------- 1 |
2 |

3 | {{ post }} 5 |

6 |
7 | -------------------------------------------------------------------------------- /Resources/views/Widget/links.html.twig: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /Resources/views/Post/view.tags.html.twig: -------------------------------------------------------------------------------- 1 | {% if tags | length %} 2 | 7 | {% endif %} 8 | -------------------------------------------------------------------------------- /Resources/views/SiteMap/tag.xml.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% for item in items %} 4 | 5 | {{ item }} 6 | 7 | {% endfor %} 8 | 9 | -------------------------------------------------------------------------------- /Resources/views/SiteMap/post.xml.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% for item in items %} 4 | 5 | {{ item }} 6 | 7 | {% endfor %} 8 | 9 | -------------------------------------------------------------------------------- /Resources/views/Page/faq.html.twig: -------------------------------------------------------------------------------- 1 | {% extends "BlogBundle::layout.html.twig" %} 2 | {% block title %} FAQ {% endblock %} 3 | {% block main %} 4 |
5 |

FAQ

6 |
7 |

Please redefine this template

8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /Resources/views/Page/about.html.twig: -------------------------------------------------------------------------------- 1 | {% extends "BlogBundle::layout.html.twig" %} 2 | {% block title %} About US {% endblock %} 3 | {% block main %} 4 |
5 |

About US

6 |
7 |

Please redefine this template

8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /Resources/views/Comment/index.html.twig: -------------------------------------------------------------------------------- 1 | {% extends "BlogBundle::layout.html.twig" %} 2 | {% block title %} Añade un comentario {% endblock %} 3 | {% block meta_robots %}noindex{% endblock %} 4 | {% block main %} 5 | {% include 'BlogBundle:/Comment:form.html.twig' with {'form': form, 'post': post } %} 6 | {% endblock %} 7 | -------------------------------------------------------------------------------- /Resources/views/Page/cookies.html.twig: -------------------------------------------------------------------------------- 1 | {% extends "BlogBundle::layout.html.twig" %} 2 | {% block title %} Politica de cookies {% endblock %} 3 | {% block main %} 4 |
5 |

Politica de cookies

6 |
7 |

Please redefine this template

8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /Resources/views/Widget/tags.html.twig: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.3 5 | - 5.4 6 | - 5.5 7 | - 5.6 8 | - hhvm 9 | 10 | notifications: 11 | email: 12 | - daniel@desarrolla2.com 13 | 14 | before_script: 15 | - composer update --prefer-source --dev --verbose --optimize-autoloader --profile 16 | - cp phpunit.xml.dist phpunit.xml 17 | -------------------------------------------------------------------------------- /Resources/views/Widget/most.html.twig: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /Resources/views/SiteMap/archive.xml.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% for year, posts in items %} 4 | {% for item in posts %} 5 | 6 | {{ url('_blog_archive_page' , 7 | { 'year' : item.date.format('Y'), 'month': item.date.format('m') }) }} 8 | 9 | {% endfor %} 10 | {% endfor %} 11 | 12 | -------------------------------------------------------------------------------- /Tests/Functional/PostControllerTest.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | class PostControllerTest 15 | { 16 | // Not ready 17 | } 18 | -------------------------------------------------------------------------------- /Resources/views/Widget/latestPostRelated.html.twig: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /Resources/views/Widget/latestPost.html.twig: -------------------------------------------------------------------------------- 1 | 15 | -------------------------------------------------------------------------------- /Resources/views/Tag/all.html.twig: -------------------------------------------------------------------------------- 1 | {% extends "BlogBundle::layout.html.twig" %} 2 | {% block title %} Todos los Tags {% endblock %} 3 | {% block main %} 4 | 11 | 12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /Resources/views/SiteMap/index.xml.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ url('_blog_sitemap_post') }} 5 | 6 | 7 | {{ url('_blog_sitemap_tag') }} 8 | 9 | 10 | {{ url('_blog_sitemap_archive') }} 11 | 12 | 13 | {{ url('_blog_sitemap_search') }} 14 | 15 | 16 | -------------------------------------------------------------------------------- /Resources/views/Comment/message.html.twig: -------------------------------------------------------------------------------- 1 | {% extends "BlogBundle::layout.html.twig" %} 2 | {% block main %} 3 |
4 |
5 |

Gracias

6 |
7 |

8 | Hemos recibido tu comentario, un administrador lo examinará para 9 | aprobarlo lo antes posible, puedes continuar navegando por los últimos 10 | elementos publicados en el sitio. 11 |

12 | {{ render(controller('BlogBundle:\\Widget:latestPost')) }} 13 |
14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /.formatter.yml: -------------------------------------------------------------------------------- 1 | use-sort: 2 | group: 3 | - _main 4 | - Sod 5 | group-type: each 6 | sort-type: alph 7 | sort-direction: asc 8 | 9 | header: | 10 | /* 11 | * This file is part of the BlogBundle package. 12 | * 13 | * Copyright (c) daniel@desarrolla2.com 14 | * 15 | * For the full copyright and license information, please view the LICENSE 16 | * file that was distributed with this source code. 17 | * 18 | * @author Daniel González 19 | */ -------------------------------------------------------------------------------- /Event/PostEvents.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Event; 15 | 16 | /** 17 | * PostEvents 18 | */ 19 | class PostEvents 20 | { 21 | const VISITED = 'blog.post.visited'; 22 | } 23 | -------------------------------------------------------------------------------- /BlogBundle.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle; 15 | 16 | use Symfony\Component\HttpKernel\Bundle\Bundle; 17 | 18 | /** 19 | * BlogBundle 20 | */ 21 | class BlogBundle extends Bundle 22 | { 23 | } 24 | -------------------------------------------------------------------------------- /Event/RatingEvents.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Event; 15 | 16 | /** 17 | * RatingEvents 18 | */ 19 | final class RatingEvents 20 | { 21 | const PERSISTED = 'blog.rating.persisted'; 22 | } 23 | -------------------------------------------------------------------------------- /Resources/views/Widget/latestComment.html.twig: -------------------------------------------------------------------------------- 1 | 17 | -------------------------------------------------------------------------------- /Resources/views/Widget/latestCommentRelated.html.twig: -------------------------------------------------------------------------------- 1 | 17 | -------------------------------------------------------------------------------- /Model/CommentStatus.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Model; 15 | 16 | /** 17 | * CommentStatus 18 | */ 19 | class CommentStatus 20 | { 21 | const PENDING = 1000; 22 | const APPROVED = 2000; 23 | const DENIED = 3000; 24 | } 25 | -------------------------------------------------------------------------------- /Entity/Repository/ImageRepository.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Entity\Repository; 15 | 16 | use Doctrine\ORM\EntityRepository; 17 | 18 | /** 19 | * ImageRepository 20 | */ 21 | class ImageRepository extends EntityRepository 22 | { 23 | } 24 | -------------------------------------------------------------------------------- /Entity/Repository/AuthorRepository.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Entity\Repository; 15 | 16 | use Doctrine\ORM\EntityRepository; 17 | 18 | /** 19 | * AuthorRepository 20 | */ 21 | class AuthorRepository extends EntityRepository 22 | { 23 | } 24 | -------------------------------------------------------------------------------- /Entity/Repository/PostHistoryRepository.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Entity\Repository; 15 | 16 | use Doctrine\ORM\EntityRepository; 17 | 18 | /** 19 | * PostHistoryRepository 20 | */ 21 | class PostHistoryRepository extends EntityRepository 22 | { 23 | } 24 | -------------------------------------------------------------------------------- /Resources/views/Search/form.html.twig: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /Resources/views/Post/index.item.html.twig: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | {{ post }} 5 |

6 |
7 | {{ post.intro | raw }} 8 | {% if post.hasSource %} 9 |

Fuente: 10 | {{ post }} 12 |

13 | {% endif %} 14 | 17 |
18 | -------------------------------------------------------------------------------- /Resources/views/Post/tag.html.twig: -------------------------------------------------------------------------------- 1 | {% extends "BlogBundle::layout.html.twig" %} 2 | {% block title %} {{ tag }} {% endblock %} 3 | {% block main %} 4 | {% for post in pagination %} 5 | {% include 'BlogBundle:Post:index.item.html.twig' with {'post': post} %} 6 | {% else %} 7 |

No hay elementos

8 | {% endfor %} 9 | 10 | 13 | {% endblock %} 14 | 15 | {% block rss %} 16 | 18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /Resources/views/Widget/postViewRelated.html.twig: -------------------------------------------------------------------------------- 1 | {% if related %} 2 |
3 | {% for post in related %} 4 |
5 |

6 | {{ post }}

7 | {% if post.hasImage %} 8 | 9 | {{ post }} 10 | 11 | {% endif %} 12 |

13 |

14 | {% else %} 15 |

No hay elementos

16 | {% endfor %} 17 |
18 | {% endif %} 19 | -------------------------------------------------------------------------------- /Model/Gravatar.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Model; 15 | 16 | /** 17 | * 18 | * Description of Gravatar 19 | * 20 | * @author : Daniel González 21 | * @file : Gravatar.php , UTF-8 22 | * @date : Jan 26, 2013 , 1:16:22 AM 23 | */ 24 | class Gravatar 25 | { 26 | const URL = 'http://www.gravatar.com/avatar/'; 27 | } 28 | -------------------------------------------------------------------------------- /Resources/views/Post/view.comment.html.twig: -------------------------------------------------------------------------------- 1 | {% for comment in comments %} 2 |
3 |
4 | 6 |
7 |
8 |

9 | {{ comment.userName }} 10 | 13 | {{ comment | raw }} 14 |

15 |
16 |
17 | {% endfor %} 18 | {% include 'BlogBundle:/Comment:form.html.twig' with {'form': form, 'post': post } %} 19 | -------------------------------------------------------------------------------- /Resources/views/Comment/form.html.twig: -------------------------------------------------------------------------------- 1 |

Dejanos tu comentario

2 |
4 |
5 | {% if form_errors(form) %} 6 |
{{ form_errors(form) }}
7 | {% endif %} 8 |
9 |

10 | 11 | {% if form_errors(form.content) %} 12 | 13 |

{{ form_errors(form.content) }}
14 | {% endif %} 15 | {{ form_widget(form.content) }} 16 |

17 |
18 |
19 | 20 | {{ form_rest(form) }} 21 |
22 |

Los campos marcados con (*) son obligatorios

23 | -------------------------------------------------------------------------------- /Model/LinkStatus.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Model; 15 | 16 | /** 17 | * 18 | * Description of LinkStatus 19 | * 20 | * @author : Daniel González Cerviño 21 | * @file : LinkStatus.php , UTF-8 22 | * @date : Mar 26, 2013 , 7:00:15 PM 23 | */ 24 | class LinkStatus 25 | { 26 | /** 27 | * The entity was created 28 | */ 29 | const CREATED = 0; 30 | 31 | /** 32 | * The entity was publised 33 | */ 34 | const PUBLISHED = 1; 35 | 36 | /** 37 | * 38 | */ 39 | const REMOVED = 50; 40 | } 41 | -------------------------------------------------------------------------------- /Resources/public/js/admin.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function () { 2 | var base_url = window.location.protocol + "//" + window.location.host + "/"; 3 | tinyMCE.init({ 4 | keep_styles: false, 5 | preformatted: true, 6 | content_css: '/bundles/blog/css/textarea.css', 7 | selector: ".wysiwyg", 8 | theme: "modern", 9 | plugins: [ 10 | "advlist autolink lists link image preview hr anchor pagebreak", 11 | "searchreplace wordcount visualblocks visualchars code fullscreen", 12 | "insertdatetime media nonbreaking save table contextmenu directionality", 13 | "template paste textcolor" 14 | ], 15 | toolbar1: " undo redo | styleselect | bold italic forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image media preview", 16 | image_advtab: true 17 | }); 18 | }); -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "desarrolla2/blog-bundle", 3 | "type": "symfony-bundle", 4 | "description": "This Bundle provides a simple blog site features.", 5 | "keywords": [ 6 | "blog", 7 | "cms" 8 | ], 9 | "license": "MIT", 10 | "minimum-stability": "dev", 11 | "authors": [ 12 | { 13 | "name": "Daniel González", 14 | "homepage": "http://desarrolla2.com/" 15 | } 16 | ], 17 | "require": { 18 | "php": ">=5.4", 19 | "knplabs/knp-paginator-bundle": "~2.4.1", 20 | "friendsofsymfony/user-bundle": "~2.0@dev", 21 | "neutron/sphinxsearch-api": "~2.0.8", 22 | "desarrolla2/cache": "*" 23 | }, 24 | "require-dev": { 25 | "liip/functional-test-bundle": "~1.0.2" 26 | }, 27 | "autoload": { 28 | "psr-4": { 29 | "Desarrolla2\\Bundle\\BlogBundle\\": "" 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /EventListener/PostListener.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\EventListener; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Event\PostEvent; 17 | use Desarrolla2\Bundle\BlogBundle\Manager\PostManager; 18 | 19 | /** 20 | * PostListener 21 | */ 22 | class PostListener 23 | { 24 | /** 25 | * @param PostManager $postManager 26 | */ 27 | public function __construct(PostManager $postManager) 28 | { 29 | $this->postManager = $postManager; 30 | } 31 | 32 | /** 33 | * @param PostEvent $event 34 | */ 35 | public function onVisited(PostEvent $event) 36 | { 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Event/PostEvent.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Event; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Entity\Post; 17 | use Symfony\Component\EventDispatcher\Event; 18 | 19 | /** 20 | * PostEvent 21 | */ 22 | class PostEvent extends Event 23 | { 24 | /** 25 | * @var Post 26 | */ 27 | protected $post; 28 | 29 | /** 30 | * @param Post $post 31 | */ 32 | public function __construct(Post $post) 33 | { 34 | $this->post = $post; 35 | } 36 | 37 | /** 38 | * @return Post 39 | */ 40 | public function getPost() 41 | { 42 | return $this->post; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Event/RatingEvent.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Event; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Entity\Rating; 17 | use Symfony\Component\EventDispatcher\Event; 18 | 19 | /** 20 | * RatingEvent 21 | */ 22 | class RatingEvent extends Event 23 | { 24 | /** 25 | * @var Rating 26 | */ 27 | protected $rating; 28 | 29 | /** 30 | * @param Rating $rating 31 | */ 32 | public function __construct(Rating $rating) 33 | { 34 | $this->rating = $rating; 35 | } 36 | 37 | /** 38 | * @return Rating 39 | */ 40 | public function getRating() 41 | { 42 | return $this->rating; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Model/PostStatus.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Model; 15 | 16 | /** 17 | * 18 | * Description of PostStatus 19 | * 20 | * @author : Daniel González 21 | * @file : PostStatus.php , UTF-8 22 | * @date : Mar 26, 2013 , 12:25:41 AM 23 | */ 24 | class PostStatus 25 | { 26 | /** 27 | * The entity was created 28 | */ 29 | const CREATED = 0; 30 | 31 | /** 32 | * The entity is waiting for publish 33 | */ 34 | const PRE_PUBLISHED = 2; 35 | 36 | /** 37 | * The entity was publised 38 | */ 39 | const PUBLISHED = 1; 40 | 41 | /** 42 | * 43 | */ 44 | const REMOVED = 50; 45 | } 46 | -------------------------------------------------------------------------------- /Resources/doc/search.md: -------------------------------------------------------------------------------- 1 | ############################################################################# 2 | ## data source definition 3 | ############################################################################# 4 | 5 | source my_soruce 6 | { 7 | type = mysql 8 | sql_host = localhost 9 | sql_user = my_userl 10 | sql_pass = my_pass 11 | sql_db = my_db 12 | sql_port = my_port 13 | 14 | sql_query = \ 15 | SELECT id, name, intro, content \ 16 | FROM post \ 17 | WHERE status = 1 \ 18 | ORDER BY published_at DESC 19 | 20 | sql_query_info = \ 21 | SELECT name \ 22 | FROM post \ 23 | WHERE id=$id 24 | 25 | } 26 | 27 | 28 | ############################################################################# 29 | ## index definition 30 | ############################################################################# 31 | 32 | 33 | index my_source 34 | { 35 | source = my_source 36 | path = /var/lib/sphinxsearch/data/my_source 37 | docinfo = extern 38 | min_word_len = 3 39 | charset_type = utf-8 40 | html_strip = 0 41 | } -------------------------------------------------------------------------------- /Resources/config/sphinx.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Desarrolla2\Bundle\BlogBundle\Search\Sphinx 7 | 8 | 9 | 10 | 11 | 12 | 13 | %blog.search.sphinx.host% 14 | %blog.search.sphinx.port% 15 | %blog.search.sphinx.index% 16 | 17 | %blog.search.sphinx.items% 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Resources/public/js/cookie.js: -------------------------------------------------------------------------------- 1 | var Cookie = (function () { 2 | return { 3 | get: function (key) { 4 | var name = key + "="; 5 | var ca = document.cookie.split(';'); 6 | for (var i = 0; i < ca.length; i++) { 7 | var c = ca[i].trim(); 8 | if (c.indexOf(name) == 0) return c.substring(name.length, c.length); 9 | } 10 | return ""; 11 | }, 12 | set: function (key, value, days) { 13 | var d = new Date(); 14 | d.setTime(d.getTime() + (days * 24 * 60 * 60 * 1000)); 15 | var expires = "expires=" + d.toGMTString(); 16 | document.cookie = key + "=" + value + "; " + expires; 17 | }, 18 | remove: function (key) { 19 | this.set(key, '', -1); 20 | }, 21 | clear: function () { 22 | var cookies = document.cookie.split(";"); 23 | for (var i = 0; i < cookies.length; i++) 24 | this.set(cookies[i].split("=")[0], '', -1); 25 | } 26 | } 27 | }()); -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ./Tests/ 10 | 11 | 12 | 13 | 14 | 15 | ./ 16 | 17 | ./build 18 | ./vendor 19 | ./Resources 20 | ./Tests 21 | 22 | 23 | 24 | 25 | 26 | 27 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Resources/config/imagine.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 9 | 10 | %blog.default_image% 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Twig/TwigExtension.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Twig; 15 | 16 | /** 17 | * TwigExtension 18 | */ 19 | class TwigExtension extends \Twig_Extension 20 | { 21 | /** 22 | * @return array 23 | */ 24 | public function getFilters() 25 | { 26 | return [ 27 | 'highlight' => new \Twig_Filter_Method($this, 'highlight'), 28 | ]; 29 | } 30 | 31 | /** 32 | * @param string $subject 33 | * @param string $search 34 | * 35 | * @return mixed 36 | */ 37 | public function highlight($subject, $search) 38 | { 39 | $replace = ''.$search.''; 40 | 41 | return str_ireplace($search, $replace, $subject); 42 | } 43 | 44 | /** 45 | * @return string 46 | */ 47 | public function getName() 48 | { 49 | return 'blog_extension'; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Resources/views/Report/mostViewed.html.twig: -------------------------------------------------------------------------------- 1 | {% extends "BlogBundle::layout.html.twig" %} 2 | {% block title %}Lo más visto {{ period }} {% endblock %} 3 | 4 | {% block main %} 5 | 6 | 23 | 24 | {% for item in items %} 25 | {% include 'BlogBundle:Post:index.item.html.twig' with {'post': item.post} %} 26 | {% else %} 27 |

No hay elementos

28 | {% endfor %} 29 | 30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /Resources/views/Post/view.social.html.twig: -------------------------------------------------------------------------------- 1 | 31 | -------------------------------------------------------------------------------- /Form/Model/CommentModel.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Form\Model; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Entity\Comment; 17 | use Symfony\Component\Validator\Constraints as Assert; 18 | 19 | /** 20 | * CommentModel 21 | */ 22 | class CommentModel 23 | { 24 | /** 25 | * @Assert\NotBlank() 26 | * @Assert\Length( min=5 ) 27 | */ 28 | protected $content; 29 | 30 | /** 31 | * @param Comment $comment 32 | */ 33 | public function __construct(Comment $comment) 34 | { 35 | $this->setContent($comment->getContent()); 36 | } 37 | 38 | /** 39 | * @return string 40 | */ 41 | public function getContent() 42 | { 43 | return $this->content; 44 | } 45 | 46 | /** 47 | * @param string $content 48 | */ 49 | public function setContent($content) 50 | { 51 | $this->content = $content; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Search/SearchInterface.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Search; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Entity\Post; 17 | use Knp\Component\Pager\Pagination\PaginationInterface; 18 | 19 | /** 20 | * 21 | * Description of SearchInterface 22 | * 23 | * @author : Daniel González 24 | */ 25 | interface SearchInterface 26 | { 27 | /** 28 | * @param string $query 29 | * @param int $page 30 | * @return array 31 | */ 32 | public function search($query, $page); 33 | 34 | /** 35 | * @param Post $post 36 | * @param int $limit 37 | * @return Post[] 38 | */ 39 | public function related(Post $post, $limit = 3); 40 | 41 | /** 42 | * @return array 43 | */ 44 | public function getItems(); 45 | 46 | /** 47 | * @return PaginationInterface 48 | */ 49 | public function getPagination(); 50 | } 51 | -------------------------------------------------------------------------------- /Resources/config/twig.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Desarrolla2\Bundle\BlogBundle\Twig\TwigExtension 8 | Twig_Extensions_Extension_Text 9 | Twig_Extensions_Extension_Intl 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | %blog.locale% 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Controller/PageController.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Controller; 15 | 16 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 17 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; 18 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; 19 | 20 | /** 21 | * PageController 22 | */ 23 | class PageController extends Controller 24 | { 25 | 26 | /** 27 | * @Route("/about-us", name="_about_us") 28 | * @Template() 29 | */ 30 | public function aboutAction() 31 | { 32 | return array(); 33 | } 34 | 35 | /** 36 | * @Route("/faq", name="_faq") 37 | * @Template() 38 | */ 39 | public function faqAction() 40 | { 41 | return array(); 42 | } 43 | 44 | /** 45 | * @Route("/cookies-policy", name="_cookies") 46 | * @Template() 47 | */ 48 | public function cookiesAction() 49 | { 50 | return array(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Resources/views/Report/mostCommented.html.twig: -------------------------------------------------------------------------------- 1 | {% extends "BlogBundle::layout.html.twig" %} 2 | {% block title %} Elementos más comentados {{ period }} {% endblock %} 3 | 4 | {% block main %} 5 | 6 | 23 | 24 | {% for item in items %} 25 | {% include 'BlogBundle:Post:index.0item.html.twig' with {'post': item.post, 'rating': item.rating} %} 26 | {% else %} 27 |

No hay elementos

28 | {% endfor %} 29 | 30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /Resources/views/Report/mostRated.html.twig: -------------------------------------------------------------------------------- 1 | {% extends "BlogBundle::layout.html.twig" %} 2 | {% block title %} Elementos más valorados {{ period }} {% endblock %} 3 | 4 | {% block main %} 5 | 6 | 24 | 25 | {% for item in items %} 26 | {% include 'BlogBundle:Post:index.item.html.twig' with {'post': item.post, 'rating': item.rating} %} 27 | {% else %} 28 |

No hay elementos

29 | {% endfor %} 30 | 31 | {% endblock %} 32 | -------------------------------------------------------------------------------- /Manager/SanitizerManager.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Manager; 15 | 16 | /** 17 | * SanitizerManager 18 | */ 19 | class SanitizerManager 20 | { 21 | /** 22 | * @param null $cacheDirectory 23 | * 24 | * @throws \InvalidArgumentException 25 | */ 26 | public function __construct($cacheDirectory = null) 27 | { 28 | if (!$cacheDirectory) { 29 | $cacheDirectory = realpath(sys_get_temp_dir()); 30 | } 31 | 32 | if (!is_writable($cacheDirectory)) { 33 | throw new \InvalidArgumentException($cacheDirectory.' is not writable'); 34 | } 35 | // require to configure some CONSTANST 36 | new \HTMLPurifier_Bootstrap(); 37 | $config = \HTMLPurifier_Config::createDefault(); 38 | $config->set('Cache.SerializerPath', $cacheDirectory); 39 | $this->purifier = new \HTMLPurifier($config); 40 | } 41 | 42 | public function doClean($string) 43 | { 44 | return $this->purifier->purify($string); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Entity/User.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Entity; 15 | 16 | use Doctrine\ORM\Mapping as ORM; 17 | use FOS\UserBundle\Model\User as BaseUser; 18 | 19 | /** 20 | * @ORM\Entity 21 | * @ORM\Table(name="fos_user") 22 | */ 23 | class User extends BaseUser 24 | { 25 | /** 26 | * @ORM\Id 27 | * @ORM\Column(type="integer") 28 | * @ORM\GeneratedValue(strategy="AUTO") 29 | */ 30 | protected $id; 31 | 32 | /** 33 | * @ORM\OneToOne(targetEntity="Profile", mappedBy="user", cascade={"persist", "remove"}) 34 | **/ 35 | protected $profile; 36 | 37 | /** 38 | * Get id 39 | * 40 | * @return integer 41 | */ 42 | public function getId() 43 | { 44 | return $this->id; 45 | } 46 | 47 | /** 48 | * @return Profile 49 | */ 50 | public function getProfile() 51 | { 52 | return $this->profile; 53 | } 54 | 55 | /** 56 | * @param Profile $profile 57 | */ 58 | public function setProfile(Profile $profile) 59 | { 60 | $this->profile = $profile; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Resources/views/Pagination/sliding.html.twig: -------------------------------------------------------------------------------- 1 | {% if pageCount > 1 %} 2 |
    3 | {% if first is defined and current != first %} 4 |
  • 5 | << 6 |
  • 7 | {% endif %} 8 | 9 | {% if previous is defined %} 10 | 13 | {% endif %} 14 | 15 | {% for page in pagesInRange %} 16 | {% if page != current %} 17 | 20 | {% else %} 21 |
  • 22 | {{ page }} 23 |
  • 24 | {% endif %} 25 | 26 | {% endfor %} 27 | 28 | {% if next is defined %} 29 | 32 | {% endif %} 33 | 34 | {% if last is defined and current != last %} 35 |
  • 36 | >> 37 |
  • 38 | {% endif %} 39 | 40 |
41 | {% endif %} 42 | -------------------------------------------------------------------------------- /Form/Model/SearchModel.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Form\Model; 15 | 16 | use Symfony\Component\Validator\Constraints as Assert; 17 | 18 | /** 19 | * Class SearchModel 20 | * 21 | * @author Daniel González 22 | */ 23 | class SearchModel 24 | { 25 | 26 | /** 27 | * @var string $content 28 | * @Assert\NotBlank() 29 | * @Assert\Length( min=3, max=100 ) 30 | */ 31 | protected $q; 32 | 33 | /** 34 | * @var int $age 35 | * @Assert\Range(min=1) 36 | */ 37 | protected $page; 38 | 39 | /** 40 | * @return string 41 | */ 42 | public function getQ() 43 | { 44 | return $this->q; 45 | } 46 | 47 | /** 48 | * @param $q 49 | */ 50 | public function setQ($q) 51 | { 52 | $this->q = $q; 53 | } 54 | 55 | /** 56 | * @param int $page 57 | */ 58 | public function setPage($page) 59 | { 60 | $this->page = $page; 61 | } 62 | 63 | /** 64 | * @return int 65 | */ 66 | public function getPage() 67 | { 68 | return $this->page; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Resources/views/Post/index.html.twig: -------------------------------------------------------------------------------- 1 | {% extends "BlogBundle::layout.html.twig" %} 2 | {% set title %}{% if page == 1 %}{{ blog_description }} :: {{ blog_name }}{% else %}{{ blog_name }} :: Página {{ page }}{% endif %}{% endset %} 3 | {% set description %}{% if pagination.current %}{{ pagination.current.intro | striptags | truncate(150) }}{% endif %}{% endset %} 4 | {% block title %}{{ title }}{% endblock %} 5 | {% block meta_description %}{{ description }}{% endblock %} 6 | {% block canonical %} 7 | 8 | {% endblock %} 9 | {% block meta_og %} 10 | {% if pagination.current %} 11 | 12 | 13 | {% if pagination.current.hasImage %} 14 | 15 | {% else %} 16 | 17 | {% endif %} 18 | 19 | 20 | {% endif %} 21 | {% endblock %} 22 | {% block main %} 23 | {% for post in pagination %} 24 | {% include 'BlogBundle:Post:index.item.html.twig' with {'post': post} %} 25 | {% else %} 26 |

No hay elementos

27 | {% endfor %} 28 |
{{ knp_pagination_render(pagination) }}
29 | {% endblock %} 30 | -------------------------------------------------------------------------------- /Entity/Repository/PostClickRepository.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Entity\Repository; 15 | 16 | use DateTime; 17 | use Desarrolla2\Bundle\BlogBundle\Entity\Post; 18 | use Desarrolla2\Bundle\BlogBundle\Entity\PostClick; 19 | use Doctrine\ORM\EntityRepository; 20 | 21 | /** 22 | * PostClickRepository 23 | * 24 | * This class was generated by the Doctrine ORM. Add your own custom 25 | * repository methods below. 26 | */ 27 | class PostClickRepository extends EntityRepository 28 | { 29 | /** 30 | * @param Post $post 31 | */ 32 | public function add(Post $post) 33 | { 34 | $date = new DateTime(); 35 | 36 | $click = $this->findOneBy( 37 | [ 38 | 'post_id' => $post->getId(), 39 | 'date' => $date, 40 | ] 41 | ); 42 | if (!$click) { 43 | $click = new PostClick(); 44 | $click->setPost($post); 45 | $click->setDate($date); 46 | } 47 | 48 | $click->increment(); 49 | 50 | $em = $this->getEntityManager(); 51 | $em->persist($click); 52 | $em->flush(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Resources/views/Feed/index.xml.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ title }} 5 | {{ url('_blog_default') }} 6 | {{ description }} 7 | {{ language }} 8 | {{ 'now'|date('r') }} 9 | {{ 'now'|date('r') }} 10 | BlogBundle 11 | http://blogs.law.harvard.edu/tech/rss 12 | {{ ttl }} 13 | {% for item in items %} 14 | 15 | {{ item.name }} 16 | {% if item.hasSource %} 17 | {{ url('_blog_redirect_post_source', { 'id' : item.id }) }} 18 | {% else %} 19 | {{ url('_blog_view', { 'slug' : item.slug }) }} 20 | {% endif %} 21 | 22 | Enlace a la fuente original: {{ item }}

27 | {% endif %} 28 | ]]> 29 |
30 | {{ url('_blog_view', { 'slug' : item.slug }) }} 31 | {{ item.createdAt | date('r') }} 32 |
33 | {% endfor %} 34 | 35 |
36 |
37 | -------------------------------------------------------------------------------- /Entity/Repository/PostViewRepository.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Entity\Repository; 15 | 16 | use DateTime; 17 | use Desarrolla2\Bundle\BlogBundle\Entity\Post; 18 | use Desarrolla2\Bundle\BlogBundle\Entity\PostView; 19 | use Doctrine\ORM\EntityRepository; 20 | 21 | /** 22 | * PostViewRepository 23 | * 24 | * This class was generated by the Doctrine ORM. Add your own custom 25 | * repository methods below. 26 | */ 27 | class PostViewRepository extends EntityRepository 28 | { 29 | /** 30 | * @param Post $post 31 | */ 32 | public function add(Post $post) 33 | { 34 | $em = $this->getEntityManager(); 35 | 36 | $date = new DateTime(); 37 | 38 | $click = $this->findOneBy( 39 | array( 40 | 'postId' => $post->getId(), 41 | 'date' => $date, 42 | ) 43 | ); 44 | if (!$click) { 45 | $click = new PostView(); 46 | $click->setPost($post); 47 | $click->setDate($date); 48 | } 49 | 50 | $click->increment(); 51 | 52 | $em->persist($click); 53 | $em->flush(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /EventListener/RatingPostListener.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\EventListener; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Entity\Post; 17 | use Desarrolla2\Bundle\BlogBundle\Entity\Rating; 18 | use Desarrolla2\Bundle\BlogBundle\Event\RatingEvent; 19 | use Desarrolla2\Bundle\BlogBundle\Manager\PostManager; 20 | 21 | /** 22 | * RatingPostListener 23 | */ 24 | class RatingPostListener 25 | { 26 | /** 27 | * @var PostManager 28 | */ 29 | protected $postManager; 30 | 31 | /** 32 | * @param PostManager $postManager 33 | */ 34 | public function __construct(PostManager $postManager) 35 | { 36 | $this->postManager = $postManager; 37 | } 38 | 39 | /** 40 | * @param RatingEvent $event 41 | */ 42 | public function onRate(RatingEvent $event) 43 | { 44 | $rating = $event->getRating(); 45 | if (!$rating->getEntityName() === 'Post') { 46 | return; 47 | } 48 | $post = $this->postManager->find($rating->getEntityId()); 49 | if (!$post) { 50 | return; 51 | } 52 | 53 | $this->postManager->updateRating($post); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Manager/ProfileManager.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Manager; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Entity\Profile; 17 | use Desarrolla2\Bundle\BlogBundle\Entity\User; 18 | use Doctrine\ORM\EntityRepository; 19 | 20 | /** 21 | * ProfileManager 22 | */ 23 | class ProfileManager extends AbstractManager 24 | { 25 | /** 26 | * @param User $user 27 | * 28 | * @return Profile 29 | */ 30 | public function get(User $user) 31 | { 32 | $profile = $user->getProfile(); 33 | if (!$profile) { 34 | $profile = new Profile(); 35 | $user->setProfile($profile); 36 | $profile->setUser($user); 37 | 38 | $this->persist($user, true); 39 | } 40 | 41 | return $profile; 42 | } 43 | 44 | /** 45 | * @return mixed 46 | */ 47 | public function create() 48 | { 49 | throw new \RuntimeException('This method is not available'); 50 | } 51 | 52 | /** 53 | * @return EntityRepository 54 | */ 55 | public function getRepository() 56 | { 57 | return $this->em->getRepository('BlogBundle:Profile'); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Controller/RatingController.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Controller; 15 | 16 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; 17 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 18 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; 19 | use Symfony\Component\HttpFoundation\Request; 20 | use Symfony\Component\HttpFoundation\Response; 21 | 22 | /** 23 | * RatingController 24 | * 25 | * @Route("/rating") 26 | */ 27 | class RatingController extends Controller 28 | { 29 | /** 30 | * @Route("/{entity}/{id}/{rate}", name="_blog_rate", requirements={"entity" = "[\w]+", "id" = "\d{1,11}", "rate" = "[\+\-]1"}) 31 | * 32 | * @Method({"POST"}) 33 | * @param Request $request 34 | * 35 | * @return array 36 | */ 37 | public function rateAction(Request $request) 38 | { 39 | $manager = $this->get('blog.rating.manager'); 40 | $rating = $manager->create( 41 | $request->get('entity'), 42 | $request->get('id'), 43 | $request->get('rate'), 44 | $request 45 | ); 46 | 47 | $manager->persist($rating); 48 | 49 | return new Response('Gracias!.'); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Resources/views/Report/postedItems.html.twig: -------------------------------------------------------------------------------- 1 | {% extends "BlogBundle::layout.html.twig" %} 2 | {% block title %} Estadisticas del sitio {% endblock %} 3 | 4 | {% block main %} 5 |
6 |
7 |

Informe de entradas publicadas

8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
EntradasComentariosEnlaces
Última dia{{ post.last_day }}{{ comment.last_day }}{{ link.last_day }}
Última semana{{ post.last_week }}{{ comment.last_week }}{{ link.last_week }}
Último mes{{ post.last_month }}{{ comment.last_month }}{{ link.last_month }}
Último año{{ post.last_year }}{{ comment.last_year }}{{ link.last_year }}
Total{{ post.total }}{{ comment.total }}{{ link.total }}
49 |
50 | {% endblock %} 51 | -------------------------------------------------------------------------------- /Resources/config/manager.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | Desarrolla2\Bundle\BlogBundle\Manager\RatingManager 9 | Desarrolla2\Bundle\BlogBundle\Manager\SanitizerManager 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | %kernel.cache_dir% 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Resources/doc/sphinx.md: -------------------------------------------------------------------------------- 1 | ############################################################################# 2 | ## data source definition 3 | ############################################################################# 4 | 5 | source desarrolla2/blog-bundle 6 | { 7 | type = mysql 8 | sql_host = localhost 9 | sql_user = root 10 | sql_pass = password 11 | sql_db = database 12 | sql_port = 3306 13 | 14 | sql_query = \ 15 | SELECT p.id, \ 16 | p.id AS id, \ 17 | p.name AS name, \ 18 | GROUP_CONCAT(t.name) tags, \ 19 | p.source AS source, \ 20 | p.intro AS intro, \ 21 | p.content AS content, \ 22 | TO_SECONDS(p.published_at) AS published_at \ 23 | FROM post p \ 24 | JOIN post_tag pt ON (p.id = pt.post_id) \ 25 | JOIN tag t ON (t.id = pt.tag_id) \ 26 | WHERE status = 1 \ 27 | GROUP BY id 28 | 29 | sql_attr_uint = id 30 | sql_attr_timestamp = published_at 31 | 32 | sql_query_info = \ 33 | SELECT name \ 34 | FROM post \ 35 | WHERE id=$id 36 | 37 | 38 | } 39 | 40 | 41 | ############################################################################# 42 | ## index definition 43 | ############################################################################# 44 | 45 | 46 | index desarrolla2/blog-bundle_idx 47 | { 48 | source = desarrolla2/blog-bundle 49 | path = /var/lib/sphinx/desarrolla2/blog-bundle 50 | docinfo = extern 51 | min_word_len = 3 52 | charset_type = utf-8 53 | html_strip = 0 54 | } 55 | -------------------------------------------------------------------------------- /Manager/RatingManager.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Manager; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Entity\Rating; 17 | use Desarrolla2\Bundle\BlogBundle\Event\RatingEvent; 18 | use Desarrolla2\Bundle\BlogBundle\Event\RatingEvents; 19 | use Symfony\Component\HttpFoundation\Request; 20 | 21 | /** 22 | * RatingManager 23 | */ 24 | class RatingManager extends AbstractManager 25 | { 26 | /** 27 | * @param string $entity 28 | * @param string $id 29 | * @param string $rate 30 | * @param Request $request 31 | * 32 | * @return Rating 33 | */ 34 | public function create($entity, $id, $rate, Request $request) 35 | { 36 | $rating = new Rating(); 37 | $rating->setEntityName($entity); 38 | $rating->setEntityId($id); 39 | $rating->setRating($rate); 40 | $rating->setIp($request->getClientIp()); 41 | $rating->setUserAgent($request->headers->get('User-Agent')); 42 | 43 | return $rating; 44 | } 45 | 46 | /** 47 | * @param Rating $rating 48 | */ 49 | public function persist(Rating $rating) 50 | { 51 | $this->em->persist($rating); 52 | $this->em->flush(); 53 | 54 | $this->eventDispatcher->dispatch( 55 | RatingEvents::PERSISTED, 56 | new RatingEvent($rating) 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Form/Type/CommentType.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Form\Type; 15 | 16 | use Symfony\Component\Form\AbstractType; 17 | use Symfony\Component\Form\FormBuilderInterface; 18 | use Symfony\Component\OptionsResolver\OptionsResolverInterface; 19 | 20 | /** 21 | * CommentType 22 | */ 23 | class CommentType extends AbstractType 24 | { 25 | /** 26 | * @param FormBuilderInterface $builder 27 | * @param array $options 28 | */ 29 | public function buildForm(FormBuilderInterface $builder, array $options) 30 | { 31 | $builder 32 | ->add( 33 | 'content', 34 | 'textarea', 35 | [ 36 | 'required' => false, 37 | 'trim' => true, 38 | ] 39 | ); 40 | } 41 | 42 | /** 43 | * @param OptionsResolverInterface $resolver 44 | */ 45 | public function setDefaultOptions(OptionsResolverInterface $resolver) 46 | { 47 | $resolver->setDefaults( 48 | [ 49 | 'data_class' => 'Desarrolla2\Bundle\BlogBundle\Form\Model\CommentModel', 50 | 'csrf_protection' => true, 51 | ] 52 | ); 53 | } 54 | 55 | /** 56 | * @return string 57 | */ 58 | public function getName() 59 | { 60 | return 'comment'; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Manager/PostManager.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Manager; 15 | 16 | use DateTime; 17 | use Desarrolla2\Bundle\BlogBundle\Entity\Post; 18 | use Desarrolla2\Bundle\BlogBundle\Entity\Repository\PostRepository; 19 | use Desarrolla2\Bundle\BlogBundle\Model\PostStatus; 20 | 21 | /** 22 | * PostManager 23 | */ 24 | class PostManager extends AbstractManager 25 | { 26 | /** 27 | * @param Post $post 28 | */ 29 | public function publish(Post $post) 30 | { 31 | $post->setStatus(PostStatus::PUBLISHED); 32 | $post->setPublishedAt(new DateTime()); 33 | $this->persist($post); 34 | } 35 | 36 | /** 37 | * @param Post $post 38 | */ 39 | public function updateRating(Post $post) 40 | { 41 | $rating = $this->em->getRepository('BlogBundle:Rating') 42 | ->getRatingFor('Post', $post->getId()); 43 | $votes = $this->em->getRepository('BlogBundle:Rating') 44 | ->getVotesFor('Post', $post->getId()); 45 | $post->setRating($rating); 46 | $post->setVotes($votes); 47 | 48 | $this->persist($post); 49 | } 50 | 51 | /** 52 | * @return Post 53 | */ 54 | public function create() 55 | { 56 | return new Post(); 57 | } 58 | 59 | /** 60 | * @return PostRepository 61 | */ 62 | public function getRepository() 63 | { 64 | return $this->em->getRepository('BlogBundle:Post'); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Entity/Repository/BannerRepository.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Entity\Repository; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Entity\Banner; 17 | use Doctrine\ORM\EntityRepository; 18 | 19 | /** 20 | * BannerRepository 21 | */ 22 | class BannerRepository extends EntityRepository 23 | { 24 | /** 25 | * @return bool|Banner 26 | */ 27 | public function getRandomActive() 28 | { 29 | $em = $this->getEntityManager(); 30 | $query = $em->createQuery( 31 | ' SELECT b FROM BlogBundle:Banner b '. 32 | ' WHERE b.isPublished = 1 ' 33 | ); 34 | 35 | $banners = []; 36 | $items = $query->getResult(); 37 | if (!$items) { 38 | return false; 39 | } 40 | foreach ($items as $banner) { 41 | $weight = $banner->getWeight(); 42 | for ($i = 0; $i < $weight; $i++) { 43 | $banners[] = $banner; 44 | } 45 | } 46 | 47 | shuffle($banners); 48 | 49 | return array_pop($banners); 50 | } 51 | 52 | /** 53 | * 54 | * @return \Doctrine\ORM\QueryBuilder 55 | */ 56 | public function getQueryBuilderForFilter() 57 | { 58 | $em = $this->getEntityManager(); 59 | $qb = $em->createQueryBuilder(); 60 | $qb 61 | ->select('b') 62 | ->from('BlogBundle:Banner', 'b') 63 | ->orderBy('b.createdAt', 'DESC'); 64 | 65 | return $qb; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Resources/views/Post/view.html.twig: -------------------------------------------------------------------------------- 1 | {% extends "BlogBundle::layout.html.twig" %} 2 | {% block title %}{{ post }}{% endblock %} 3 | {% block canonical %} 4 | {% endblock %} 5 | {% block meta_description %}{{ post.intro | striptags | raw | truncate(150) }}{% endblock %} 6 | {% block meta_og %} 7 | 8 | 9 | {% if post.hasImage %} 10 | 11 | {% else %} 12 | 13 | {% endif %} 14 | 15 | 16 | {% endblock %} 17 | {% block main %} 18 |
19 | {% include 'BlogBundle:Post:view.header.html.twig' with {'post': post} %} 20 | {{ post.content | raw }} 21 | 22 | {% if post.hasSource %} 23 |

Enlace a la fuente original: 24 | {{ post }} 26 |

27 | {% endif %} 28 | 31 | {% include 'BlogBundle:Post:view.tags.html.twig' with {'tags': post.tags } %} 32 | {% include 'BlogBundle:Post:view.social.html.twig' with {'url': url('_blog_view', { 'slug' : post.slug }) } %} 33 | {% include 'BlogBundle:Post:view.related.html.twig' with {'post': post } %} 34 | {#{% include 'BlogBundle:Post:view.comment.html.twig' with {'form': form, 'comments': comments } %}#} 35 |
36 | {% endblock %} 37 | -------------------------------------------------------------------------------- /Manager/SearchManager.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Manager; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Entity\Post; 17 | use Symfony\Component\DependencyInjection\ContainerInterface; 18 | 19 | /** 20 | * Class SearchManager 21 | * @package Desarrolla2\Bundle\BlogBundle\Manager 22 | */ 23 | class SearchManager 24 | { 25 | /** @var \Symfony\Component\DependencyInjection\ContainerInterface $container */ 26 | protected $container; 27 | 28 | /** 29 | * @param ContainerInterface $container 30 | */ 31 | public function __construct(ContainerInterface $container) 32 | { 33 | $this->container = $container; 34 | $this->config = $container->getParameter('blog'); 35 | $this->provider = $container->get( 36 | sprintf( 37 | 'blog.search.%s', 38 | $this->config['search']['provider'] 39 | ) 40 | ); 41 | } 42 | 43 | /** 44 | * @param string $query 45 | * @param int $page 46 | * @return array 47 | */ 48 | public function search($query, $page = 1) 49 | { 50 | return $this->provider->search($query, $page); 51 | } 52 | 53 | public function related(Post $post, $limit = 10) 54 | { 55 | return $this->provider->related($post, $limit); 56 | } 57 | 58 | public function getItems() 59 | { 60 | return $this->provider->getItems(); 61 | } 62 | 63 | public function getPagination() 64 | { 65 | return $this->provider->getPagination(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Manager/AbstractManager.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Manager; 15 | 16 | use Doctrine\ORM\EntityManager; 17 | use Doctrine\ORM\EntityRepository; 18 | use Symfony\Component\EventDispatcher\EventDispatcherInterface; 19 | 20 | /** 21 | * AbstractManager 22 | */ 23 | abstract class AbstractManager 24 | { 25 | /** 26 | * @var \Doctrine\ORM\EntityManager; 27 | */ 28 | protected $em; 29 | 30 | /** 31 | * @var EventDispatcherInterface 32 | */ 33 | protected $eventDispatcher; 34 | 35 | /** 36 | * @param EntityManager $em 37 | * @param EventDispatcherInterface $eventDispatcher 38 | */ 39 | public function __construct(EntityManager $em, EventDispatcherInterface $eventDispatcher) 40 | { 41 | $this->em = $em; 42 | $this->eventDispatcher = $eventDispatcher; 43 | } 44 | 45 | /** 46 | * @param int $id 47 | * 48 | * @return Post 49 | */ 50 | public function find($id) 51 | { 52 | return $this->getRepository()->find($id); 53 | } 54 | 55 | /** 56 | * @param mixed $entity 57 | * @param bool $flush 58 | */ 59 | public function persist($entity, $flush = true) 60 | { 61 | $this->em->persist($entity); 62 | if ($flush) { 63 | $this->em->flush(); 64 | } 65 | } 66 | 67 | /** 68 | * @return mixed 69 | */ 70 | abstract public function create(); 71 | 72 | /** 73 | * @return EntityRepository 74 | */ 75 | abstract public function getRepository(); 76 | } 77 | -------------------------------------------------------------------------------- /Form/Type/SearchType.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Form\Type; 15 | 16 | use Symfony\Component\Form\AbstractType; 17 | use Symfony\Component\Form\FormBuilderInterface; 18 | use Symfony\Component\OptionsResolver\OptionsResolverInterface; 19 | 20 | /** 21 | * SearchType 22 | */ 23 | class SearchType extends AbstractType 24 | { 25 | /** 26 | * @param FormBuilderInterface $builder 27 | * @param array $options 28 | */ 29 | public function buildForm(FormBuilderInterface $builder, array $options) 30 | { 31 | $builder 32 | ->add( 33 | 'q', 34 | 'text', 35 | [ 36 | 'required' => true, 37 | 'trim' => true, 38 | ] 39 | ) 40 | ->add( 41 | 'page', 42 | 'hidden', 43 | [ 44 | 'required' => false, 45 | 'trim' => true, 46 | ] 47 | ); 48 | } 49 | 50 | /** 51 | * @param OptionsResolverInterface $resolver 52 | */ 53 | public function setDefaultOptions(OptionsResolverInterface $resolver) 54 | { 55 | $resolver->setDefaults( 56 | [ 57 | 'data_class' => 'Desarrolla2\Bundle\BlogBundle\Form\Model\SearchModel', 58 | 'csrf_protection' => false, 59 | ] 60 | ); 61 | } 62 | 63 | /** 64 | * @return string 65 | */ 66 | public function getName() 67 | { 68 | return ''; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Resources/public/js/blog.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function () { 2 | (function () { 3 | tinyMCE.init({ 4 | menubar: false, 5 | mode: 'textareas', 6 | content_css: '/bundles/blog/css/textarea.css' 7 | }); 8 | })(); 9 | 10 | (function () { 11 | $('a.rating').click(function (e) { 12 | e.preventDefault(); 13 | $parent = $(this).parent() 14 | $parent.html(''); 15 | $.post($(this).data('url')) 16 | .done(function (data) { 17 | $parent.html(data); 18 | }); 19 | }); 20 | })(); 21 | 22 | (function () { 23 | var $p = $('a#post-view'); 24 | if (!$p.length) { 25 | return; 26 | } 27 | $.post("/view" + $p.attr('href'), function () { 28 | }); 29 | })(); 30 | 31 | (function () { 32 | var cookieLaw = Cookie.get('accepted-cookie-law'); 33 | 34 | if (cookieLaw !== 'yes') { 35 | var $body = $('body'); 36 | $body.append( 37 | '' 45 | ); 46 | 47 | $('div.cookie-law a.accept').click(function (e) { 48 | e.preventDefault(); 49 | Cookie.set('accepted-cookie-law', 'yes', 365 * 10); 50 | $('div.cookie-law').hide(); 51 | }); 52 | } 53 | })(); 54 | }); -------------------------------------------------------------------------------- /Resources/views/Archive/index.html.twig: -------------------------------------------------------------------------------- 1 | {% extends "BlogBundle::layout.html.twig" %} 2 | {% block title %} Archivo del sitio | {{ parent() }}{% endblock %} 3 | {% block canonical %} 4 | {% endblock %} 5 | {% block meta_description %} Puedes encontrar todas las entradas del sitio ordenadas por fecha {% endblock %} 6 | {% block meta_og %} 7 | {{ parent() }} 8 | 9 | 10 | 11 | {% endblock %} 12 | {% block meta_twiter %} 13 | {{ parent() }} 14 | 15 | 16 | {% endblock %} 17 | {% block main %} 18 |
19 |
20 |

Archivo del sitio

21 |
22 |

Puedes encontrar todas las entradas del sitio ordenadas por fecha.

23 |
    24 | {% for year, posts in items %} 25 |
  1. Año {{ year }}
  2. 26 |
      27 | {% for item in posts %} 28 |
    1. 29 | 32 | {{ item.date | date('F') | capitalize }} 33 | [{{ item.n }}] 34 |
    2. 35 | {% else %} 36 |
    3. No hay elementos
    4. 37 | {% endfor %} 38 |
    39 | {% else %} 40 |
  3. No hay elementos
  4. 41 | {% endfor %} 42 |
43 |
44 | {% endblock %} 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BlogBundle 2 | 3 | This is the most complete bundle you can find to start creating your blog, 4 | actualy this blogBundle is running on Symfony2.3 5 | 6 | ![BlogBundle](http://knpbundles.com/desarrolla2/BlogBundle/badge) 7 | 8 | [![Build Status](https://travis-ci.org/desarrolla2/BlogBundle.png)](https://travis-ci.org/desarrolla2/BlogBundle) [![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/desarrolla2/BlogBundle/badges/quality-score.png?s=46e9f051c02566d0b2b5bcb55327b5ae7b203f08)](https://scrutinizer-ci.com/g/desarrolla2/BlogBundle/) [![Code Coverage](https://scrutinizer-ci.com/g/desarrolla2/BlogBundle/badges/coverage.png?s=37e1a3950bb2b8fd52c3d3c4f84688f937d2305b)](https://scrutinizer-ci.com/g/desarrolla2/BlogBundle/) 9 | 10 | [![Latest Stable](https://poser.pugx.org/desarrolla2/blog-bundle/v/stable.png)](https://packagist.org/packages/desarrolla2/blog-bundle) [![Total Downloads](https://poser.pugx.org/desarrolla2/blog-bundle/downloads.png)](https://packagist.org/packages/desarrolla2/blog-bundle) [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/desarrolla2/desarrolla2/blog-bundle/trend.png)](https://bitdeli.com/desarrolla2 "BlogBundle") 11 | 12 | 13 | Some Features include: 14 | 15 | * URLs SEO friendly 16 | * Taxonomy with Many to Many relation to post 17 | * Article editing with awesome theme for ckEditor 18 | * Very basic image upload and management 19 | * Comments management 20 | * Blog archive 21 | * HTTP cache support 22 | 23 | You can see a example for this blog in http://desarrolla2.com 24 | 25 | ## Bundle Installation 26 | 27 | You can see complete Bundle Installation instruction [here](Resources/doc/installation/index.md) 28 | 29 | ## Using the bundle 30 | 31 | Not ready yet :(, contributions here is appreciated. 32 | 33 | ## Coming soon 34 | 35 | * Improve Comments workflow. 36 | * More documentation 37 | * Some tests 38 | 39 | ## Contact 40 | 41 | You can contact with me on [twitter](https://twitter.com/desarrolla2). 42 | -------------------------------------------------------------------------------- /Resources/config/search.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Desarrolla2\Bundle\BlogBundle\Search\Sphinx 7 | Desarrolla2\Bundle\BlogBundle\Search\MySQL 8 | Desarrolla2\Bundle\BlogBundle\Manager\SearchManager 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | %blog.search.sphinx.host% 20 | %blog.search.sphinx.port% 21 | %blog.search.sphinx.index% 22 | %blog.items% 23 | 24 | 25 | 26 | 27 | %blog.search.mysql.connection% 28 | %blog.search.mysql.manager% 29 | %blog.items% 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Resources/views/Tag/index.html.twig: -------------------------------------------------------------------------------- 1 | {% extends "BlogBundle::layout.html.twig" %} 2 | 3 | {% block title %} Etiqueta "{{ tag | upper }}" {% if page != 1 %}| Página {{ page }} {% endif %}| {{ parent() }}{% endblock %} 4 | {% block meta_description %}Contenido relacionado con {{ tag | upper}}{% endblock %} 5 | {% block meta_keywords %}{{ tag }}{% endblock %} 6 | {% block canonical %}{% endblock %} 7 | {% block meta_og %} 8 | {{ parent() }} 9 | 10 | 11 | 12 | {% if pagination.current.hasImage %} 13 | 14 | {% endif %} 15 | {% endblock %} 16 | {% block meta_twiter %} 17 | {{ parent() }} 18 | 19 | 20 | {% if pagination.current.hasImage %} 21 | 22 | {% endif %} 23 | {% endblock %} 24 | 25 | {% block rss %} 26 | 28 | {% endblock %} 29 | 30 | {% block main %} 31 | {% for post in pagination %} 32 | {% include 'BlogBundle:Post:index.item.html.twig' with {'post': post} %} 33 | {% else %} 34 |

No hay elementos

35 | {% endfor %} 36 | 37 | 38 | {% endblock %} 39 | -------------------------------------------------------------------------------- /Entity/Repository/LinkRepository.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Entity\Repository; 15 | 16 | use DateTime; 17 | use Desarrolla2\Bundle\BlogBundle\Model\LinkStatus; 18 | use Doctrine\ORM\EntityRepository; 19 | 20 | /** 21 | * LinkRepository 22 | */ 23 | class LinkRepository extends EntityRepository 24 | { 25 | /** 26 | * @return array 27 | */ 28 | public function getActive() 29 | { 30 | $query = $this->getQueryForGetActive(); 31 | 32 | return $query->getResult(); 33 | } 34 | 35 | /** 36 | * @return \Doctrine\ORM\Query 37 | */ 38 | public function getQueryForGetActive() 39 | { 40 | $em = $this->getEntityManager(); 41 | $query = $em->createQuery( 42 | ' SELECT l FROM BlogBundle:Link l '. 43 | ' WHERE l.isPublished = '.LinkStatus::PUBLISHED. 44 | ' ORDER BY l.createdAt DESC ' 45 | ); 46 | 47 | return $query; 48 | } 49 | 50 | /** 51 | * @return array 52 | */ 53 | public function getActiveOrdered() 54 | { 55 | $query = $this->getQueryForGetActiveOrdered(); 56 | 57 | return $query->getResult(); 58 | } 59 | 60 | /** 61 | * @return \Doctrine\ORM\Query 62 | */ 63 | public function getQueryForGetActiveOrdered() 64 | { 65 | $em = $this->getEntityManager(); 66 | $query = $em->createQuery( 67 | ' SELECT l FROM BlogBundle:Link l '. 68 | ' WHERE l.isPublished = '.LinkStatus::PUBLISHED. 69 | ' ORDER BY l.name ASC ' 70 | ); 71 | 72 | return $query; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Search/AbstractSearch.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Search; 15 | 16 | use Knp\Component\Pager\Pagination\PaginationInterface; 17 | use Knp\Component\Pager\Paginator; 18 | 19 | /** 20 | * Class AbstractSearch 21 | * 22 | * @author Daniel González 23 | */ 24 | abstract class AbstractSearch implements SearchInterface 25 | { 26 | 27 | /** 28 | * @var int 29 | */ 30 | protected $itemsPerPage = 12; 31 | 32 | /** 33 | * @var int 34 | */ 35 | protected $maxSearchResults = 1000; 36 | 37 | /** 38 | * @var int 39 | */ 40 | protected $limitRelated = 3; 41 | 42 | /** 43 | * @var PaginationInterface 44 | */ 45 | protected $pagination; 46 | 47 | /** 48 | * @var Paginator 49 | */ 50 | protected $paginator; 51 | 52 | /** 53 | * @var array 54 | */ 55 | protected $items; 56 | 57 | /** 58 | * @return array 59 | */ 60 | public function getItems() 61 | { 62 | return $this->items; 63 | } 64 | 65 | /** 66 | * @return \Knp\Component\Pager\Pagination\PaginationInterface 67 | */ 68 | public function getPagination() 69 | { 70 | return $this->pagination; 71 | } 72 | 73 | /** 74 | * @param int $itemsPerPage 75 | */ 76 | public function setItemsPerPage($itemsPerPage) 77 | { 78 | $this->itemsPerPage = $itemsPerPage; 79 | } 80 | 81 | /** 82 | * @param int $maxSearchResults 83 | */ 84 | public function setMaxSearchResults($maxSearchResults) 85 | { 86 | $this->maxSearchResults = $maxSearchResults; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Form/Handler/SearchHandler.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Form\Handler; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Search\SphinxManager; 17 | use Doctrine\ORM\EntityManager; 18 | use Symfony\Component\Form\Form; 19 | use Symfony\Component\HttpFoundation\Request; 20 | 21 | class SearchHandler 22 | { 23 | /** 24 | * @var \Symfony\Component\Form\Form 25 | */ 26 | protected $form; 27 | 28 | /** 29 | * @var \Symfony\Component\HttpFoundation\Request 30 | */ 31 | protected $request; 32 | 33 | /** 34 | * @var \Doctrine\ORM\EntityManager 35 | */ 36 | protected $em; 37 | 38 | /** 39 | * @var \Desarrolla2\Bundle\BlogBundle\Search\SphinxManager 40 | */ 41 | protected $sm; 42 | 43 | /** 44 | * 45 | * @param \Symfony\Component\Form\Form $form 46 | * @param \Symfony\Component\HttpFoundation\Request $request 47 | * @param \Desarrolla2\Bundle\BlogBundle\Entity\Comment $comment 48 | * @param \Symfony\Component\DependencyInjection\ContainerInterface $container 49 | */ 50 | public function __construct(Form $form, Request $request, EntityManager $em, SphinxManager $sm) 51 | { 52 | $this->form = $form; 53 | $this->request = $request; 54 | $this->em = $em; 55 | $this->sm = $sm; 56 | } 57 | 58 | /** 59 | * @return boolean 60 | */ 61 | public function process() 62 | { 63 | $this->form->submit($this->request); 64 | 65 | if ($this->form->isValid()) { 66 | $query = $this->form->getData()->getQuery(); 67 | 68 | return true; 69 | } 70 | 71 | return false; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Form/Handler/ProfileHandler.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Form\Handler; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Entity\Profile; 17 | use Desarrolla2\Bundle\BlogBundle\Manager\ProfileManager; 18 | use Symfony\Component\Form\Form; 19 | use Symfony\Component\HttpFoundation\Request; 20 | 21 | /** 22 | * ProfileHandler 23 | */ 24 | class ProfileHandler 25 | { 26 | 27 | /** 28 | * @var Form 29 | */ 30 | protected $form; 31 | 32 | /** 33 | * @var Request 34 | */ 35 | protected $request; 36 | 37 | /** 38 | * @var ProfileManager 39 | */ 40 | protected $manager; 41 | 42 | /** 43 | * @var Profile 44 | */ 45 | protected $profile; 46 | 47 | /** 48 | * @param Form $form 49 | * @param Request $request 50 | * @param ProfileManager $manager 51 | * @param Profile $profile 52 | */ 53 | public function __construct(Form $form, Request $request, ProfileManager $manager, Profile $profile) 54 | { 55 | $this->form = $form; 56 | $this->request = $request; 57 | $this->manager = $manager; 58 | $this->profile = $profile; 59 | } 60 | 61 | /** 62 | * @return bool 63 | */ 64 | public function process() 65 | { 66 | $this->form->submit($this->request); 67 | 68 | if ($this->form->isValid()) { 69 | $entityModel = $this->form->getData(); 70 | 71 | $this->profile->setName($entityModel->getName()); 72 | $this->profile->setAddress($entityModel->getAddress()); 73 | $this->profile->setDescription($entityModel->getDescription()); 74 | 75 | $this->manager->persist($this->profile); 76 | 77 | return true; 78 | } 79 | 80 | return false; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Controller/RedirectController.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Controller; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Entity\PostClick; 17 | use Desarrolla2\Bundle\BlogBundle\Model\PostStatus; 18 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; 19 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 20 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; 21 | use Symfony\Component\HttpFoundation\RedirectResponse; 22 | use Symfony\Component\HttpFoundation\Request; 23 | 24 | /** 25 | * RedirectController 26 | * 27 | * Route("/r") 28 | */ 29 | class RedirectController extends Controller 30 | { 31 | /** 32 | * Redirect to post source if it has 33 | * 34 | * @Route("/p/s/{id}", name="_blog_redirect_post_source", requirements={"id" = "\d{1,11}"}) 35 | * @Method({"GET"}) 36 | * 37 | * @param Request $request 38 | * 39 | * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException 40 | * @return RedirectResponse 41 | */ 42 | public function postSourceAction(Request $request) 43 | { 44 | $post = $this->getDoctrine()->getManager() 45 | ->getRepository('BlogBundle:Post')->find($request->get('id', false)); 46 | 47 | if (!$post) { 48 | throw $this->createNotFoundException('The post does not exist'); 49 | } 50 | if ($post->getStatus() != PostStatus::PUBLISHED) { 51 | return new RedirectResponse($this->generateUrl('_blog_default'), 302); 52 | } 53 | if (!$post->hasSource()) { 54 | return new RedirectResponse( 55 | $this->generateUrl('_blog_view', array('slug' => $post->getSlug())), 56 | 302 57 | ); 58 | } 59 | 60 | $this->getDoctrine()->getManager() 61 | ->getRepository('BlogBundle:PostClick') 62 | ->add($post); 63 | 64 | return new RedirectResponse( 65 | $post->getSource(), 66 | 302 67 | ); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | before_commands: 2 | - "composer update --prefer-source --dev --verbose --optimize-autoloader --profile" 3 | 4 | tools: 5 | # Code Coverage 6 | php_code_coverage: 7 | enabled: true 8 | test_command: phpunit 9 | filter: 10 | excluded_paths: 11 | - 'vendor/*' 12 | - 'tests/*' 13 | 14 | 15 | # Code Sniffer 16 | php_code_sniffer: 17 | enabled: true 18 | command: phpcs 19 | config: 20 | standard: PSR2 21 | filter: 22 | excluded_paths: 23 | - 'vendor/*' 24 | 25 | 26 | # Copy/Paste Detector 27 | php_cpd: 28 | enabled: true 29 | command: phpcpd 30 | excluded_dirs: 31 | - 'vendor' 32 | 33 | 34 | # PHP CS Fixer (http://http://cs.sensiolabs.org/). 35 | php_cs_fixer: 36 | enabled: true 37 | command: php-cs-fixer 38 | config: 39 | level: psr2 40 | filter: 41 | excluded_paths: 42 | - 'vendor/*' 43 | 44 | 45 | # Analyzes the size and structure of a PHP project. 46 | php_loc: 47 | enabled: true 48 | command: phploc 49 | excluded_dirs: 50 | - vendor 51 | 52 | 53 | # PHP Mess Detector (http://phpmd.org). 54 | php_mess_detector: 55 | enabled: true 56 | command: phpmd 57 | config: 58 | rulesets: 59 | - codesize 60 | - unusedcode 61 | - naming 62 | - design 63 | - controversial 64 | filter: 65 | excluded_paths: 66 | - 'vendor/*' 67 | 68 | 69 | # Analyzes the size and structure of a PHP project. 70 | php_pdepend: 71 | enabled: true 72 | command: pdepend 73 | excluded_dirs: 74 | - vendor 75 | 76 | # Runs Scrutinizer's PHP Analyzer Tool 77 | php_analyzer: 78 | enabled: true 79 | filter: 80 | excluded_paths: 81 | - 'vendor/*' 82 | 83 | # Security Advisory Checker 84 | sensiolabs_security_checker: true -------------------------------------------------------------------------------- /Form/Type/ProfileType.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Form\Type; 15 | 16 | use Symfony\Component\Form\AbstractType; 17 | use Symfony\Component\Form\FormBuilderInterface; 18 | use Symfony\Component\OptionsResolver\OptionsResolverInterface; 19 | 20 | /** 21 | * ProfileType 22 | */ 23 | class ProfileType extends AbstractType 24 | { 25 | /** 26 | * @param FormBuilderInterface $builder 27 | * @param array $options 28 | */ 29 | public function buildForm(FormBuilderInterface $builder, array $options) 30 | { 31 | $builder 32 | ->add( 33 | 'name', 34 | 'text', 35 | [ 36 | 'required' => false, 37 | 'trim' => true, 38 | ] 39 | ) 40 | ->add( 41 | 'address', 42 | 'text', 43 | [ 44 | 'required' => false, 45 | 'trim' => true, 46 | ] 47 | ) 48 | ->add( 49 | 'description', 50 | 'textarea', 51 | [ 52 | 'required' => false, 53 | 'trim' => true, 54 | ] 55 | ) 56 | ->add( 57 | 'show_public_profile', 58 | 'checkbox', 59 | [ 60 | 'required' => false, 61 | ] 62 | ); 63 | } 64 | 65 | /** 66 | * @param OptionsResolverInterface $resolver 67 | */ 68 | public function setDefaultOptions(OptionsResolverInterface $resolver) 69 | { 70 | $resolver->setDefaults( 71 | [ 72 | 'data_class' => 'Desarrolla2\Bundle\BlogBundle\Form\Model\ProfileModel', 73 | 'csrf_protection' => true, 74 | ] 75 | ); 76 | } 77 | 78 | /** 79 | * @return string 80 | */ 81 | public function getName() 82 | { 83 | return 'profile'; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Resources/views/Profile/edit.html.twig: -------------------------------------------------------------------------------- 1 | {% extends "BlogBundle::layout.html.twig" %} 2 | {% trans_default_domain 'FOSUserBundle' %} 3 | {% block meta_robots %}noindex, follow{% endblock %} 4 | {% block title %}Tu perfil de usuario{% endblock %} 5 | {% block content %} 6 |
7 |
8 |
9 |
10 |

Tu perfil de usuario

11 | 16 | 17 |
18 |
19 |
20 | 21 | {{ form_widget(form.name) }} 22 |
23 |
24 | 25 | {{ form_widget(form.address) }} 26 |
27 |
28 | 29 | {{ form_widget(form.description, {attr:{ style: 'height: 150px'}}) }} 30 |
31 |
32 |
2
33 |
34 |
35 |

Mostrar mi información personal en mi perfil público:

36 | {{ form_widget(form.show_public_profile , {label: 'Marcar para mostrar mi información'}) }} 37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |

45 | 46 | Ir a modificar contraseña 47 |

48 |
49 |
50 | 51 |
52 | {% endblock %} 53 | -------------------------------------------------------------------------------- /Controller/SearchController.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Controller; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Form\Model\SearchModel; 17 | use Desarrolla2\Bundle\BlogBundle\Form\Type\SearchType; 18 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; 19 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 20 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; 21 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; 22 | use Symfony\Component\HttpFoundation\Request; 23 | 24 | /** 25 | * 26 | * Description of SearchController 27 | * 28 | */ 29 | class SearchController extends Controller 30 | { 31 | /** 32 | * @Route("/search", name="_blog_search") 33 | * @Method({"GET"}) 34 | * @Template() 35 | */ 36 | public function indexAction(Request $request) 37 | { 38 | $items = array(); 39 | $pagination = null; 40 | $form = $this->createForm(new SearchType(), new SearchModel()); 41 | $query = $request->get('q', false); 42 | $page = $this->getPage(); 43 | if ($query) { 44 | $form->submit($request); 45 | if ($form->isValid()) { 46 | $query = $form->getData()->getQ(); 47 | $search = $this->get('blog.search'); 48 | $search->search( 49 | $query, 50 | $page 51 | ); 52 | 53 | $items = $search->getItems(); 54 | $pagination = $search->getPagination(); 55 | } 56 | } 57 | 58 | return array( 59 | 'page' => $page, 60 | 'form' => $form->createView(), 61 | 'items' => $items, 62 | 'query' => $query, 63 | 'pagination' => $pagination, 64 | 65 | ); 66 | } 67 | 68 | /** 69 | * @return int 70 | */ 71 | private function getPage() 72 | { 73 | $page = (int) $this->getRequest()->get('page', 1); 74 | if (!$page) { 75 | return 1; 76 | } 77 | 78 | return $page; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Controller/ProfileController.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Controller; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Entity\Profile; 17 | use Desarrolla2\Bundle\BlogBundle\Form\Handler\ProfileHandler; 18 | use Desarrolla2\Bundle\BlogBundle\Form\Model\ProfileModel; 19 | use Desarrolla2\Bundle\BlogBundle\Form\Type\ProfileType; 20 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; 21 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 22 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; 23 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; 24 | use Symfony\Component\HttpFoundation\RedirectResponse; 25 | use Symfony\Component\HttpFoundation\Request; 26 | 27 | /** 28 | * ProfileController 29 | */ 30 | class ProfileController extends Controller 31 | { 32 | /** 33 | * @Route("/profile/", name="_blog_profile_index") 34 | * @Method({"GET"}) 35 | * 36 | * @return RedirectResponse 37 | */ 38 | public function indexAction() 39 | { 40 | return new RedirectResponse($this->generateUrl('_blog_profile_edit')); 41 | } 42 | 43 | /** 44 | * @Route("/profile/edit", name="_blog_profile_edit") 45 | * @Method({"GET", "POST"}) 46 | * @Template() 47 | * 48 | * @param Request $request 49 | * 50 | * @return array 51 | */ 52 | public function editAction(Request $request) 53 | { 54 | $profile = $this->get('blog.post.profile')->get($this->getUser()); 55 | $form = $this->createForm(new ProfileType(), new ProfileModel($profile)); 56 | 57 | if ($request->getMethod() == 'POST') { 58 | $formHandler = new ProfileHandler( 59 | $form, 60 | $request, 61 | $this->container->get('blog.post.profile'), 62 | $profile 63 | ); 64 | 65 | if ($formHandler->process()) { 66 | return $this->redirect($this->generateUrl('_blog_profile_edit')); 67 | } 68 | } 69 | 70 | return [ 71 | 'form' => $form->createView(), 72 | ]; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Entity/Repository/CommentRepository.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Entity\Repository; 15 | 16 | use DateTime; 17 | use Desarrolla2\Bundle\BlogBundle\Entity\Post; 18 | use Desarrolla2\Bundle\BlogBundle\Model\CommentStatus; 19 | use Doctrine\ORM\EntityRepository; 20 | 21 | /** 22 | * CommentRepository 23 | */ 24 | class CommentRepository extends EntityRepository 25 | { 26 | 27 | /** 28 | * @return \Doctrine\ORM\Query 29 | */ 30 | public function getQueryForGet() 31 | { 32 | $em = $this->getEntityManager(); 33 | $query = $em->createQuery( 34 | ' SELECT c FROM BlogBundle:Comment c '. 35 | ' WHERE c.status = '.CommentStatus::PENDING. 36 | ' OR c.status = '.CommentStatus::APPROVED. 37 | ' ORDER BY c.createdAt DESC ' 38 | ); 39 | 40 | return $query; 41 | } 42 | 43 | /** 44 | * @param bool $limit 45 | * 46 | * @return array 47 | */ 48 | public function getLatest($limit = false) 49 | { 50 | $query = $this->getQueryForGet($limit); 51 | if ($limit) { 52 | $query->setMaxResults($limit); 53 | } 54 | 55 | return $query->getResult(); 56 | } 57 | 58 | /** 59 | * @param Post $post 60 | * 61 | * @return \Doctrine\ORM\AbstractQuery 62 | */ 63 | public function getQueryForGetForPost(Post $post) 64 | { 65 | $em = $this->getEntityManager(); 66 | $query = $em->createQuery( 67 | ' SELECT c FROM BlogBundle:Comment c '. 68 | ' WHERE ( c.status = '.CommentStatus::PENDING.' OR c.status = '.CommentStatus::APPROVED.' ) '. 69 | ' AND c.post = :post '. 70 | ' ORDER BY c.createdAt ASC ' 71 | ) 72 | ->setParameter('post', $post); 73 | 74 | return $query; 75 | } 76 | 77 | /** 78 | * @param Post $post 79 | * 80 | * @return array 81 | */ 82 | public function getForPost(Post $post) 83 | { 84 | $query = $this->getQueryForGetForPost($post); 85 | 86 | return $query->getResult(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Resources/views/User/register.html.twig: -------------------------------------------------------------------------------- 1 | {% extends "BlogBundle::layout.html.twig" %} 2 | {% block title %} Registro de usuarios {% endblock %} 3 | {% block meta_robots %}noindex{% endblock %} 4 | {% block main %} 5 |

Registro de usuarios

6 | 8 |
9 | {% if form_errors(form) %} 10 |
{{ form_errors(form) }}
11 | {% endif %} 12 |
13 |

14 | 15 | {% if form_errors(form.userName) %} 16 | 17 |

{{ form_errors(form.userName) }}
18 | {% endif %} 19 | {{ form_widget(form.userName) }} 20 |

21 |
22 |
23 |

24 | 25 | {% if form_errors(form.userEmail) %} 26 | 27 |

{{ form_errors(form.userEmail) }}
28 | {% endif %} 29 | {{ form_widget(form.userEmail) }} 30 |

31 |
32 |
33 |

34 | 35 | {% if form_errors(form.plainPassword.first) %} 36 | 37 |

{{ form_errors(form.plainPassword.first) }}
38 | {% endif %} 39 | {{ form_widget(form.plainPassword.first) }} 40 |

41 |
42 |
43 |

44 | 45 | {% if form_errors(form.plainPassword.second) %} 46 | 47 |

{{ form_errors(form.plainPassword.second) }}
48 | {% endif %} 49 | {{ form_widget(form.plainPassword.second) }} 50 |

51 |
52 |
53 |
54 |

55 | 56 | {% if form_errors(form.captcha) %} 57 | 58 |

{{ form_errors(form.captcha) }}
59 | {% endif %} 60 | 61 | {{ form_widget(form.captcha, { 'attr': {'class': 'captcha' }} ) }} 62 |

63 |
64 | 65 | 66 | {{ form_rest(form) }} 67 | 68 |

Los campos marcados con (*) son obligatorios

69 | 70 | {{ form_rest(form) }} 71 | {% endblock %} 72 | -------------------------------------------------------------------------------- /Form/Handler/CommentHandler.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Form\Handler; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Entity\Comment; 17 | use Desarrolla2\Bundle\BlogBundle\Manager\SanitizerManager; 18 | use Doctrine\ORM\EntityManager; 19 | use Symfony\Component\Form\Form; 20 | use Symfony\Component\HttpFoundation\Request; 21 | 22 | /** 23 | * CommentHandler 24 | */ 25 | class CommentHandler 26 | { 27 | /** 28 | * @var \Symfony\Component\Form\Form 29 | */ 30 | protected $form; 31 | 32 | /** 33 | * @var \Symfony\Component\HttpFoundation\Request 34 | */ 35 | protected $request; 36 | 37 | /** 38 | * @var \Doctrine\ORM\EntityManager 39 | */ 40 | protected $em; 41 | 42 | /** 43 | * 44 | * @var SanitizerManager 45 | */ 46 | protected $sanitizer; 47 | 48 | /** 49 | * @var \Desarrolla2\Bundle\BlogBundle\Entity\Comment 50 | */ 51 | protected $entity; 52 | 53 | /** 54 | * @param Form $form 55 | * @param Request $request 56 | * @param EntityManager $em 57 | * @param SanitizerManager $sanitizer 58 | * @param Comment $comment 59 | */ 60 | public function __construct( 61 | Form $form, 62 | Request $request, 63 | EntityManager $em, 64 | SanitizerManager $sanitizer, 65 | Comment $comment 66 | ) { 67 | $this->form = $form; 68 | $this->request = $request; 69 | $this->entity = $comment; 70 | $this->em = $em; 71 | $this->sanitizer = $sanitizer; 72 | } 73 | 74 | /** 75 | * @return boolean 76 | */ 77 | public function process() 78 | { 79 | $this->form->submit($this->request); 80 | 81 | if ($this->form->isValid()) { 82 | $entityModel = $this->form->getData(); 83 | 84 | $this->entity->setContent( 85 | $this->sanitizer->doClean( 86 | $entityModel->getContent() 87 | ) 88 | ); 89 | 90 | $this->em->persist($this->entity); 91 | $this->em->flush(); 92 | 93 | return true; 94 | } 95 | 96 | return false; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Controller/CommentController.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Controller; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Entity\Comment; 17 | use Desarrolla2\Bundle\BlogBundle\Form\Handler\CommentHandler; 18 | use Desarrolla2\Bundle\BlogBundle\Form\Model\CommentModel; 19 | use Desarrolla2\Bundle\BlogBundle\Form\Type\CommentType; 20 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; 21 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 22 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; 23 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; 24 | use Symfony\Component\HttpFoundation\Request; 25 | 26 | /** 27 | * Comment controller. 28 | * 29 | * @Route("/comment") 30 | */ 31 | class CommentController extends Controller 32 | { 33 | /** 34 | * Creates a new Comment entity. 35 | * 36 | * @Route("/{post_id}", name="_blog_comment_create", requirements={"post_id" = "\d+"}, defaults={"post_id" = "1" }) 37 | * @Method({"GET", "POST"}) 38 | * @Template() 39 | */ 40 | public function indexAction(Request $request) 41 | { 42 | $em = $this->getDoctrine()->getManager(); 43 | $post = $em->getRepository('BlogBundle:Post')->find($request->get('post_id', false)); 44 | if (!$post) { 45 | throw $this->createNotFoundException('Unable to find post.'); 46 | } 47 | 48 | $comment = new Comment(); 49 | $comment->setPost($post); 50 | $form = $this->createForm(new CommentType(), new CommentModel($comment)); 51 | if ($request->getMethod() == 'POST') { 52 | $formHandler = new CommentHandler($form, $request, $em, $this->container->get('blog.sanitizer.manager'), $comment); 53 | 54 | if ($formHandler->process()) { 55 | return $this->redirect($this->generateUrl('_comment_message')); 56 | } 57 | } 58 | 59 | return array( 60 | 'form' => $form->createView(), 61 | 'post' => $post, 62 | ); 63 | } 64 | 65 | /** 66 | * 67 | * @Route("/message/", name="_comment_message") 68 | * @Method("GET") 69 | * @Template() 70 | */ 71 | public function messageAction(Request $request) 72 | { 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Form/Model/ProfileModel.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Form\Model; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Entity\Profile; 17 | use Symfony\Component\Validator\Constraints as Assert; 18 | 19 | /** 20 | * ProfileModel 21 | */ 22 | class ProfileModel 23 | { 24 | /** 25 | * @Assert\Length( min=5, max=100 ) 26 | */ 27 | protected $name; 28 | 29 | /** 30 | * @Assert\Length( min=5, max=100 ) 31 | */ 32 | protected $address; 33 | 34 | /** 35 | * @Assert\Length( min=5, max=1000 ) 36 | */ 37 | protected $description; 38 | 39 | /** 40 | * @var bool 41 | */ 42 | protected $showPublicProfile; 43 | 44 | /** 45 | * @param Profile $profile 46 | */ 47 | public function __construct(Profile $profile) 48 | { 49 | $this->name = $profile->getName(); 50 | $this->address = $profile->getAddress(); 51 | $this->description = $profile->getDescription(); 52 | $this->showPublicProfile = false; 53 | } 54 | 55 | /** 56 | * @return string 57 | */ 58 | public function getName() 59 | { 60 | return $this->name; 61 | } 62 | 63 | /** 64 | * @param string $name 65 | */ 66 | public function setName($name) 67 | { 68 | $this->name = $name; 69 | } 70 | 71 | /** 72 | * @return string 73 | */ 74 | public function getAddress() 75 | { 76 | return $this->address; 77 | } 78 | 79 | /** 80 | * @param string $address 81 | */ 82 | public function setAddress($address) 83 | { 84 | $this->address = $address; 85 | } 86 | 87 | /** 88 | * @return string 89 | */ 90 | public function getDescription() 91 | { 92 | return $this->description; 93 | } 94 | 95 | /** 96 | * @param string $description 97 | */ 98 | public function setDescription($description) 99 | { 100 | $this->description = $description; 101 | } 102 | 103 | /** 104 | * @return boolean 105 | */ 106 | public function isShowPublicProfile() 107 | { 108 | return $this->showPublicProfile; 109 | } 110 | 111 | /** 112 | * @param boolean $showPublicProfile 113 | */ 114 | public function setShowPublicProfile($showPublicProfile) 115 | { 116 | $this->showPublicProfile = $showPublicProfile; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /Resources/views/Archive/page.html.twig: -------------------------------------------------------------------------------- 1 | {% extends "BlogBundle::layout.html.twig" %} 2 | {% block title %} 3 | Archivo del sitio {{ pagination.current.item.publishedAt | date('F') | capitalize }} 4 | {% if page != 1 %}| Página {{ page }} | {% endif %} {{ parent() }} 5 | {% endblock %} 6 | {% block canonical %} 7 | 8 | {% endblock %} 9 | {% block meta_description %}{{ pagination.current.item.intro | striptags | truncate(150) }}{% endblock %} 10 | {% block meta_keywords %}{% for tag in pagination.current.item.tags %}{{ tag }}, {% endfor %}{% endblock %} 11 | {% block meta_og %} 12 | {{ parent() }} 13 | 15 | 16 | 17 | {% if pagination.current.item.hasImage %} 18 | 19 | {% endif %} 20 | {% endblock %} 21 | {% block meta_twiter %} 22 | {{ parent() }} 23 | 25 | 26 | {% if pagination.current.item.hasImage %} 27 | 28 | {% endif %} 29 | {% endblock %} 30 | {% block main %} 31 |
32 |
33 |

34 | 35 | {{ pagination.current.item.publishedAt | date('F Y') | capitalize }} 36 | {% if page != 1 %} Página {{ page }}{% endif %} 37 | 38 |

39 |
40 |

Puedes encontrar todas las entradas del sitio ordenadas por fecha

41 |
    42 | {% for item in pagination %} 43 | {% set item = item.item %} 44 |
  • 45 | {{ item }} 46 | {{ item.intro | striptags | raw | truncate(160) }} [..] 47 | el 48 | 51 | . 52 |
  • 53 | {% else %} 54 |
  • No hay elementos
  • 55 | {% endfor %} 56 |
57 |
58 | 59 | {% endblock %} 60 | -------------------------------------------------------------------------------- /DependencyInjection/BlogExtension.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\DependencyInjection; 15 | 16 | use Symfony\Component\Config\FileLocator; 17 | use Symfony\Component\DependencyInjection\ContainerBuilder; 18 | use Symfony\Component\DependencyInjection\Loader; 19 | use Symfony\Component\HttpKernel\DependencyInjection\Extension; 20 | 21 | /** 22 | * This is the class that loads and manages your bundle configuration 23 | * 24 | * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html} 25 | */ 26 | class BlogExtension extends Extension 27 | { 28 | /** 29 | * @var ContainerBuilder 30 | */ 31 | protected $container; 32 | 33 | /** 34 | * {@inheritDoc} 35 | */ 36 | public function load(array $configs, ContainerBuilder $container) 37 | { 38 | $this->container = $container; 39 | 40 | $files = [ 41 | 'twig', 42 | 'search', 43 | 'manager', 44 | 'imagine', 45 | ]; 46 | 47 | $configuration = new Configuration(); 48 | $config = $this->processConfiguration($configuration, $configs); 49 | 50 | foreach ($config as $key => $value) { 51 | $this->parseNode('blog.'.$key, $value); 52 | } 53 | 54 | $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 55 | 56 | foreach ($files as $file) { 57 | $loader->load($file.'.xml'); 58 | } 59 | 60 | $container->setParameter('blog', $config); 61 | } 62 | 63 | /** 64 | * @param string $name 65 | * @param mixed $value 66 | * 67 | * @throws \Exception 68 | */ 69 | protected function parseNode($name, $value) 70 | { 71 | if (is_string($value)) { 72 | $this->set($name, $value); 73 | 74 | return; 75 | } 76 | if (is_integer($value)) { 77 | $this->set($name, $value); 78 | 79 | return; 80 | } 81 | if (is_array($value)) { 82 | foreach ($value as $newKey => $newValue) { 83 | $this->parseNode($name.'.'.$newKey, $newValue); 84 | } 85 | 86 | return; 87 | } 88 | throw new \Exception(gettype($value).' not supported'); 89 | } 90 | 91 | /** 92 | * @param string $key 93 | * @param mixed $value 94 | */ 95 | protected function set($key, $value) 96 | { 97 | $this->container->setParameter($key, $value); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Resources/views/Search/index.html.twig: -------------------------------------------------------------------------------- 1 | {% extends "BlogBundle::layout.html.twig" %} 2 | {% block title %} 3 | {% if query %} Resultados de busqueda "{{ query }}" {% else %} Buscar {% endif %} 4 | {% if page != 1 %}| Página {{ page }} {% endif %} | {{ parent() }} 5 | {% endblock %} 6 | {% block canonical %} 7 | 8 | {% endblock %} 9 | {% block meta_description %}{% if items.0 is defined %}{{ items.0.intro | striptags | truncate(150) }}{% endif %}{% endblock %} 10 | {% block meta_keywords %}{% if items.0 is defined %}{% for tag in items.0.tags %}{{ tag }}, {% endfor %}{% endif %}{% endblock %} 11 | {% block meta_og %} 12 | {{ parent() }} 13 | {% if items.0 is defined %} 14 | 16 | 17 | 18 | {% if items.0.hasImage %} 19 | 20 | {% endif %} 21 | {% endif %} 22 | {% endblock %} 23 | {% block meta_twiter %} 24 | {{ parent() }} 25 | {% if items.0 is defined %} 26 | 28 | 29 | {% if items.0.hasImage %} 30 | 31 | {% endif %} 32 | {% endif %} 33 | {% endblock %} 34 | {% block main %} 35 |
36 |
37 | {% if query %} 38 |

39 | 40 | Resultados de busqueda "{{ query }}" 41 | {% if page != 1 %} Página {{ page }}{% endif %} 42 | 43 |

44 | {% else %} 45 |

Buscar

46 | {% endif %} 47 |
48 | {% include 'BlogBundle:/Search:form.html.twig' with {'form': form} %} 49 | {% if query %} 50 |
    51 | {% for item in items %} 52 |
  • 53 |
    {{ item | highlight(query) | raw }}
    55 | {{ item.intro | striptags | truncate(160) | highlight(query) | raw }} [..] el 56 | 59 |
  • 60 | {% else %} 61 |
  • No se han encontrado resultados de para la búsqueda
  • 62 | {% endfor %} 63 |
64 | {% endif %} 65 | {% if pagination %} 66 | 67 | {% endif %} 68 |
69 | {% endblock %} 70 | {% block search_widget %}{% endblock %} 71 | -------------------------------------------------------------------------------- /Controller/FeedController.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Controller; 15 | 16 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; 17 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 18 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; 19 | use Symfony\Component\HttpFoundation\Request; 20 | 21 | /** 22 | * 23 | * Description of FeedController 24 | * 25 | * @author : Daniel González 26 | */ 27 | class FeedController extends Controller 28 | { 29 | /** 30 | * @Route("/feed/", name="_blog_feed") 31 | * @Route("/feed.{_format}") 32 | * @Method({"GET"}) 33 | */ 34 | public function indexAction(Request $request) 35 | { 36 | $request->setRequestFormat('xml'); 37 | $items = $this->getDoctrine()->getManager() 38 | ->getRepository('BlogBundle:Post')->get( 39 | $this->container->getParameter('blog.rss.items') 40 | ); 41 | 42 | return $this->render( 43 | 'BlogBundle:/Feed:index.xml.twig', 44 | array( 45 | 'title' => $this->container->getParameter('blog.rss.title'), 46 | 'description' => $this->container->getParameter('blog.rss.description'), 47 | 'language' => $this->container->getParameter('blog.rss.language'), 48 | 'ttl' => $this->container->getParameter('blog.rss.ttl'), 49 | 'items' => $items, 50 | ) 51 | ); 52 | } 53 | 54 | /** 55 | * @Route("/feed/{slug}/", name="_blog_feed_tag", requirements={"slug" = "[\w\d\-]+"}) 56 | * @Method({"GET"}) 57 | */ 58 | public function tagAction(Request $request) 59 | { 60 | $request->setRequestFormat('xml'); 61 | $tag = $this->getDoctrine()->getManager() 62 | ->getRepository('BlogBundle:Tag')->getOneBySlug($request->get('slug', false)); 63 | if (!$tag) { 64 | throw $this->createNotFoundException('The tag does not exist'); 65 | } 66 | $items = $this->getDoctrine()->getManager() 67 | ->getRepository('BlogBundle:Post')->getByTag( 68 | $tag, 69 | $this->container->getParameter('blog.rss.items') 70 | ); 71 | 72 | return $this->render( 73 | 'BlogBundle:/Feed:index.xml.twig', 74 | array( 75 | 'title' => $this->container->getParameter('blog.rss.title').' :: '.$tag->getName(), 76 | 'description' => $this->container->getParameter('blog.rss.description'), 77 | 'language' => $this->container->getParameter('blog.rss.language'), 78 | 'ttl' => $this->container->getParameter('blog.rss.ttl'), 79 | 'items' => $items, 80 | ) 81 | ); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Entity/Image.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Entity; 15 | 16 | use Doctrine\ORM\Mapping as ORM; 17 | use Gedmo\Mapping\Annotation as Gedmo; 18 | 19 | /** 20 | * Desarrolla2\Bundle\BlogBundle\Entity\Image 21 | * 22 | * @ORM\Table(name="image") 23 | * @ORM\Entity(repositoryClass="Desarrolla2\Bundle\BlogBundle\Entity\Repository\ImageRepository") 24 | */ 25 | class Image 26 | { 27 | /** 28 | * @ORM\Id 29 | * @ORM\Column(type="integer") 30 | * @ORM\GeneratedValue(strategy="AUTO") 31 | */ 32 | protected $id; 33 | 34 | /** 35 | * @var string $name 36 | * 37 | * @ORM\Column(name="name", type="string", length=255) 38 | */ 39 | protected $name; 40 | 41 | /** 42 | * @ORM\Column(type="string", length=255) 43 | */ 44 | protected $file; 45 | 46 | /** 47 | * @var \DateTime $created_at 48 | * 49 | * @Gedmo\Timestampable(on="create") 50 | * @ORM\Column(name="created_at", type="datetime") 51 | */ 52 | protected $createdAt; 53 | 54 | /** 55 | * @var \DateTime $updated_at 56 | * 57 | * @Gedmo\Timestampable(on="update") 58 | * @ORM\Column(name="updated_at", type="datetime") 59 | */ 60 | protected $updatedAt; 61 | 62 | /** 63 | * Get id 64 | * 65 | * @return integer 66 | */ 67 | public function getId() 68 | { 69 | return $this->id; 70 | } 71 | 72 | /** 73 | * Set file 74 | * 75 | * @param string $file 76 | * @return Image 77 | */ 78 | public function setFile($file) 79 | { 80 | $this->file = $file; 81 | 82 | 83 | } 84 | 85 | /** 86 | * Get file 87 | * 88 | * @return string 89 | */ 90 | public function getFile() 91 | { 92 | return $this->file; 93 | } 94 | 95 | /** 96 | * Set createdAt 97 | * 98 | * @param \DateTime $createdAt 99 | * @return Image 100 | */ 101 | public function setCreatedAt($createdAt) 102 | { 103 | $this->createdAt = $createdAt; 104 | 105 | 106 | } 107 | 108 | /** 109 | * Get createdAt 110 | * 111 | * @return \DateTime 112 | */ 113 | public function getCreatedAt() 114 | { 115 | return $this->createdAt; 116 | } 117 | 118 | /** 119 | * Set updatedAt 120 | * 121 | * @param \DateTime $updatedAt 122 | * @return Image 123 | */ 124 | public function setUpdatedAt($updatedAt) 125 | { 126 | $this->updatedAt = $updatedAt; 127 | 128 | 129 | } 130 | 131 | /** 132 | * Get updatedAt 133 | * 134 | * @return \DateTime 135 | */ 136 | public function getUpdatedAt() 137 | { 138 | return $this->updatedAt; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /Controller/WidgetController.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Controller; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Entity\Post; 17 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; 18 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; 19 | 20 | /** 21 | * WidgetController 22 | */ 23 | class WidgetController extends Controller 24 | { 25 | /** 26 | * @Template() 27 | */ 28 | public function latestCommentAction() 29 | { 30 | return [ 31 | 'comments' => $this->getDoctrine()->getManager() 32 | ->getRepository('BlogBundle:Comment')->getLatest(4) 33 | ]; 34 | } 35 | 36 | /** 37 | * @Template() 38 | */ 39 | public function latestCommentRelatedAction(Post $post, $items = 3) 40 | { 41 | return [ 42 | 'comments' => $this->getDoctrine()->getManager() 43 | ->getRepository('BlogBundle:Comment')->getLatestRelated($post, $items) 44 | ]; 45 | } 46 | 47 | /** 48 | * @Template() 49 | */ 50 | public function latestPostAction() 51 | { 52 | return [ 53 | 'posts' => $this->getDoctrine()->getManager() 54 | ->getRepository('BlogBundle:Post')->getLatest(4) 55 | ]; 56 | } 57 | 58 | /** 59 | * @Template() 60 | */ 61 | public function latestPostRelatedAction(Post $post) 62 | { 63 | return []; 64 | 65 | return [ 66 | 'posts' => $this->getDoctrine()->getManager() 67 | ->getRepository('BlogBundle:Post')->getLatestRelated($post, 4) 68 | ]; 69 | } 70 | 71 | /** 72 | * @Template() 73 | */ 74 | public function tagsAction() 75 | { 76 | return [ 77 | 'tags' => $this->getDoctrine()->getManager() 78 | ->getRepository('BlogBundle:Tag')->get() 79 | ]; 80 | } 81 | 82 | /** 83 | * @Template() 84 | */ 85 | public function linksAction() 86 | { 87 | return [ 88 | 'links' => $this->getDoctrine()->getManager() 89 | ->getRepository('BlogBundle:Link')->getActiveOrdered() 90 | ]; 91 | } 92 | 93 | /** 94 | * @Template() 95 | */ 96 | public function postViewRelatedAction($post, $items = 3) 97 | { 98 | return [ 99 | 'related' => [] 100 | ]; 101 | $search = $this->get('blog.search'); 102 | 103 | return [ 104 | 'related' => $search->related($post, $items), 105 | ]; 106 | } 107 | 108 | /** 109 | * @Template() 110 | */ 111 | public function bannerAction() 112 | { 113 | return [ 114 | 'banner' => $this->getDoctrine()->getManager() 115 | ->getRepository('BlogBundle:Banner')->getRandomActive() 116 | ]; 117 | } 118 | 119 | /** 120 | * @Template() 121 | */ 122 | public function mostAction() 123 | { 124 | return []; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /Entity/Profile.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Entity; 15 | 16 | use Doctrine\ORM\Mapping as ORM; 17 | 18 | /** 19 | * Profile 20 | * 21 | * @ORM\Table(name="profile") 22 | * @ORM\Entity(repositoryClass="Desarrolla2\Bundle\BlogBundle\Entity\Repository\ProfileRepository") 23 | */ 24 | class Profile 25 | { 26 | /** 27 | * @ORM\Id 28 | * @ORM\Column(type="integer") 29 | * @ORM\GeneratedValue(strategy="AUTO") 30 | */ 31 | protected $id; 32 | 33 | /** 34 | * @ORM\OneToOne(targetEntity="User", inversedBy="profile") 35 | * @ORM\JoinColumn(name="user_id", referencedColumnName="id") 36 | **/ 37 | protected $user; 38 | 39 | /** 40 | * @ORM\Column(name="name", type="string", length=255) 41 | */ 42 | protected $name; 43 | 44 | /** 45 | * @ORM\Column(name="address", type="string", length=255) 46 | */ 47 | protected $address; 48 | 49 | /** 50 | * @ORM\Column(name="description", type="text") 51 | */ 52 | protected $description; 53 | 54 | /** 55 | * Constructor 56 | */ 57 | public function __construct() 58 | { 59 | $this->name = ''; 60 | $this->address = ''; 61 | $this->description = ''; 62 | } 63 | 64 | /** 65 | * @return mixed 66 | */ 67 | public function getId() 68 | { 69 | return $this->id; 70 | } 71 | 72 | /** 73 | * @param mixed $id 74 | */ 75 | public function setId($id) 76 | { 77 | $this->id = $id; 78 | } 79 | 80 | /** 81 | * @return mixed 82 | */ 83 | public function getUser() 84 | { 85 | return $this->user; 86 | } 87 | 88 | /** 89 | * @param mixed $user 90 | */ 91 | public function setUser($user) 92 | { 93 | $this->user = $user; 94 | } 95 | 96 | /** 97 | * @return mixed 98 | */ 99 | public function getName() 100 | { 101 | return $this->name; 102 | } 103 | 104 | /** 105 | * @param mixed $name 106 | */ 107 | public function setName($name) 108 | { 109 | $this->name = $name; 110 | } 111 | 112 | /** 113 | * @return mixed 114 | */ 115 | public function getAddress() 116 | { 117 | return $this->address; 118 | } 119 | 120 | /** 121 | * @param mixed $address 122 | */ 123 | public function setAddress($address) 124 | { 125 | $this->address = $address; 126 | } 127 | 128 | /** 129 | * @return mixed 130 | */ 131 | public function getDescription() 132 | { 133 | return $this->description; 134 | } 135 | 136 | /** 137 | * @param mixed $description 138 | */ 139 | public function setDescription($description) 140 | { 141 | $this->description = $description; 142 | } 143 | 144 | /** 145 | * @return mixed 146 | */ 147 | public function getAvatar() 148 | { 149 | return $this->avatar; 150 | } 151 | 152 | /** 153 | * @param mixed $avatar 154 | */ 155 | public function setAvatar($avatar) 156 | { 157 | $this->avatar = $avatar; 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /Search/MySQL.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Search; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Entity\Post; 17 | use Doctrine\Bundle\DoctrineBundle\Registry; 18 | use Knp\Component\Pager\Paginator; 19 | 20 | /** 21 | * Class MySQL 22 | * 23 | * @package Desarrolla2\Bundle\BlogBundle\Search 24 | */ 25 | class MySQL extends AbstractSearch 26 | { 27 | /** 28 | * @var \Doctrine\Bundle\DoctrineBundle\Registry $registry 29 | */ 30 | protected $registry; 31 | 32 | /** 33 | * @var \Doctrine\DBAL\Connection $connection 34 | */ 35 | protected $connection; 36 | 37 | /** 38 | * @var \Doctrine\ORM\EntityManager $manager 39 | */ 40 | protected $manager; 41 | 42 | /** 43 | * @param Registry $registry 44 | * @param \Knp\Component\Pager\Paginator $paginator 45 | * @param $connection 46 | * @param $manager 47 | * @param $itemsPerPage 48 | * @internal param $items 49 | */ 50 | public function __construct(Registry $registry, Paginator $paginator, $connection, $manager, $itemsPerPage) 51 | { 52 | $this->registry = $registry; 53 | $this->paginator = $paginator; 54 | $this->itemsPerPage = $itemsPerPage; 55 | 56 | // this prevents a 'NULL not support' exception 57 | if (!$connection || empty($connection)) { 58 | $connection = null; 59 | } 60 | $this->connection = $registry->getConnection($connection); 61 | 62 | if (!$manager || empty($manager)) { 63 | $manager = null; 64 | } 65 | $this->manager = $registry->getManager($manager); 66 | } 67 | 68 | /** 69 | * @param $query 70 | * @param int $page 71 | * @return array 72 | */ 73 | public function search($query, $page = 1) 74 | { 75 | $searchQueryBuilder = $this->manager->getRepository('BlogBundle:Post')->getSearchBuilder( 76 | $query, 77 | $page, 78 | $this->itemsPerPage 79 | ); 80 | 81 | $this->pagination = $this->paginator->paginate($searchQueryBuilder); 82 | 83 | return $searchQueryBuilder->getQuery()->getResult(); 84 | } 85 | 86 | /** 87 | * @param Post $post 88 | * @param int $limit 89 | * @return mixed 90 | */ 91 | public function related(Post $post, $limit = 3) 92 | { 93 | /** @var \Doctrine\ORM\QueryBuilder $qb */ 94 | $qb = $this->manager->getRepository('BlogBundle:Post')->createQueryBuilder('p'); 95 | $qb->innerJoin('p.tags', 't'); 96 | 97 | $tags = array(); 98 | foreach ($post->getTags() as $tag) { 99 | $tags[] = $tag->getId(); 100 | } 101 | 102 | $qb->where('p.status = 1'); 103 | $qb->andWhere($qb->expr()->neq('p.id', $post->getId())); 104 | $qb->andWhere($qb->expr()->in('t.id', ':tags')); 105 | $qb->setParameter('tags', $tags); 106 | 107 | if ($limit) { 108 | $qb->setMaxResults($limit); 109 | } 110 | 111 | $this->items = $qb->getQuery()->getResult(); 112 | 113 | return $this->items; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /Controller/TagController.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Controller; 15 | 16 | use Doctrine\ORM\Query\QueryException; 17 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; 18 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 19 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; 20 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; 21 | use Symfony\Component\HttpFoundation\RedirectResponse; 22 | use Symfony\Component\HttpFoundation\Request; 23 | 24 | /** 25 | * 26 | * Description of TagController 27 | * 28 | */ 29 | class TagController extends Controller 30 | { 31 | 32 | /** 33 | * @Route("/tag/{slug}/{page}", name="_blog_tag", requirements={"slug" = "[\w\d\-]+", "page" = "\d{1,6}"}, defaults={"page" = "1" }) 34 | * @Method({"GET"}) 35 | * @Template() 36 | */ 37 | public function indexAction(Request $request) 38 | { 39 | $paginator = $this->get('knp_paginator'); 40 | $tag = $this->getDoctrine()->getManager() 41 | ->getRepository('BlogBundle:Tag')->getOneBySlug($request->get('slug', false)); 42 | if (!$tag) { 43 | throw $this->createNotFoundException('The tag does not exist'); 44 | } 45 | 46 | if (!$tag->getItems()) { 47 | throw $this->createNotFoundException('The tag have not items'); 48 | } 49 | 50 | $query = $this->getDoctrine()->getManager() 51 | ->getRepository('BlogBundle:Post')->getQueryForGetByTag($tag); 52 | 53 | try { 54 | $pagination = $paginator->paginate( 55 | $query, $this->getPage(), $this->container->getParameter('blog.items') 56 | ); 57 | } catch (QueryException $e) { 58 | if ($e->getMessage() == 'Invalid parameter number: number of bound variables does not match number of tokens') { 59 | return new RedirectResponse($this->generateUrl('_blog_tag', array( 60 | 'slug' => $tag->getSlug(), 61 | )), 301); 62 | } 63 | throw $e; 64 | } 65 | 66 | return array( 67 | 'page' => $this->getPage(), 68 | 'pagination' => $pagination, 69 | 'tag' => $tag, 70 | ); 71 | } 72 | 73 | /** 74 | * @Route("/tags/{page}", name="_blog_all_tag", requirements={"page" = "\d{1,6}"}, defaults={"page" = "1" }) 75 | * @Method({"GET"}) 76 | * @Template() 77 | */ 78 | public function allAction(Request $request) 79 | { 80 | $paginator = $this->get('knp_paginator'); 81 | 82 | $query = $this->getDoctrine()->getManager() 83 | ->getRepository('BlogBundle:Tag')->getQueryForGet(); 84 | 85 | $pagination = $paginator->paginate( 86 | $query, $this->getPage(), 30 87 | ); 88 | 89 | return array( 90 | 'pagination' => $pagination, 91 | ); 92 | } 93 | 94 | /** 95 | * 96 | * @return type 97 | */ 98 | protected function getPage() 99 | { 100 | $request = $this->getRequest(); 101 | $page = (int) $request->get('page', 1); 102 | if ($page < 1) { 103 | $this->createNotFoundException('Page number is not valid'.$page); 104 | } 105 | 106 | return $page; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Controller/SiteMapController.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Controller; 15 | 16 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; 17 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 18 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; 19 | use Symfony\Component\HttpFoundation\Request; 20 | 21 | /** 22 | * Class SiteMapController 23 | * 24 | * @author Daniel González 25 | */ 26 | class SiteMapController extends Controller 27 | { 28 | /** 29 | * @Route("/sitemap.xml", name="_blog_sitemap") 30 | * @Method({"GET"}) 31 | */ 32 | public function indexAction(Request $request) 33 | { 34 | $request->setRequestFormat('xml'); 35 | 36 | return $this->render( 37 | 'BlogBundle:/SiteMap:index.xml.twig', 38 | array() 39 | ); 40 | } 41 | 42 | /** 43 | * @Route("/sitemap.archive.xml", name="_blog_sitemap_archive") 44 | * @Method({"GET"}) 45 | */ 46 | public function archiveAction(Request $request) 47 | { 48 | return $this->render( 49 | 'BlogBundle:/SiteMap:archive.xml.twig', 50 | array( 51 | 'items' => $this->getDoctrine()->getManager() 52 | ->getRepository('BlogBundle:Post')->getArchiveItems(), 53 | ) 54 | ); 55 | } 56 | 57 | /** 58 | * @Route("/sitemap.post.xml", name="_blog_sitemap_post") 59 | * @Method({"GET"}) 60 | */ 61 | public function postAction(Request $request) 62 | { 63 | $request->setRequestFormat('xml'); 64 | $items = array(); 65 | $posts = $this->getDoctrine()->getManager() 66 | ->getRepository('BlogBundle:Post')->get( 67 | $this->container->getParameter('blog.sitemap.items') 68 | ); 69 | foreach ($posts as $post) { 70 | $items[] = $this->generateUrl('_blog_view', array('slug' => $post->getSlug()), true); 71 | } 72 | 73 | return $this->render( 74 | 'BlogBundle:/SiteMap:post.xml.twig', 75 | array( 76 | 'items' => $items, 77 | ) 78 | ); 79 | } 80 | 81 | /** 82 | * @Route("/sitemap.search.xml", name="_blog_sitemap_search") 83 | * @Method({"GET"}) 84 | */ 85 | public function searchAction(Request $request) 86 | { 87 | $items = array(); 88 | 89 | return $this->render( 90 | 'BlogBundle:/SiteMap:archive.xml.twig', 91 | array( 92 | 'items' => $items, 93 | ) 94 | ); 95 | } 96 | 97 | /** 98 | * @Route("/sitemap.tag.xml", name="_blog_sitemap_tag") 99 | * @Method({"GET"}) 100 | */ 101 | public function tagAction(Request $request) 102 | { 103 | $request->setRequestFormat('xml'); 104 | $items = array(); 105 | $tags = $this->getDoctrine()->getManager() 106 | ->getRepository('BlogBundle:Tag')->get( 107 | $this->container->getParameter('blog.sitemap.items') 108 | ); 109 | foreach ($tags as $tag) { 110 | $items[] = $this->generateUrl('_blog_tag', array('slug' => $tag->getSlug()), true); 111 | } 112 | 113 | return $this->render( 114 | 'BlogBundle:/SiteMap:tag.xml.twig', 115 | array( 116 | 'items' => $items, 117 | ) 118 | ); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /DependencyInjection/Configuration.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\DependencyInjection; 15 | 16 | use Symfony\Component\Config\Definition\Builder\TreeBuilder; 17 | use Symfony\Component\Config\Definition\ConfigurationInterface; 18 | 19 | /** 20 | * This is the class that validates and merges configuration from your app/config files 21 | * 22 | * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class} 23 | */ 24 | class Configuration implements ConfigurationInterface 25 | { 26 | /** 27 | * {@inheritDoc} 28 | */ 29 | public function getConfigTreeBuilder() 30 | { 31 | $treeBuilder = new TreeBuilder(); 32 | $rootNode = $treeBuilder->root('blog'); 33 | 34 | $rootNode->addDefaultsIfNotSet() 35 | ->children() 36 | ->scalarNode('title')->defaultValue('my blog title')->end() 37 | ->scalarNode('description')->defaultValue('my blog description')->end() 38 | ->scalarNode('items')->defaultValue(12)->end() 39 | ->scalarNode('ga_tracking')->defaultValue('')->end() 40 | ->scalarNode('locale')->defaultValue('en')->end() 41 | ->scalarNode('default_image')->defaultValue('')->end() 42 | ->scalarNode('upload_dir')->defaultValue('%kernel.root_dir%/../web/uploads')->end() 43 | ->scalarNode('upload_url')->defaultValue('/uploads')->end() 44 | ->append($this->createSearchSection()) 45 | ->append($this->createSiteMapSection()) 46 | ->append($this->createRSSSection()) 47 | ->end(); 48 | 49 | return $treeBuilder; 50 | } 51 | 52 | private function createSearchSection() 53 | { 54 | $builder = new TreeBuilder(); 55 | $node = $builder->root('search'); 56 | $node 57 | ->addDefaultsIfNotSet() 58 | ->children() 59 | ->scalarNode('provider')->defaultValue('mysql')->end() 60 | ->arrayNode('mysql') 61 | ->addDefaultsIfNotSet() 62 | ->children() 63 | ->scalarNode('connection')->defaultValue('')->end() 64 | ->scalarNode('manager')->defaultValue('')->end() 65 | ->end() 66 | ->end() 67 | ->arrayNode('sphinx') 68 | ->addDefaultsIfNotSet() 69 | ->children() 70 | ->scalarNode('host')->defaultValue('localhost')->end() 71 | ->scalarNode('port')->defaultValue(9312)->end() 72 | ->scalarNode('index')->defaultValue('search_idx')->end() 73 | ->scalarNode('items')->defaultValue(12)->end() 74 | ->end() 75 | ->end() 76 | ->end(); 77 | 78 | return $node; 79 | } 80 | 81 | private function createSiteMapSection() 82 | { 83 | $builder = new TreeBuilder(); 84 | $node = $builder->root('sitemap'); 85 | $node->addDefaultsIfNotSet() 86 | ->children() 87 | ->scalarNode('items')->defaultValue(2000)->end() 88 | ->end(); 89 | 90 | return $node; 91 | } 92 | 93 | private function createRSSSection() 94 | { 95 | $builder = new TreeBuilder(); 96 | $node = $builder->root('rss'); 97 | $node->addDefaultsIfNotSet() 98 | ->children() 99 | ->scalarNode('title')->defaultValue('RSS Feed')->end() 100 | ->scalarNode('description')->defaultValue('my RSS feed')->end() 101 | ->scalarNode('language')->defaultValue('en')->end() 102 | ->scalarNode('items')->defaultValue(16)->end() 103 | ->scalarNode('ttl')->defaultValue(60)->end() 104 | ->end(); 105 | 106 | return $node; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Entity/Author.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Entity; 15 | 16 | use Doctrine\ORM\Mapping as ORM; 17 | use Gedmo\Mapping\Annotation as Gedmo; 18 | 19 | /** 20 | * Author 21 | * 22 | * @ORM\Table(name="author") 23 | * @ORM\Entity(repositoryClass="Desarrolla2\Bundle\BlogBundle\Entity\Repository\AuthorRepository") 24 | */ 25 | class Author 26 | { 27 | /** 28 | * @var integer $id 29 | * 30 | * @ORM\Column(name="id", type="integer") 31 | * @ORM\Id 32 | * @ORM\GeneratedValue(strategy="AUTO") 33 | */ 34 | protected $id; 35 | 36 | /** 37 | * @var string $name 38 | * 39 | * @ORM\Column(name="name", type="string", length=255) 40 | */ 41 | protected $name; 42 | 43 | /** 44 | * @var string $email 45 | * 46 | * @ORM\Column(name="email", type="string", length=255, unique=true) 47 | */ 48 | protected $email; 49 | 50 | /** 51 | * @var string $slug 52 | * 53 | * @Gedmo\Slug(fields={"name"}) 54 | * @ORM\Column(name="slug", type="string", length=255, unique=true)) 55 | */ 56 | protected $slug; 57 | 58 | /** 59 | * @var \DateTime $createdAt 60 | * 61 | * @Gedmo\Timestampable(on="create") 62 | * @ORM\Column(name="created_at", type="datetime") 63 | */ 64 | protected $createdAt; 65 | 66 | /** 67 | * @var \DateTime $updatedAt 68 | * 69 | * @Gedmo\Timestampable(on="update") 70 | * @ORM\Column(name="updated_at", type="datetime") 71 | */ 72 | protected $updatedAt; 73 | 74 | /** 75 | * @return string 76 | */ 77 | public function __toString() 78 | { 79 | return $this->getName(); 80 | } 81 | 82 | /** 83 | * Get id 84 | * 85 | * @return integer 86 | */ 87 | public function getId() 88 | { 89 | return $this->id; 90 | } 91 | 92 | /** 93 | * Set name 94 | * 95 | * @param string $name 96 | * 97 | * @return Author 98 | */ 99 | public function setName($name) 100 | { 101 | $this->name = $name; 102 | } 103 | 104 | /** 105 | * Get name 106 | * 107 | * @return string 108 | */ 109 | public function getName() 110 | { 111 | return $this->name; 112 | } 113 | 114 | /** 115 | * Set created_at 116 | * 117 | * @param \DateTime $createdAt 118 | * 119 | * @return Author 120 | */ 121 | public function setCreatedAt($createdAt) 122 | { 123 | $this->createdAt = $createdAt; 124 | 125 | 126 | } 127 | 128 | /** 129 | * Get created_at 130 | * 131 | * @return \DateTime 132 | */ 133 | public function getCreatedAt() 134 | { 135 | return $this->createdAt; 136 | } 137 | 138 | /** 139 | * Set updated_at 140 | * 141 | * @param \DateTime $updatedAt 142 | * 143 | * @return Author 144 | */ 145 | public function setUpdatedAt($updatedAt) 146 | { 147 | $this->updatedAt = $updatedAt; 148 | 149 | 150 | } 151 | 152 | /** 153 | * Get updated_at 154 | * 155 | * @return \DateTime 156 | */ 157 | public function getUpdatedAt() 158 | { 159 | return $this->updatedAt; 160 | } 161 | 162 | /** 163 | * Set slug 164 | * 165 | * @param string $slug 166 | * 167 | * @return Author 168 | */ 169 | public function setSlug($slug) 170 | { 171 | $this->slug = $slug; 172 | } 173 | 174 | /** 175 | * Get slug 176 | * 177 | * @return string 178 | */ 179 | public function getSlug() 180 | { 181 | return $this->slug; 182 | } 183 | 184 | /** 185 | * Get email 186 | * 187 | * @return string 188 | */ 189 | public function getEmail() 190 | { 191 | return $this->email; 192 | } 193 | 194 | /** 195 | * set email 196 | * 197 | * @param string $email 198 | */ 199 | public function setEmail($email) 200 | { 201 | $this->email = $email; 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /Entity/Tag.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Entity; 15 | 16 | use Doctrine\ORM\Mapping as ORM; 17 | use Gedmo\Mapping\Annotation as Gedmo; 18 | 19 | /** 20 | * Desarrolla2\Bundle\BlogBundle\Entity\Tag 21 | * 22 | * @ORM\Table(name="tag") 23 | * @ORM\Entity(repositoryClass="Desarrolla2\Bundle\BlogBundle\Entity\Repository\TagRepository") 24 | */ 25 | class Tag 26 | { 27 | /** 28 | * @var integer $id 29 | * 30 | * @ORM\Column(name="id", type="integer") 31 | * @ORM\Id 32 | * @ORM\GeneratedValue(strategy="AUTO") 33 | */ 34 | protected $id; 35 | 36 | /** 37 | * @var string $name 38 | * 39 | * @ORM\Column(name="name", type="string", length=255) 40 | */ 41 | protected $name; 42 | 43 | /** 44 | * @var string $slug 45 | * 46 | * @Gedmo\Slug(fields={"name"}) 47 | * @ORM\Column(name="slug", type="string", length=255, unique=true)) 48 | */ 49 | protected $slug; 50 | 51 | /** 52 | * @var int $items 53 | * 54 | * @ORM\Column(name="items", type="integer") 55 | */ 56 | protected $items; 57 | 58 | /** 59 | * @var \DateTime $createdAt 60 | * 61 | * @Gedmo\Timestampable(on="create") 62 | * @ORM\Column(name="created_at", type="datetime") 63 | */ 64 | protected $createdAt; 65 | 66 | /** 67 | * @var \DateTime $updatedAt 68 | * 69 | * @Gedmo\Timestampable(on="update") 70 | * @ORM\Column(name="updated_at", type="datetime") 71 | */ 72 | protected $updatedAt; 73 | 74 | /** 75 | * Constructor 76 | */ 77 | public function __construct() 78 | { 79 | $this->items = 0; 80 | } 81 | 82 | /** 83 | * @return string 84 | */ 85 | public function __toString() 86 | { 87 | return $this->getName(); 88 | } 89 | 90 | /** 91 | * Get id 92 | * 93 | * @return integer 94 | */ 95 | public function getId() 96 | { 97 | return $this->id; 98 | } 99 | 100 | /** 101 | * Set name 102 | * 103 | * @param string $name 104 | * 105 | * @return Tag 106 | */ 107 | public function setName($name) 108 | { 109 | $this->name = strtolower($name); 110 | } 111 | 112 | /** 113 | * Get name 114 | * 115 | * @return string 116 | */ 117 | public function getName() 118 | { 119 | return $this->name; 120 | } 121 | 122 | /** 123 | * Set created_at 124 | * 125 | * @param \DateTime $createdAt 126 | * 127 | * @return Tag 128 | */ 129 | public function setCreatedAt($createdAt) 130 | { 131 | $this->createdAt = $createdAt; 132 | } 133 | 134 | /** 135 | * Get created_at 136 | * 137 | * @return \DateTime 138 | */ 139 | public function getCreatedAt() 140 | { 141 | return $this->createdAt; 142 | } 143 | 144 | /** 145 | * Set updated_at 146 | * 147 | * @param \DateTime $updatedAt 148 | * 149 | * @return Tag 150 | */ 151 | public function setUpdatedAt($updatedAt) 152 | { 153 | $this->updatedAt = $updatedAt; 154 | } 155 | 156 | /** 157 | * Get updated_at 158 | * 159 | * @return \DateTime 160 | */ 161 | public function getUpdatedAt() 162 | { 163 | return $this->updatedAt; 164 | } 165 | 166 | /** 167 | * Set slug 168 | * 169 | * @param string $slug 170 | * 171 | * @return Tag 172 | */ 173 | public function setSlug($slug) 174 | { 175 | $this->slug = $slug; 176 | } 177 | 178 | /** 179 | * Get slug 180 | * 181 | * @return string 182 | */ 183 | public function getSlug() 184 | { 185 | return $this->slug; 186 | } 187 | 188 | /** 189 | * Set items 190 | * 191 | * @param int $items 192 | * 193 | * @return Tag 194 | */ 195 | public function setItems($items) 196 | { 197 | $this->items = (int) $items; 198 | } 199 | 200 | /** 201 | * Get items 202 | * 203 | * @return int 204 | */ 205 | public function getItems() 206 | { 207 | return $this->items; 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /Entity/Comment.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Entity; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Model\CommentStatus; 17 | use Doctrine\ORM\Mapping as ORM; 18 | use Gedmo\Mapping\Annotation as Gedmo; 19 | 20 | /** 21 | * Comment 22 | * 23 | * @ORM\Table(name="comment") 24 | * @ORM\Entity(repositoryClass="Desarrolla2\Bundle\BlogBundle\Entity\Repository\CommentRepository") 25 | */ 26 | class Comment 27 | { 28 | /** 29 | * @var integer $id 30 | * 31 | * @ORM\Column(name="id", type="integer") 32 | * @ORM\Id 33 | * @ORM\GeneratedValue(strategy="AUTO") 34 | */ 35 | protected $id; 36 | 37 | /** 38 | * @var Post 39 | * 40 | * @ORM\ManyToOne(targetEntity="Post", inversedBy="comments") 41 | * @ORM\JoinColumn(name="post_id", referencedColumnName="id") 42 | */ 43 | protected $post; 44 | 45 | /** 46 | * @var User 47 | * 48 | * @ORM\ManyToOne(targetEntity="User") 49 | * @ORM\JoinColumn(name="user_id", referencedColumnName="id") 50 | */ 51 | protected $user; 52 | 53 | /** 54 | * @var string $content 55 | * 56 | * @ORM\Column(name="content", type="text") 57 | */ 58 | protected $content; 59 | 60 | /** 61 | * @var string status 62 | * 63 | * @ORM\Column(name="status", type="integer") 64 | */ 65 | protected $status; 66 | 67 | /** 68 | * @var \DateTime $createdAt 69 | * 70 | * @Gedmo\Timestampable(on="create") 71 | * @ORM\Column(name="created_at", type="datetime") 72 | */ 73 | protected $createdAt; 74 | 75 | /** 76 | * @var \DateTime $updatedAt 77 | * 78 | * @Gedmo\Timestampable(on="update") 79 | * @ORM\Column(name="updated_at", type="datetime") 80 | */ 81 | protected $updatedAt; 82 | 83 | /** 84 | * @param Post $post 85 | * @param User $user 86 | */ 87 | public function __construct(Post $post, User $user = null) 88 | { 89 | $this->post = $post; 90 | $this->user = $user; 91 | $this->status = CommentStatus::PENDING; 92 | } 93 | 94 | /** 95 | * @return string 96 | */ 97 | public function __toString() 98 | { 99 | return $this->getContent(); 100 | } 101 | 102 | /** 103 | * Get id 104 | * 105 | * @return integer 106 | */ 107 | public function getId() 108 | { 109 | return $this->id; 110 | } 111 | 112 | /** 113 | * Set content 114 | * 115 | * @param string $content 116 | * 117 | * @return Comment 118 | */ 119 | public function setContent($content) 120 | { 121 | $this->content = $content; 122 | 123 | 124 | } 125 | 126 | /** 127 | * Get content 128 | * 129 | * @return string 130 | */ 131 | public function getContent() 132 | { 133 | return $this->content; 134 | } 135 | 136 | /** 137 | * Set published 138 | * 139 | * @param boolean $published 140 | * 141 | * @return Comment 142 | */ 143 | public function setPublished($published) 144 | { 145 | $this->published = $published; 146 | 147 | 148 | } 149 | 150 | /** 151 | * Get published 152 | * 153 | * @return boolean 154 | */ 155 | public function getPublished() 156 | { 157 | return $this->published; 158 | } 159 | 160 | /** 161 | * Set createdAt 162 | * 163 | * @param \DateTime $createdAt 164 | * 165 | * @return Comment 166 | */ 167 | public function setCreatedAt($createdAt) 168 | { 169 | $this->createdAt = $createdAt; 170 | 171 | 172 | } 173 | 174 | /** 175 | * Get createdAt 176 | * 177 | * @return \DateTime 178 | */ 179 | public function getCreatedAt() 180 | { 181 | return $this->createdAt; 182 | } 183 | 184 | /** 185 | * Set updatedAt 186 | * 187 | * @param \DateTime $updatedAt 188 | * 189 | * @return Comment 190 | */ 191 | public function setUpdatedAt($updatedAt) 192 | { 193 | $this->updatedAt = $updatedAt; 194 | 195 | 196 | } 197 | 198 | /** 199 | * Get updatedAt 200 | * 201 | * @return \DateTime 202 | */ 203 | public function getUpdatedAt() 204 | { 205 | return $this->updatedAt; 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /Controller/ArchiveController.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Controller; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Model\PostStatus; 17 | use Doctrine\ORM\Query\ResultSetMapping; 18 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; 19 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 20 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; 21 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; 22 | use Symfony\Component\HttpFoundation\Request; 23 | 24 | /** 25 | * ArchiveController 26 | * 27 | * @Route("/archive") 28 | */ 29 | class ArchiveController extends Controller 30 | { 31 | 32 | /** 33 | * @Route("/", name="_blog_archive") 34 | * @Method({"GET"}) 35 | * @Template() 36 | */ 37 | public function indexAction(Request $request) 38 | { 39 | $items = $this->session->all(); 40 | $sessionValues = []; 41 | foreach ($items as $item) { 42 | if (!is_object($item)) { 43 | $sessionValues[] = (string) $item; 44 | continue; 45 | } 46 | if (method_exists($item, '__toString')) { 47 | $sessionValues[] = $item->__toString(); 48 | } 49 | } 50 | 51 | return [ 52 | 'items' => $this->getDoctrine()->getManager() 53 | ->getRepository('BlogBundle:Post')->getArchiveItems(), 54 | ]; 55 | } 56 | 57 | /** 58 | * @Route( 59 | * "/{year}/{month}/{page}", 60 | * name="_blog_archive_page", 61 | * requirements={"year"="\d{4}", "month"="\d{1,2}", "page" = "\d{1,4}"}, defaults={"page" = "1" } 62 | * ) 63 | * @Route("/{year}/{month}", requirements={"year"="\d{4}", "month"="\d{1,2}"}) 64 | * @Method({"GET"}) 65 | * @Template() 66 | */ 67 | public function pageAction(Request $request) 68 | { 69 | $paginator = $this->get('knp_paginator'); 70 | $year = $request->get('year'); 71 | $month = $request->get('month'); 72 | $page = $this->getPage($request); 73 | $rsm = new ResultSetMapping(); 74 | $rsm->addScalarResult('n', 'n', 'string'); 75 | $count = 76 | $query = $this->getDoctrine() 77 | ->getManager() 78 | ->createNativeQuery( 79 | ' SELECT COUNT(*) as n FROM ( '. 80 | ' SELECT p.id, '. 81 | ' SUBSTRING(p.published_at, 1, 4) AS year, '. 82 | ' SUBSTRING(p.published_at, 6, 2) AS month '. 83 | ' FROM post AS p'. 84 | ' WHERE p.status = '.PostStatus::PUBLISHED. 85 | ' HAVING year = :year '. 86 | ' AND month = :month '. 87 | ' ) AS items', 88 | $rsm 89 | ) 90 | ->setParameter('year', $year) 91 | ->setParameter('month', $month) 92 | ->getSingleScalarResult(); 93 | 94 | $query = $this->getDoctrine() 95 | ->getManager() 96 | ->createQuery( 97 | ' SELECT p as item, '. 98 | ' SUBSTRING(p.publishedAt, 1, 4) as year, '. 99 | ' SUBSTRING(p.publishedAt, 6, 2) as month '. 100 | ' FROM BlogBundle:Post p '. 101 | ' WHERE p.status = '.PostStatus::PUBLISHED. 102 | ' HAVING year = :year '. 103 | ' AND month = :month ' 104 | ) 105 | ->setHint('knp_paginator.count', $count) 106 | ->setParameter('year', $year) 107 | ->setParameter('month', $month); 108 | 109 | $pagination = $paginator->paginate( 110 | $query->getResult(), 111 | $page, 112 | $this->container->getParameter('blog.items'), 113 | ['distinct' => false] 114 | ); 115 | 116 | return [ 117 | 'page' => $page, 118 | 'year' => $year, 119 | 'month' => $month, 120 | 'pagination' => $pagination, 121 | ]; 122 | } 123 | 124 | /** 125 | * @param Request $request 126 | * 127 | * @return int 128 | */ 129 | protected function getPage(Request $request) 130 | { 131 | $page = (int) $request->get('page', 1); 132 | if ($page < 1) { 133 | $this->createNotFoundException('Page number is not valid'.$page); 134 | } 135 | 136 | return $page; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /Search/Sphinx.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Search; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Entity\Post; 17 | use Doctrine\ORM\EntityManager; 18 | use Knp\Component\Pager\Paginator; 19 | use SphinxClient; 20 | 21 | class Sphinx extends AbstractSearch 22 | { 23 | 24 | /** 25 | * @var EntityManager 26 | */ 27 | protected $em; 28 | 29 | /** 30 | * @var string $host 31 | */ 32 | protected $host; 33 | 34 | /** 35 | * @var string $port 36 | */ 37 | protected $port; 38 | 39 | /** 40 | * @var string $index 41 | */ 42 | protected $index; 43 | 44 | /** 45 | * @var SphinxClient $sphinx 46 | */ 47 | protected $sphinx; 48 | 49 | /** 50 | * 51 | * @param \Doctrine\ORM\EntityManager $em 52 | * @param \Knp\Component\Pager\Paginator $paginator 53 | * @param string $host 54 | * @param string $port 55 | * @param string $index 56 | */ 57 | public function __construct(EntityManager $em, Paginator $paginator, $host, $port, $index) 58 | { 59 | $this->sphinx = new SphinxClient(); 60 | $this->em = $em; 61 | $this->paginator = $paginator; 62 | $this->host = $host; 63 | $this->port = $port; 64 | $this->index = $index; 65 | $this->sphinx->SetServer($this->host, $this->port); 66 | $this->sphinx->SetMaxQueryTime(3000); 67 | $this->sphinx->SetSortMode( 68 | SPH_SORT_EXPR, 69 | ' @weight * 1000 + published_at ' 70 | ); 71 | } 72 | 73 | /** 74 | * 75 | * @param Post $post 76 | * @param int $limit 77 | * @param int $limit 78 | * @return array 79 | */ 80 | public function related(Post $post, $limit = 3) 81 | { 82 | $this->sphinx->SetMatchMode(SPH_MATCH_ANY); 83 | $this->sphinx->SetLimits(0, $limit); 84 | $ids = $this->sphinxSearch($post->getTagsAsString()); 85 | if (!$ids) { 86 | return array(); 87 | } 88 | $items = $this->em->getRepository('BlogBundle:Post')->getByIds($ids); 89 | $this->items = $this->orderResults($ids, $items); 90 | 91 | return $this->items; 92 | } 93 | 94 | /** 95 | * 96 | * @param string $query 97 | * @param int $page 98 | * @return array 99 | */ 100 | public function search($query, $page) 101 | { 102 | $this->sphinx->SetLimits(0, $this->maxSearchResults); 103 | $this->sphinx->SetMatchMode(SPH_MATCH_ALL); 104 | $ids = $this->sphinxSearch($query); 105 | if (!$ids) { 106 | return array(); 107 | } 108 | $this->pagination = $this->paginator->paginate($ids, $page, $this->itemsPerPage); 109 | $items = $this->em->getRepository('BlogBundle:Post')->getByIds($this->pagination->getItems()); 110 | $this->items = $this->orderResults($ids, $items); 111 | 112 | return $this->items; 113 | } 114 | 115 | /** 116 | * @param array $ids 117 | * @param array $items 118 | * @return array 119 | */ 120 | protected function orderResults($ids, $items) 121 | { 122 | $result = array(); 123 | foreach ($ids as $id) { 124 | foreach ($items as $key => $item) { 125 | if ($id != $item->getId()) { 126 | continue; 127 | } 128 | $result[] = $item; 129 | unset($items[$key]); 130 | break; 131 | } 132 | } 133 | 134 | return $result; 135 | } 136 | 137 | /** 138 | * @param $query 139 | * @return array 140 | * @throws \RuntimeException 141 | */ 142 | protected function sphinxSearch($query) 143 | { 144 | $ids = array(); 145 | $query = $this->sphinx->escapeString($query); 146 | $response = $this->sphinx->Query($query, $this->index); 147 | if ($response === false) { 148 | throw new \RuntimeException('Sphinx Query failed: '.$this->sphinx->GetLastError()); 149 | } else { 150 | if (empty($response['matches'])) { 151 | return; 152 | } 153 | foreach ($response['matches'] as $doc => $docInfo) { 154 | $ids[] = $doc; 155 | } 156 | } 157 | 158 | return $ids; 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /Entity/PostHistory.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Entity; 15 | 16 | use Doctrine\ORM\Mapping as ORM; 17 | use Gedmo\Mapping\Annotation as Gedmo; 18 | 19 | /** 20 | * PostHistory 21 | * 22 | * @ORM\Table(name="post_history") 23 | * @ORM\Entity(repositoryClass="Desarrolla2\Bundle\BlogBundle\Entity\Repository\PostHistoryRepository") 24 | */ 25 | class PostHistory 26 | { 27 | /** 28 | * @var integer $id 29 | * 30 | * @ORM\Column(name="id", type="integer") 31 | * @ORM\Id 32 | * @ORM\GeneratedValue(strategy="AUTO") 33 | */ 34 | protected $id; 35 | 36 | /** 37 | * @var Post 38 | * 39 | * @ORM\ManyToOne(targetEntity="Post") 40 | * @ORM\JoinColumn(name="post_id", referencedColumnName="id") 41 | */ 42 | protected $post; 43 | 44 | /** 45 | * @var string $name 46 | * 47 | * @ORM\Column(name="name", type="string", length=255) 48 | */ 49 | protected $name; 50 | 51 | /** 52 | * @var string $intro 53 | * 54 | * @ORM\Column(name="intro", type="text") 55 | */ 56 | protected $intro; 57 | 58 | /** 59 | * @var string $content 60 | * 61 | * @ORM\Column(name="content", type="text") 62 | */ 63 | protected $content; 64 | 65 | /** 66 | * @var \DateTime $created_at 67 | * 68 | * @Gedmo\Timestampable(on="create") 69 | * @ORM\Column(name="created_at", type="datetime") 70 | */ 71 | protected $createdAt; 72 | 73 | /** 74 | * Constructor 75 | */ 76 | public function __construct() 77 | { 78 | } 79 | 80 | /** 81 | * @return string 82 | */ 83 | public function __toString() 84 | { 85 | return $this->getName(); 86 | } 87 | 88 | /** 89 | * Get id 90 | * 91 | * @return integer 92 | */ 93 | public function getId() 94 | { 95 | return $this->id; 96 | } 97 | 98 | /** 99 | * Set name 100 | * 101 | * @param string $name 102 | * 103 | * @return PostHistory 104 | */ 105 | public function setName($name) 106 | { 107 | $this->name = $name; 108 | 109 | 110 | } 111 | 112 | /** 113 | * Get name 114 | * 115 | * @return string 116 | */ 117 | public function getName() 118 | { 119 | return $this->name; 120 | } 121 | 122 | /** 123 | * Set intro 124 | * 125 | * @param string $intro 126 | * 127 | * @return PostHistory 128 | */ 129 | public function setIntro($intro) 130 | { 131 | $this->intro = $intro; 132 | 133 | 134 | } 135 | 136 | /** 137 | * Get intro 138 | * 139 | * @return string 140 | */ 141 | public function getIntro() 142 | { 143 | return $this->intro; 144 | } 145 | 146 | /** 147 | * Set content 148 | * 149 | * @param string $content 150 | * 151 | * @return PostHistory 152 | */ 153 | public function setContent($content) 154 | { 155 | $this->content = $content; 156 | 157 | 158 | } 159 | 160 | /** 161 | * Get content 162 | * 163 | * @return string 164 | */ 165 | public function getContent() 166 | { 167 | return $this->content; 168 | } 169 | 170 | /** 171 | * Set createdAt 172 | * 173 | * @param \DateTime $createdAt 174 | * 175 | * @return PostHistory 176 | */ 177 | public function setCreatedAt($createdAt) 178 | { 179 | $this->createdAt = $createdAt; 180 | 181 | 182 | } 183 | 184 | /** 185 | * Get createdAt 186 | * 187 | * @return \DateTime 188 | */ 189 | public function getCreatedAt() 190 | { 191 | return $this->createdAt; 192 | } 193 | 194 | /** 195 | * Set post 196 | * 197 | * @param \Desarrolla2\Bundle\BlogBundle\Entity\Post $post 198 | * 199 | * @return PostHistory 200 | */ 201 | public function setPost(\Desarrolla2\Bundle\BlogBundle\Entity\Post $post = null) 202 | { 203 | $this->post = $post; 204 | $this->setName($post->getName()); 205 | $this->setIntro($post->getIntro()); 206 | $this->setContent($post->getContent()); 207 | 208 | 209 | } 210 | 211 | /** 212 | * Get post 213 | * 214 | * @return \Desarrolla2\Bundle\BlogBundle\Entity\Post 215 | */ 216 | public function getPost() 217 | { 218 | return $this->post; 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /Entity/Banner.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Entity; 15 | 16 | use Doctrine\ORM\Mapping as ORM; 17 | use Gedmo\Mapping\Annotation as Gedmo; 18 | 19 | /** 20 | * Banner 21 | * 22 | * @ORM\Table(name="banner") 23 | * @ORM\Entity(repositoryClass="Desarrolla2\Bundle\BlogBundle\Entity\Repository\BannerRepository") 24 | */ 25 | class Banner 26 | { 27 | /** 28 | * @var integer $id 29 | * 30 | * @ORM\Column(name="id", type="integer") 31 | * @ORM\Id 32 | * @ORM\GeneratedValue(strategy="AUTO") 33 | */ 34 | protected $id; 35 | 36 | /** 37 | * @var string $name 38 | * 39 | * @ORM\Column(name="name", type="string", length=255) 40 | */ 41 | protected $name; 42 | 43 | /** 44 | * @var string $content 45 | * 46 | * @ORM\Column(name="content", type="text") 47 | */ 48 | protected $content; 49 | 50 | /** 51 | * 52 | * @var Post 53 | * 54 | * @ORM\Column(name="weight", type="integer") 55 | */ 56 | protected $weight; 57 | 58 | /** 59 | * @var string $isPublished 60 | * 61 | * @ORM\Column(name="is_published", type="boolean") 62 | */ 63 | protected $isPublished = false; 64 | 65 | /** 66 | * @var \DateTime $created_at 67 | * 68 | * @Gedmo\Timestampable(on="create") 69 | * @ORM\Column(name="created_at", type="datetime") 70 | */ 71 | protected $createdAt; 72 | 73 | /** 74 | * @var \DateTime $updated_at 75 | * 76 | * @Gedmo\Timestampable(on="update") 77 | * @ORM\Column(name="updated_at", type="datetime") 78 | */ 79 | protected $updatedAt; 80 | 81 | /** 82 | * Get id 83 | * 84 | * @return integer 85 | */ 86 | public function getId() 87 | { 88 | return $this->id; 89 | } 90 | 91 | /** 92 | * Set name 93 | * 94 | * @param string $name 95 | * 96 | * @return Banner 97 | */ 98 | public function setName($name) 99 | { 100 | $this->name = $name; 101 | } 102 | 103 | /** 104 | * Get name 105 | * 106 | * @return string 107 | */ 108 | public function getName() 109 | { 110 | return $this->name; 111 | } 112 | 113 | /** 114 | * Set content 115 | * 116 | * @param string $content 117 | * 118 | * @return Banner 119 | */ 120 | public function setContent($content) 121 | { 122 | $this->content = $content; 123 | } 124 | 125 | /** 126 | * Get content 127 | * 128 | * @return string 129 | */ 130 | public function getContent() 131 | { 132 | return $this->content; 133 | } 134 | 135 | /** 136 | * Set isPublished 137 | * 138 | * @param boolean $isPublished 139 | * 140 | * @return Banner 141 | */ 142 | public function setIsPublished($isPublished) 143 | { 144 | $this->isPublished = $isPublished; 145 | 146 | 147 | } 148 | 149 | /** 150 | * Get isPublished 151 | * 152 | * @return boolean 153 | */ 154 | public function getIsPublished() 155 | { 156 | return $this->isPublished; 157 | } 158 | 159 | /** 160 | * Set createdAt 161 | * 162 | * @param \DateTime $createdAt 163 | * 164 | * @return Banner 165 | */ 166 | public function setCreatedAt($createdAt) 167 | { 168 | $this->createdAt = $createdAt; 169 | 170 | 171 | } 172 | 173 | /** 174 | * Get createdAt 175 | * 176 | * @return \DateTime 177 | */ 178 | public function getCreatedAt() 179 | { 180 | return $this->createdAt; 181 | } 182 | 183 | /** 184 | * Set updatedAt 185 | * 186 | * @param \DateTime $updatedAt 187 | * 188 | * @return Banner 189 | */ 190 | public function setUpdatedAt($updatedAt) 191 | { 192 | $this->updatedAt = $updatedAt; 193 | 194 | 195 | } 196 | 197 | /** 198 | * Get updatedAt 199 | * 200 | * @return \DateTime 201 | */ 202 | public function getUpdatedAt() 203 | { 204 | return $this->updatedAt; 205 | } 206 | 207 | /** 208 | * Set weight 209 | * 210 | * @param integer $weight 211 | * 212 | * @return Banner 213 | */ 214 | public function setWeight($weight) 215 | { 216 | $this->weight = $weight; 217 | 218 | 219 | } 220 | 221 | /** 222 | * Get weight 223 | * 224 | * @return integer 225 | */ 226 | public function getWeight() 227 | { 228 | return $this->weight; 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /Controller/PostController.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | namespace Desarrolla2\Bundle\BlogBundle\Controller; 15 | 16 | use Desarrolla2\Bundle\BlogBundle\Entity\Comment; 17 | use Desarrolla2\Bundle\BlogBundle\Entity\Post; 18 | use Desarrolla2\Bundle\BlogBundle\Form\Model\CommentModel; 19 | use Desarrolla2\Bundle\BlogBundle\Form\Type\CommentType; 20 | use Desarrolla2\Bundle\BlogBundle\Model\PostStatus; 21 | use Doctrine\ORM\Query\QueryException; 22 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; 23 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 24 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; 25 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; 26 | use Symfony\Component\HttpFoundation\RedirectResponse; 27 | use Symfony\Component\HttpFoundation\Request; 28 | use Symfony\Component\HttpFoundation\Response; 29 | 30 | /** 31 | * PostController 32 | */ 33 | class PostController extends Controller 34 | { 35 | /** 36 | * @Route("/{page}", name="_blog_default", requirements={"page" = "\d{1,6}"}, defaults={"page" = "1" }) 37 | * @Method({"GET"}) 38 | * @Template() 39 | * 40 | * @param int $page 41 | * 42 | * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException 43 | * @return array 44 | */ 45 | public function indexAction($page) 46 | { 47 | $paginator = $this->get('knp_paginator'); 48 | $query = $this->getDoctrine()->getManager() 49 | ->getRepository('BlogBundle:Post')->getQueryForGet(); 50 | 51 | try { 52 | $pagination = $paginator->paginate( 53 | $query, 54 | $page, 55 | $this->container->getParameter('blog.items') 56 | ); 57 | } catch (QueryException $e) { 58 | throw $this->createNotFoundException('Page not found'); 59 | } 60 | 61 | return [ 62 | 'page' => $page, 63 | 'pagination' => $pagination, 64 | 'title' => $this->container->getParameter('blog.title'), 65 | 'description' => $this->container->getParameter('blog.description'), 66 | ]; 67 | } 68 | 69 | /** 70 | * @Route("/post/{slug}" , name="_blog_view", requirements={"slug" = "[\w\d\-]+"}) 71 | * @Method({"GET"}) 72 | * @Template() 73 | * 74 | * @param string $slug 75 | * 76 | * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException 77 | * @return array|\Symfony\Component\HttpFoundation\RedirectResponse 78 | */ 79 | public function viewAction($slug) 80 | { 81 | $em = $this->getDoctrine()->getManager(); 82 | $post = $em->getRepository('BlogBundle:Post')->findOneBySlug($slug); 83 | 84 | if (!$post) { 85 | throw $this->createNotFoundException('The post does not exist'); 86 | } 87 | if ($post->getStatus() != PostStatus::PUBLISHED) { 88 | return new RedirectResponse($this->generateUrl('_blog_default'), 302); 89 | } 90 | 91 | /* 92 | $comments = $this->getDoctrine()->getManager() 93 | ->getRepository('BlogBundle:Comment')->getForPost($post); 94 | 95 | $form = $this->createForm(new CommentType(), new CommentModel($this->createCommentForPost($post))); 96 | */ 97 | 98 | return [ 99 | 'post' => $post, 100 | /*'comments' => $comments, 101 | 'form' => $form->createView(),*/ 102 | ]; 103 | } 104 | 105 | /** 106 | * 107 | * @Route("/view/post/{slug}" , name="_blog_post_view", requirements={"slug" = "[\w\d\-]+"}) 108 | * @Method({"POST"}) 109 | * 110 | * @param Request $request 111 | * 112 | * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException 113 | * @return Response 114 | */ 115 | public function postViewAction(Request $request) 116 | { 117 | $post = $this->getDoctrine()->getManager() 118 | ->getRepository('BlogBundle:Post')->getOneBySlug($request->get('slug', false)); 119 | if (!$post) { 120 | throw $this->createNotFoundException('The post does not exist'); 121 | } 122 | 123 | $this->getDoctrine()->getManager() 124 | ->getRepository('BlogBundle:PostView') 125 | ->add($post); 126 | 127 | return new Response(); 128 | } 129 | 130 | /** 131 | * @param \Desarrolla2\Bundle\BlogBundle\Entity\Post $post 132 | * 133 | * @return \Desarrolla2\Bundle\BlogBundle\Entity\Comment 134 | */ 135 | protected function createCommentForPost(Post $post) 136 | { 137 | $comment = new Comment(); 138 | $comment->setPost($post); 139 | 140 | return $comment; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /Resources/doc/installation/index.md: -------------------------------------------------------------------------------- 1 | # Bundle Installation 2 | 3 | ## Prerequisites 4 | 5 | This version of the bundle requires Symfony 2.3. 6 | 7 | // PUT HERE RESUME LIST 8 | 9 | ## Install Symfony 10 | 11 | If you are starting a new project you need install symfony standard, if you already 12 | have a symfony project go to next step. 13 | 14 | If you arent install symfony yet you need to read symfony install 15 | [documentation](http://symfony.com/doc/current/book/installation.html) 16 | 17 | ## Install the bundle 18 | 19 | Add to your `/composer.json` file : 20 | 21 | ``` json 22 | "require": { 23 | ... 24 | "desarrolla2/blog-bundle": "dev-master" 25 | }, 26 | ```` 27 | 28 | *If you are in production environment, maybe you want to fix version.* 29 | 30 | run composer update 31 | 32 | ``` bash 33 | $ composer update --no-custom-installers --no-scripts --verbose 34 | ``` 35 | 36 | ## Enable the Bundle 37 | 38 | Enable the blog bundle in your AppKernel, additionally you need to enable KnpPaginatorBundle. 39 | 40 | ``` php 41 |