Commit 1d11d2d8 authored by Hermann Mayer's avatar Hermann Mayer

Implemented Feature #19. A blog archiv service were implemented. Extended…

Implemented Feature #19. A blog archiv service were implemented. Extended service controller features, so they can now work properly with real routing parameters.
parent 8e161bfe
......@@ -500,9 +500,9 @@ class SymfonyRequirements extends RequirementCollection
$pcreVersion = defined('PCRE_VERSION') ? (float) PCRE_VERSION : null;
$this->addRequirement(
null !== $pcreVersion && $pcreVersion > 8.0,
sprintf('PCRE extension must be available and at least 8.0 (%s installed)', $pcreVersion ? $pcreVersion : 'not'),
'Upgrade your <strong>PCRE</strong> extension (8.0+).'
null !== $pcreVersion,
'PCRE extension must be available',
'Install the <strong>PCRE</strong> extension (version 8.0+).'
);
/* optional recommendations follow */
......@@ -531,6 +531,14 @@ class SymfonyRequirements extends RequirementCollection
'Your project might not work properly due to the PHP bug #61453 ("Cannot dump definitions which have method calls"). Install PHP 5.4.1 or newer.'
);
if (null !== $pcreVersion) {
$this->addRecommendation(
$pcreVersion >= 8.0,
sprintf('PCRE extension should be at least version 8.0 (%s installed)', $pcreVersion),
'<strong>PCRE 8.0+</strong> is preconfigured in PHP since 5.3.2 but you are using an outdated version of it. Symfony probably works anyway but it is recommended to upgrade your PCRE extension.'
);
}
$this->addRecommendation(
class_exists('DomDocument'),
'PHP-XML module should be installed',
......
......@@ -49,6 +49,11 @@ doctrine:
orm:
auto_generate_proxy_classes: %kernel.debug%
auto_mapping: true
dql:
datetime_functions:
month: DoctrineExtensions\Query\Mysql\Month
year: DoctrineExtensions\Query\Mysql\Year
day: DoctrineExtensions\Query\Mysql\Day
# Enable required doctrine extensions
stof_doctrine_extensions:
......
No preview for this file type
......@@ -26,9 +26,11 @@
"sensio/distribution-bundle": "2.1.*",
"sensio/framework-extra-bundle": "2.1.*",
"sensio/generator-bundle": "2.1.*",
"jms/security-extra-bundle": "1.2.*",
"jms/di-extra-bundle": "1.1.*",
"jms/serializer-bundle": "1.0.x-dev",
"jms/metadata": "1.1.1",
"jms/security-extra-bundle": "1.*",
"jms/di-extra-bundle": "dev-master",
"jms/serializer": "dev-master",
"jms/serializer-bundle": "dev-master",
"doctrine/doctrine-fixtures-bundle": "dev-master",
"doctrine/data-fixtures": "dev-master",
"knplabs/knp-markdown-bundle": "dev-master",
......@@ -41,7 +43,9 @@
"presta/sitemap-bundle": "dev-master",
"jity/tag-generator": "dev-master",
"nelmio/solarium-bundle": "1.0.x-dev",
"doctrine/doctrine-migrations-bundle": "dev-master"
"doctrine/doctrine-migrations-bundle": "dev-master",
"beberlei/DoctrineExtensions": "dev-master",
"phpcollection/phpcollection": "0.1.x-dev"
},
"scripts": {
"post-install-cmd": [
......
This diff is collapsed.
......@@ -33,13 +33,14 @@ class BlogController extends Controller
*
* Show an article.
*
* @param string $slug Slug of the article to show
* @param string $_format Response Format
* @param string $slug Slug of the article to show
* @param string $_format Response Format
* @param string $parameters Optional Service Parameter String
*
* @access public
* @return Response
*/
public function showAction($slug, $_format)
public function showAction($slug, $_format, $parameters)
{
// Get Entity Manager
$em = $this->getDoctrine()->getEntityManager();
......@@ -59,57 +60,21 @@ class BlogController extends Controller
);
}
// Return the rendered result
return $this->render(
'JityHomepageBundle:Blog:show_article.' . $_format . '.twig', array(
'article' => $article
));
}
/**
* sectionArchivAction
*
* Build an archiv-map of all articles for
* printing this as a Sidebar Section.
*
* @access public
* @return Response
*/
public function sectionArchivAction()
{
$em = $this->getDoctrine()->getManager();
// Use DQL because its more powerfull and only one query is needed
$query = $em->createQueryBuilder()
->select('a.createdAt')
->from('JityHomepageBundle:Article', 'a')
->getQuery();
$archivMap = array();
// The article is connected to a service, we detected
// the root of all evil so just jump over to the Default
// Controller to solve this task
if ($service = $article->getService()) {
// Map the archiv
foreach ($query->getArrayResult() as $entity) {
$date = $entity['createdAt'];
$year = $date->format('Y');
$month = $date->format('F');
if (array_key_exists($year, $archivMap) &&
array_key_exists($month, $archivMap[$year])) {
// We found a existing year/month combo -> increase counter
$archivMap[$year][$month]++;
} else {
// We found a new year/month combo -> set first entry
$archivMap[$year][$month] = 1;
}
return $this->forward('JityHomepageBundle:Default:showPage', array(
'service' => $service->getName(),
'parameters' => $parameters
));
}
// Return the rendered result
return $this->render(
'JityHomepageBundle:Blog:archiv_section.html.twig', array(
'map' => $archivMap,
'JityHomepageBundle:Blog:show_article.' . $_format . '.twig', array(
'article' => $article
));
}
......@@ -331,5 +296,56 @@ class BlogController extends Controller
'form_edit' => $form->createView(),
));
}
/**
* sectionArchivAction
*
* Build an archiv-map of all articles for
* printing this as a Sidebar Section.
*
* @access public
* @return Response
*/
public function sectionArchivAction()
{
$em = $this->getDoctrine()->getManager();
// Use DQL because its more powerfull and only one query is needed
$query = $em->createQueryBuilder()
->select('a.createdAt')
->from('JityHomepageBundle:Article', 'a')
->where('a.service is NULL')
->getQuery();
$archivMap = array();
// Map the archiv
foreach ($query->getArrayResult() as $entity) {
$date = $entity['createdAt'];
$year = $date->format('Y');
$month = $date->format('F');
$monthNumber = $date->format('m');
if (array_key_exists($year, $archivMap) &&
array_key_exists($monthNumber, $archivMap[$year])) {
// We found a existing year/month combo -> increase counter
$archivMap[$year][$monthNumber][$month]++;
} else {
// We found a new year/month combo -> set first entry
$archivMap[$year][$monthNumber][$month] = 1;
}
}
return $this->render(
'JityHomepageBundle:Blog:archiv_section.html.twig', array(
'map' => $archivMap,
'servicePage' => $this->get('jity_service.handler')
->getPageByService('blog-archiv')
));
}
}
......@@ -32,13 +32,14 @@ class DefaultController extends Controller
* Delegates the request to various content providers.
* (Eg. Article, Page, Service)
*
* @param string $slug Slug for an AbstractPage
* @param string $service Name of an Service
* @param string $slug Slug for an AbstractPage
* @param string $service Name of an Service
* @param string $parameters Optional Service Parameter String
*
* @access public
* @return Response
*/
public function showPageAction($slug = '', $service = '')
public function showPageAction($slug = '', $service = '', $parameters = '')
{
// Validate the request
if ((true === empty($slug)) && (true === empty($service))) {
......@@ -60,6 +61,8 @@ class DefaultController extends Controller
// Get service controller
$servController = $servHandler->getController($service);
$servController->setParameters($parameters);
$isServiceRequest = true;
}
}
......@@ -112,6 +115,7 @@ class DefaultController extends Controller
// Get service controller
$servOutput = $servHandler
->getController($service)
->setParameters($parameters)
->process();
}
}
......
......@@ -12,6 +12,7 @@
namespace Jity\HomepageBundle\DataFixtures\ORM;
use Jity\HomepageBundle\Entity\Page,
Jity\HomepageBundle\Entity\Article,
Doctrine\Common\Persistence\ObjectManager,
Doctrine\Common\DataFixtures\AbstractFixture,
Doctrine\Common\DataFixtures\OrderedFixtureInterface;
......@@ -40,8 +41,8 @@ class Load30PageData extends AbstractFixture implements OrderedFixtureInterface
public function load(ObjectManager $manager)
{
// Build Impress Page
$blog = new Page();
$blog
$blogDashboard = new Page();
$blogDashboard
->setTitle('Blog')
->setContent('Neue Artikel
--------
......@@ -50,7 +51,22 @@ class Load30PageData extends AbstractFixture implements OrderedFixtureInterface
->setSidebar($this->getReference('blog-sidebar'))
->setNavigation($this->getReference('default-navigation'))
->setAuthor($this->getReference('admin-user'))
->setService($this->getReference('blog-service'))
->setService($this->getReference('blog-dashboard-service'))
->setIcon('icon-pencil');
/*
* --------------------------------------------------------------------
*/
// Build Impress Page
$blogArchiv = new Article();
$blogArchiv
->setTitle('Archiv')
->setCategory($this->getReference('default-category'))
->setSidebar($this->getReference('blog-sidebar'))
->setNavigation($this->getReference('blog-navigation'))
->setAuthor($this->getReference('admin-user'))
->setService($this->getReference('blog-archiv-service'))
->setIcon('icon-pencil');
/*
......@@ -141,7 +157,8 @@ Administrator einzuloggen.
*/
// Save all Metadata
$manager->persist($blog);
$manager->persist($blogDashboard);
$manager->persist($blogArchiv);
$manager->persist($demo);
$manager->persist($impress);
$manager->persist($contact);
......@@ -150,7 +167,8 @@ Administrator einzuloggen.
// Flush to Database
$manager->flush();
$this->addReference('blog-page', $blog);
$this->addReference('blog-dashboard-page', $blogDashboard);
$this->addReference('blog-archiv-page', $blogArchiv);
$this->addReference('demo-page', $demo);
$this->addReference('impress-page', $impress);
$this->addReference('contact-page', $contact);
......
......@@ -12,6 +12,10 @@
namespace Jity\HomepageBundle\DependencyInjection\Service;
use Symfony\Component\DependencyInjection\ContainerInterface,
Symfony\Component\Routing\Matcher\UrlMatcher,
Symfony\Component\Routing\RequestContext,
Symfony\Component\Routing\Route,
Symfony\Component\Routing\RouteCollection,
JMS\DiExtraBundle\Annotation as DI;
/**
......@@ -66,6 +70,12 @@ abstract class AbstractService
*/
protected $container;
/**
* @var parameters
* @access protected
*/
protected $parameters;
/**
* __construct
......@@ -112,5 +122,69 @@ abstract class AbstractService
return array();
}
/**
* getParameterPattern
*
* Define the default Service Parameters which will be parsed.
*
* @access public
* @return void
*/
public function getParameterPattern()
{
return new RouteCollection();
}
/**
* setParameters
*
* Set the unparsed parameters which will be matched by
* the defined parameter patterns.
*
* @param string $parameters Unparsed Parameters
*
* @access public
* @return void
*/
public function setParameters($parameters)
{
// Try to match a parameter pattern defined by
// the service controller against
// the given parameters variable
try {
$matcher = new UrlMatcher(
$this->getParameterPattern(),
new RequestContext()
);
$matches = $matcher->match('/' . $parameters);
// We survived the ResourceNotFound exception
// so we can set our matched route parameters
$this->parameters = $matches;
} catch (\Exception $e) {
// Nothing matched
$this->parameters = false;
}
return $this;
}
/**
* getParameters
*
* Get the parameters which matched the defined parameter patterns.
*
* @access public
* @return array|false
*/
public function getParameters()
{
return $this->parameters;
}
}
<?php
/*
* This file is part of the Jity package.
*
* (c) Hermann Mayer <hermann.mayer92@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Jity\HomepageBundle\DependencyInjection\Service\Controller;
use Jity\HomepageBundle\DependencyInjection\Service\AbstractService,
Symfony\Bundle\FrameworkBundle\Controller\Controller,
JMS\DiExtraBundle\Annotation as DI,
Symfony\Component\HttpFoundation\Response,
Symfony\Component\Routing\Route,
Symfony\Component\Routing\RouteCollection;
/**
* BlogArchivController
*
* The Blog-Archiv Controller deliver the dashboard of a blog.
*
* @DI\Service("jity_service.controller.blog.archiv")
* @DI\Tag("jity_service.controller")
*
* @uses AbstractService
* @author Hermann Mayer <hermann.mayer92@gmail.com>
*/
class BlogArchivController extends AbstractService
{
/**
* getName
*
* Get the name of the service.
*
* @access public
* @return string
*/
public function getName()
{
return 'blog-archiv';
}
/**
* getTitle
*
* Get the title of the service.
*
* @access public
* @return string
*/
public function getTitle()
{
return 'Blog Archiv';
}
/**
* getDescription
*
* Get the description of the service.
*
* @access public
* @return string
*/
public function getDescription()
{
return 'Fügt die Archiv Funktionalität eines Blogs hinzu.';
}
/**
* getParameterPattern
*
* Define the default Service Parameters which will be parsed.
*
* @access public
* @return void
*/
public function getParameterPattern()
{
$routes = new RouteCollection();
$routes->add('service_blog_archiv', new Route(
'{year}/{month}',
array(),
array(
'year' => '\d+',
'month' => '^(0?[1-9]|1[0-2])$'
))
);
return $routes;
}
/**
* process
*
* Process the service functionality.
*
* @access public
* @return Response
*/
public function process()
{
// Get the matched parameters
$range = (object) $this->getParameters();
$em = $this->container->get('doctrine.orm.entity_manager');
// Use DQL because its more powerfull and only one query is needed
$query = $em->createQueryBuilder()
->select('a')
->from('JityHomepageBundle:Article', 'a')
->where('a.service is NULL')
->where('YEAR(a.createdAt) = :year')
->andWhere('MONTH(a.createdAt) = :month')
->getQuery()
->setParameter('year', $range->year)
->setParameter('month', $range->month);
return $this->container
->get('templating')
->render(
'JityHomepageBundle:Service:Blog/archiv.html.twig', array(
'year' => $range->year,
'month' => $range->month,
'entities' => $query->getResult()
));
}
}
......@@ -17,17 +17,17 @@ use Jity\HomepageBundle\DependencyInjection\Service\AbstractService,
Symfony\Component\HttpFoundation\Response;
/**
* BlogController
* BlogDashboardController
*
* The Blog Controller deliver the dashboard of a blog.
* The Blog-Dashboard Controller deliver the dashboard of a blog.
*
* @DI\Service("jity_service.controller.blog")
* @DI\Service("jity_service.controller.blog.dashboard")
* @DI\Tag("jity_service.controller")
*
* @uses AbstractService
* @author Hermann Mayer <hermann.mayer92@gmail.com>
*/
class BlogController extends AbstractService
class BlogDashboardController extends AbstractService
{
/**
* getName
......@@ -39,7 +39,7 @@ class BlogController extends AbstractService
*/
public function getName()
{
return 'blog';
return 'blog-dashboard';
}
/**
......@@ -84,16 +84,13 @@ class BlogController extends AbstractService
->getRepository('JityHomepageBundle:Article')
->findBy(array(), array('createdAt' => 'DESC'), 10);
foreach ($entities as $entity) {
foreach ($entities as $key => $entity) {
// Get only the first paragraph (all until first blank line)
$matches = '';
preg_match("/((.*|\n)*)\n[\s]/", $entity->getContent(), $matches);
// We dont want to show service articles
if ($entity->getService()) {
if (!empty($matches[0])) {
$entity->setContent(trim($matches[0]));
} else {
$entity->setContent(trim(substr($entity->getContent(), 0, 400)));
unset($entities[$key]);
continue;
}
}
......
......@@ -27,6 +27,29 @@ use Jity\HomepageBundle\DependencyInjection\Service\AbstractService,
class Handler
{
private $controller;
private $em;
private $serviceCache;
/**
* __construct
*
* Initalize a new Service Handler instance.
*
* @param mixed $em DI Injected Doctrine Entity Manager
*
* @DI\InjectParams({
* "em" = @DI\Inject("doctrine.orm.entity_manager")
* })
*
* @access public
* @return void
*/
public function __construct($em)
{
$this->em = $em;
$this->serviceCache = array();
}
/**
* addController
......@@ -102,5 +125,52 @@ class Handler
return $meta;
}
/**
* getPageByService
*
* Lookup a page for a specified service.
*
* @param string $name Name of the service to lookup
*
* @access public
* @return void
*/
public function getPageByService($name)
{
// The service seems not to be in cache
if (false === array_key_exists($name, $this->serviceCache)) {
// Try to find a valid service for the given name
$service = $this->em
->getRepository('JityHomepageBundle:Service')
->findOneByName($name);
// No service was found
if (!$service) {
// Save our useless try to prevent further useless tries
$this->serviceCache[$name] = false;
return false;
}
$page = $service->getPages()->first();
// No page is connected to this service
if (false === $page) {
// Save our useless try to prevent further useless tries
$this->serviceCache[$name] = false;
return false;
}
// Save service lookup in service cache
$this->serviceCache[$name] = $page;
}
return $this->serviceCache[$name];
}
}
......@@ -59,7 +59,7 @@ abstract class AbstractPage
protected $icon;
/**
* @ORM\Column(type="text")
* @ORM\Column(type="text", nullable=true)
*/
protected $content;
......@@ -601,7 +601,7 @@ abstract class AbstractPage
* Get the current (extended) type of the abstract base page.
*
* @access public
* @return void
* @return string
*/
public function getType()
{
......@@ -610,5 +610,30 @@ abstract class AbstractPage
// array in "stream" (needs to be stored in a var)
return current(array_reverse(explode('\\', get_called_class())));
}
/**
* getDescription
*