Added basic blog functionality

Signed-off-by: Gergely Polonkai (W00d5t0ck) <polesz@w00d5t0ck.info>
This commit is contained in:
Gergely Polonkai (W00d5t0ck) 2012-09-04 13:09:32 +02:00
parent ea325aab7f
commit 5bcd9f079b
17 changed files with 412 additions and 21 deletions

View File

@ -20,7 +20,9 @@ class AppKernel extends Kernel
new JMS\AopBundle\JMSAopBundle(),
new JMS\DiExtraBundle\JMSDiExtraBundle($this),
new JMS\SecurityExtraBundle\JMSSecurityExtraBundle(),
new Io\TcpdfBundle\IoTcpdfBundle(),
new Io\TcpdfBundle\IoTcpdfBundle(),
new Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle(),
new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle(),
new GergelyPolonkai\FrontBundle\GergelyPolonkaiFrontBundle(),
new GergelyPolonkai\GeshiBundle\GergelyPolonkaiGeshiBundle(),
);

View File

@ -0,0 +1,32 @@
<?php
namespace Application\Migrations;
use Doctrine\DBAL\Migrations\AbstractMigration,
Doctrine\DBAL\Schema\Schema;
/**
* Auto-generated Migration: Please modify to your need!
*/
class Version20120904115727 extends AbstractMigration
{
public function up(Schema $schema)
{
// this up() migration is autogenerated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql");
$this->addSql("CREATE TABLE users (id INT AUTO_INCREMENT NOT NULL, username VARCHAR(50) NOT NULL, name VARCHAR(100) NOT NULL, UNIQUE INDEX UNIQ_1483A5E9F85E0677 (username), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE = InnoDB");
$this->addSql("CREATE TABLE blog_posts (id INT AUTO_INCREMENT NOT NULL, user_id INT NOT NULL, title VARCHAR(100) NOT NULL, slug VARCHAR(100) NOT NULL, content LONGTEXT NOT NULL, created_at DATETIME NOT NULL, INDEX IDX_78B2F932A76ED395 (user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE = InnoDB");
$this->addSql("ALTER TABLE blog_posts ADD CONSTRAINT FK_78B2F932A76ED395 FOREIGN KEY (user_id) REFERENCES users (id)");
}
public function down(Schema $schema)
{
// this down() migration is autogenerated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql");
$this->addSql("ALTER TABLE blog_posts DROP FOREIGN KEY FK_78B2F932A76ED395");
$this->addSql("DROP TABLE users");
$this->addSql("DROP TABLE blog_posts");
}
}

View File

@ -57,3 +57,15 @@ swiftmailer:
username: %mailer_user%
password: %mailer_password%
spool: { type: memory }
jms_di_extra:
locations:
all_bundles: false
bundles: [ GergelyPolonkaiFrontBundle ]
stof_doctrine_extensions:
default_locale: en_US
orm:
default:
sluggable: true
timestampable: true

View File

@ -2,9 +2,9 @@ parameters:
database_driver: pdo_mysql
database_host: localhost
database_port: ~
database_name: symfony
database_user: root
database_password: ~
database_name: gergelypolonkai
database_user: gergelypolonkai
database_password: the8dooM
mailer_transport: smtp
mailer_host: localhost
@ -12,4 +12,4 @@ parameters:
mailer_password: ~
locale: en
secret: ThisTokenIsNotSoSecretChangeIt
secret: rie5chooqu8oche5ha6Keidop3ahxoob

View File

@ -25,6 +25,8 @@
"jms/security-extra-bundle": "1.2.*",
"jms/di-extra-bundle": "1.1.*",
"easybook/geshi": "dev-master",
"stof/doctrine-extensions-bundle": "dev-master",
"doctrine/doctrine-migrations-bundle": "dev-master",
"gergelypolonkai/tcpdfbundle": "dev-master"
},
"scripts": {

View File

@ -0,0 +1,41 @@
<?php
namespace GergelyPolonkai\FrontBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use GergelyPolonkai\FrontBundle\Entity\Post;
/**
* Description of BlogController
*
* @author polonkai.gergely
*/
class BlogController extends Controller
{
/**
* @Route("/blog/{year}/{month}/{day}/{slug}.html", name="GergelyPolonkaiFront_blogViewPost")
* @Template
*/
public function viewPostAction($year, $month, $day, $slug)
{
$date = new \DateTime();
$date->setDate($year, $month, $day);
$date->setTime(0, 0, 0);
$date2 = new \DateTime();
$date2->setDate($year, $month, $day);
$date2->setTime(0, 0, 0);
$date2->add(new \DateInterval('P1D'));
$query = $this->getDoctrine()->getEntityManager()->createQuery("SELECT p FROM GergelyPolonkaiFrontBundle:Post p WHERE p.slug = :slug AND p.createdAt BETWEEN :date1 AND :date2");
$query->setParameter(':slug', $slug);
$query->setParameter(':date1', $date);
$query->setParameter(':date2', $date2);
$post = $query->getOneOrNullResult();
return array(
'post' => $post,
);
}
}

View File

@ -17,7 +17,13 @@ class DefaultController extends Controller
*/
public function indexAction()
{
return array();
$query = $this->getDoctrine()->getEntityManager()->createQuery("SELECT p FROM GergelyPolonkaiFrontBundle:Post p ORDER BY p.createdAt DESC");
$query->setMaxResults(4);
$posts = $query->getResult();
return array(
'posts' => $posts,
);
}
/**
@ -30,7 +36,7 @@ class DefaultController extends Controller
}
/**
* @param string $_format
* @param string $_format
*
* @Route("/resume.{_format}", name="GergelyPolonkaiFrontBundle_resume")
* @Template

View File

@ -23,7 +23,6 @@ class Configuration implements ConfigurationInterface
// Here you should define the parameters that are allowed to
// configure your bundle. See the documentation linked above for
// more information on that topic.
return $treeBuilder;
}
}

View File

@ -0,0 +1,163 @@
<?php
namespace GergelyPolonkai\FrontBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as GedmoORM;
/**
* Description of Post
*
* @author polonkai.gergely
*
* @ORM\Entity
* @ORM\Table(name="blog_posts")
*/
class Post
{
/**
* @var integer $id
*
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
* @ORM\Column(type="integer")
*/
private $id;
/**
* @var GergelyPolonkai\FrontBundle\Entity\User $user
*
* @ORM\ManyToOne(targetEntity="User")
* @ORM\JoinColumn(nullable=false)
*/
private $user;
/**
* @var string $title
*
* @ORM\Column(type="string", length=100)
*/
private $title;
/**
* @var string $slug
*
* @GedmoORM\Slug(fields={"title"})
* @ORM\Column(type="string", length=100)
*/
private $slug;
/**
* @var string $content
*
* @ORM\Column(type="text", nullable=false)
*/
private $content;
/**
* @var DateTime $createdAt
*
* @GedmoORM\Timestampable(on="create")
* @ORM\Column(type="datetime", nullable=false, name="created_at")
*/
private $createdAt;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set title
*
* @param string $title
* @return Post
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get title
*
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Get slug
*
* @return string
*/
public function getSlug()
{
return $this->slug;
}
/**
* Set user
*
* @param GergelyPolonkai\FrontBundle\Entity\User $user
* @return Post
*/
public function setUser(\GergelyPolonkai\FrontBundle\Entity\User $user)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* @return GergelyPolonkai\FrontBundle\Entity\User
*/
public function getUser()
{
return $this->user;
}
/**
* Set content
*
* @param string $content
* @return Post
*/
public function setContent($content)
{
$this->content = $content;
return $this;
}
/**
* Get content
*
* @return string
*/
public function getContent()
{
return $this->content;
}
/**
* Get createdAt
*
* @return \DateTime
*/
public function getCreatedAt()
{
return $this->createdAt;
}
}

View File

@ -0,0 +1,88 @@
<?php
namespace GergelyPolonkai\FrontBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Description of User
*
* @author polonkai.gergely
*
* @ORM\Entity
* @ORM\Table(name="users")
*/
class User
{
/**
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=50, unique=true)
*/
private $username;
/**
* @ORM\Column(type="string", length=100)
*/
private $name;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set username
*
* @param string $username
* @return User
*/
public function setUsername($username)
{
$this->username = $username;
return $this;
}
/**
* Get username
*
* @return string
*/
public function getUsername()
{
return $this->username;
}
/**
* Set name
*
* @param string $name
* @return User
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
}

View File

@ -0,0 +1,6 @@
{% extends 'GergelyPolonkaiFrontBundle:Default:front_base.html.twig' %}
{% block content %}
<h3>{{ post.title }}</h3>
<p class="article-date">{{ post.createdAt|date('m-d-Y :: H:i') }} by {{ post.user.name }}</p>
{{ post.content|raw }}
{% endblock content %}

View File

@ -42,4 +42,3 @@
</script>
</body>
</html>

View File

@ -1,12 +1,9 @@
{% extends 'GergelyPolonkaiFrontBundle:Default:front_base.html.twig' %}
{% block content %}
<h3>Upgrades requiring a reboot on Linux? At last!</h3>
<p class="article-date">22 June, 2012 :: 22:04 by Gergely Polonkai</p>
<p>I've recently received an article on Google+ about Fedora's new idea: package upgrades that require a reboot. The article said that Linux guys have lost their primary adoo: "Haha! I don't have to reboot my system to install system upgrades!" My answer was always this: "You should..."</p>
<p>I think this can be a great idea if distros implement it well. PackageKit was a good first step on this road. That software could easily solve such an issue. However, it is sooo easy to do it wrong. The kernel, of course, can not be upgraded online (or could it be? I have some theories on this subject, wonder if it can be implemented...), but other packages are much different. From the users' point of view the best would be if the packages would be upgraded in the background seemlessly. E.g. PackageKit should check if the given executable is running. If not, it should upgrade it, while notifying the user like "hey dude, don't start Anjuta now, I'm upgrading it!", or simply denying to start it. Libraries are a bit different, as PackageKit should check if any running executables are using the library. Meanwhile, PK should also keep a notification somewhere telling the users that some packages could be upgraded, but without stopping this-and-that, it can not be done.</p>
<p>I know these things are easier said than done. But I think (a) users should tell such ideas to the developers and (b) developers (mostly large companies, like Microsoft or Apple) should listen to them, and at least think of these ideas. Some users are not as stupid as they think...</p>
<h3>Wordpress madness</h3>
<p class="article-date">14 June, 2012 :: 08:40 by Gergely Polonkai</p>
<p>I'm a bit fed up that I had to install <a href="http://www.mysql.com/">MySQL</a> on my server to have <a href="http://wordpress.org/">Wordpress</a> working, so I've Googled a bit to find a solution for my pain. I found this: <a href="http://codex.wordpress.org/Using_Alternative_Databases">http://codex.wordpress.org/Using_Alternative_Databases</a>. I don't know when this post was written, but I think it's a bit out of date. I mean come on, PDO is the part of PHP for ages now, and they say adding a DBAL to the dependencies would be a project as large as (or larger than) WP itself. Well, yes, but PHP is already a dependency, isn't it? Remove it guys, it's too large!</p>
<p>Okay, to be serious... Having a heavily MySQL dependent codebase is a bad thing in my opinion, and changing it is no easy task. But once it is done, it would be a child's play to keep it up to date, and to port WP to other database backends. And it would be more than enough to call it 4.0, and raising version numbers fast is a must nowadays (right, Firefox and Linux Kernel guys?)</p>
{% for post in posts %}
<h3><a href="{{ path('GergelyPolonkaiFront_blogViewPost', {year: post.createdAt|date('Y'), month: post.createdAt|date('m'), day: post.createdAt|date('d'), slug: post.slug}) }}">{{ post.title }}</a></h3>
<p class="article-date">{{ post.createdAt|date('m-d-Y :: H:i') }} by {{ post.user.name }}</p>
{{ post.content|raw }}
{% endfor %}
{% endblock content %}

View File

@ -0,0 +1,43 @@
<?php
namespace GergelyPolonkai\FrontBundle\Service;
use JMS\DiExtraBundle\Annotation as DI;
/**
* Description of Slugifier
*
* @author polonkai.gergely
*
* @DI\Service("slugifier")
*/
class Slugifier
{
public function slugify($string)
{
$string = strtolower(
preg_replace(
'/^-+/',
'',
preg_replace(
'/-+$/',
'',
preg_replace(
'/[^a-z]+/i',
'-',
preg_replace(
'/([a-z])[":\']/i',
'\1',
iconv(
'UTF-8',
'ASCII//TRANSLIT',
$string
)
)
)
)
)
);
return $string;
}
}

View File

@ -23,7 +23,6 @@ class Configuration implements ConfigurationInterface
// Here you should define the parameters that are allowed to
// configure your bundle. See the documentation linked above for
// more information on that topic.
return $treeBuilder;
}
}

View File

@ -5,4 +5,4 @@ services:
gergely_polonkai_geshi.geshi_highlighter:
class: %gergely_polonkai_geshi.geshi_highlighter.class%
tags:
- { name: 'twig.extension' }
- { name: 'twig.extension' }

View File

@ -36,10 +36,12 @@ class GeshiHighlight extends \Twig_Extension
$this->geshi->enable_line_numbers(GESHI_NORMAL_LINE_NUMBERS);
$this->geshi->enable_keyword_links(false);
$this->geshi->enable_classes();
return $this->geshi->parse_code();
}
public function getName() {
public function getName()
{
return 'geshi_highlighter';
}
}