Getting started with KdrmklabsTicketBundle in Symfony2.
This bundle allows you to integrate in your Symfony2 project a basic system of customer support by tickets. You can create, edit and respond tickets instantly after installing this bundle ., (*1)
Needs a minimum configuration and the whole procedure is very simple., (*2)
Installation.
I. Installing the bundle in two different ways.
a) Automatically.
You can install the last version of this bundle with composer running the command from your command line:, (*3)
$ composer require kdrmklabs/ticket-bundle
b) By composer.json .
Or you can install this bundle by adding next code line to your project in the composer.json file and after update it with the command composer update
, (*4)
file: /composer.json, (*5)
{
"require": {
"kdrmklabs/ticket-bundle": "dev-master",
}
}
Now, update the bundle with composer:, (*6)
$ composer update kdrmklabs/ticket-bundle
II. Enable and register the Bundle in the AppKernel
// file: app/AppKernel.php
public function registerBundles()
{
$bundles = array(
// ...
new Kdrmklabs\Bundle\TicketBundle\KdrmklabsTicketBundle(),
// ...
// Your application bundles
);
}
III. Install Gedmon Doctrine2 extensions
Requirements:
Check if gedmo doctrine extensions are downloaded., (*7)
/vendor/gedmo/doctrine-extensions/lib/Gedmo
, (*8)
if not download it:, (*9)
a. Add dependency to composer.json, (*10)
file: /composer.json, (*11)
{
"require": {
....
"gedmo/doctrine-extensions": "dev-master"
}
}
b. Update with composer in the command line:, (*12)
$ php composer.phar update gedmo/doctrine-extensions
III.I. Create a DoctrineExtensionListener, (*13)
// file: src/AppBundle/Listener/DoctrineExtensionListener.php
namespace AppBundle\Listener;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class DoctrineExtensionListener implements ContainerAwareInterface
{
/**
* @var ContainerInterface
*/
protected $container;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
public function onLateKernelRequest(GetResponseEvent $event)
{
$translatable = $this->container->get('gedmo.listener.translatable');
$translatable->setTranslatableLocale($event->getRequest()->getLocale());
}
public function onKernelRequest(GetResponseEvent $event)
{
$securityContext = $this->container->get('security.context', ContainerInterface::NULL_ON_INVALID_REFERENCE);
if (null !== $securityContext && null !== $securityContext->getToken() && $securityContext->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
$loggable = $this->container->get('gedmo.listener.loggable');
$loggable->setUsername($securityContext->getToken()->getUsername());
}
}
}
III.II. Create file doctrine_extensions.yml
and locate it in your app/config
directory, (*14)
# file: app/config/doctrine_extensions.yml
doctrine:
orm:
auto_generate_proxy_classes: %kernel.debug%
auto_mapping: true
# only these lines are added additionally
mappings:
translatable:
type: annotation
alias: Gedmo
prefix: Gedmo\Translatable\Entity
# make sure vendor library location is correct
dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Translatable/Entity"
# services to handle doctrine extensions
# import it in config.yml
services:
# KernelRequest listener
extension.listener:
# change this to your DoctrineExtensionListener namespace
class: AppBundle\Listener\DoctrineExtensionListener
calls:
- [ setContainer, [ @service_container ] ]
tags:
# translatable sets locale after router processing
- { name: kernel.event_listener, event: kernel.request, method: onLateKernelRequest, priority: -10 }
# loggable hooks user username if one is in security context
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
# Doctrine Extension listeners to handle behaviors
gedmo.listener.tree:
class: Gedmo\Tree\TreeListener
tags:
- { name: doctrine.event_subscriber, connection: default }
calls:
- [ setAnnotationReader, [ @annotation_reader ] ]
gedmo.listener.translatable:
class: Gedmo\Translatable\TranslatableListener
tags:
- { name: doctrine.event_subscriber, connection: default }
calls:
- [ setAnnotationReader, [ @annotation_reader ] ]
- [ setDefaultLocale, [ %locale% ] ]
- [ setTranslatableLocale, [ %locale% ]]
- [ setTranslationFallback, [ false ] ]
gedmo.listener.timestampable:
class: Gedmo\Timestampable\TimestampableListener
tags:
- { name: doctrine.event_subscriber, connection: default }
calls:
- [ setAnnotationReader, [ @annotation_reader ] ]
gedmo.listener.sluggable:
class: Gedmo\Sluggable\SluggableListener
tags:
- { name: doctrine.event_subscriber, connection: default }
calls:
- [ setAnnotationReader, [ @annotation_reader ] ]
gedmo.listener.sortable:
class: Gedmo\Sortable\SortableListener
tags:
- { name: doctrine.event_subscriber, connection: default }
calls:
- [ setAnnotationReader, [ @annotation_reader ] ]
gedmo.listener.loggable:
class: Gedmo\Loggable\LoggableListener
tags:
- { name: doctrine.event_subscriber, connection: default }
calls:
- [ setAnnotationReader, [ @annotation_reader ] ]
Don't forget change 'AppBundle\Listener\DoctrineExtensionListener' to your DoctrineExtensionListener namespace., (*15)
Finally, Do not forget to import doctrine_extensions.yml in your app/config/config.yml :, (*16)
# file: app/config/config.yml
imports:
- { resource: parameters.yml }
- { resource: security.yml }
- { resource: doctrine_extensions.yml }
More details of Gedmo Doctrine2 extensions in Symfony2: https://github.com/Atlantic18/DoctrineExtensions/blob/master/doc/symfony2.md, (*17)
More details: https://github.com/KnpLabs/KnpPaginatorBundle#configuration-example, (*18)
V.I. Add kdrmklabs_ticket
configuration to you config.yml, (*19)
# file: app/config/config.yml
kdrmklabs_ticket:
user_class: AppBundle\Entity\User
user_primay_key: id
Where user_primay_key
is the name of your primary key in the user table., (*20)
V.II. Add resolve_target_entities
to your doctrine configuration, (*21)
# file: app/config/config.yml
# Doctrine Configuration
doctrine:
orm:
auto_mapping: true
resolve_target_entities:
Kdrmklabs\Bundle\TicketBundle\Model\UserInterface: AppBundle\Entity\User
Do not forget change 'AppBundle\Entity\User' to your User Entity namespace, (*22)
More details about resolve_target_entities: http://symfony.com/doc/current/cookbook/doctrine/resolve_target_entity.html, (*23)
V.III. Implements Kdrmklabs\Bundle\TicketBundle\Model\UserInterface
from your User entity., (*24)
// file:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* User
*
* @ORM\Table(name="user")
* @ORM\Entity
*/
class User implements \Kdrmklabs\Bundle\TicketBundle\Model\UserInterface
{
public function getId(){
}
}
VII. Finally, create database tables and update the schema
Update your database schema with the command:, (*25)
$ php app/console doctrine:schema:update --force
Now, you need to populete the database tables kdrmklabs_ticket_status
and kdrmklabs_ticket_category
, (*26)
Example of SQL to populete the tables:, (*27)
INSERT INTO `kdrmklabs_ticket_category` (`id`, `name`, `active`) VALUES ('1', 'Billing', '1');
INSERT INTO `kdrmklabs_ticket_category` (`id`, `name`, `active`) VALUES ('2', 'Cancellations and refunds', '1');
INSERT INTO `kdrmklabs_ticket_category` (`id`, `name`, `active`) VALUES ('3', 'Report a scam or offer false', '1');
INSERT INTO `kdrmklabs_ticket_category` (`id`, `name`, `active`) VALUES ('4', 'Report inappropriate or illegal content', '1');
INSERT INTO `kdrmklabs_ticket_category` (`id`, `name`, `active`) VALUES ('5', 'Security Center and user protection', '1');
INSERT INTO `kdrmklabs_ticket_status` (`id`, `name`, `active`) VALUES ('1', 'Pending', '1');
INSERT INTO `kdrmklabs_ticket_status` (`id`, `name`, `active`) VALUES ('2', 'Invalid', '1');
INSERT INTO `kdrmklabs_ticket_status` (`id`, `name`, `active`) VALUES ('3', 'Solved', '1');
Statuses
You can add to the database table kdrmklabs_ticket_status
all states that you want to use to identify the tickets, for example:, (*28)
, (*29)
Categories
You can add to the database table kdrmklabs_ticket_category
all categories that you want to use to classify the tickets, for example:, (*30)
, (*31)
Available services
Examples of implementation of kdrmklabs_ticket.ticket_service from a controller, (*32)
Create a ticket
/**
* @Route("/create")
*/
public function createAction() {
$kdrmklabs_ticket_service = $this->get('kdrmklabs_ticket.ticket_service');
$ticket = $kdrmklabs_ticket_service->createTicket("message", "subject", 1, 1, 1);
return $this->redirectToRoute('kdrmklabs_ticket_show', array('id' => $ticket->getId()));
}
createTicket -> Return a Kdrmklabs\Bundle\TicketBundle\Entity\Ticket
object, (*33)
Description, (*34)
createTicket(
string $initial_message,
string $subject,
int|Kdrmklabs\Bundle\TicketBundle\Model\UserInterface|AppBundle\Entity\User $user,
int|Kdrmklabs\Bundle\TicketBundle\Entity\TicketCategory $category,
int|Kdrmklabs\Bundle\TicketBundle\Entity\TicketStatus $status
[, int $dateAdded])
Delete
/**
* @Route("/delete/{id}")
*/
public function deleteAction($id) {
$kdrmklabs_ticket_service = $this->get('kdrmklabs_ticket.ticket_service');
$kdrmklabs_ticket_service->deleteTicket($id);
return $this->redirectToRoute('kdrmklabs_ticket_index');
}
deleteTicket -> Return boolean, (*35)
Description:, (*36)
deleteTicket( int|Kdrmklabs\Bundle\TicketBundle\Entity\Ticket $ticket)
Reply
/**
* @Route("/reply/{id}")
*/
public function replyAction($id) {
$kdrmklabs_ticket_service = $this->get('kdrmklabs_ticket.ticket_service');
$ticket = $kdrmklabs_ticket_service->replyTicket($id, 1, "reply");
return $this->redirectToRoute('kdrmklabs_ticket_show', array('id' => $ticket->getId()));
}
replyTicket -> Return a Kdrmklabs\Bundle\TicketBundle\Entity\Ticket
object, (*37)
Description:, (*38)
replyTicket(
int|Kdrmklabs\Bundle\TicketBundle\Entity\Ticket $ticket,
int|Kdrmklabs\Bundle\TicketBundle\Model\UserInterface|AppBundle\Entity\User $user,
string $message
[, int $dateAdded])
get a ticket
/**
* @Route("/show/{id}", name="kdrmklabs_ticket_show")
* @Template()
*/
public function showAction($id) {
$kdrmklabs_ticket_service = $this->get('kdrmklabs_ticket.ticket_service');
$ticket = $kdrmklabs_ticket_service->getTicket($id);
return array('ticket' => $ticket);
}
getTicket -> Return a Kdrmklabs\Bundle\TicketBundle\Entity\Ticket
object, (*39)
Description:, (*40)
getTicket( int|string $id_ticket )
list tickets
/**
* @Route("/", name="kdrmklabs_ticket_index")
* @Template()
*/
public function indexAction(Request $request) {
$kdrmklabs_ticket_service = $this->get('kdrmklabs_ticket.ticket_service');
$query = $kdrmklabs_ticket_service->getTickets(); // get all tickets
$paginator = $this->get('knp_paginator');
$pagination = $paginator->paginate(
$query->getQuery(),
$request->query->get('page', 1),
10
);
return array('pagination' => $pagination);
}
getTickets -> return DQL QUERY, (*41)
Description:, (*42)
getTickets(
[ int|Kdrmklabs\Bundle\TicketBundle\Model\UserInterface|AppBundle\Entity\User $author,
int|Kdrmklabs\Bundle\TicketBundle\Entity\TicketCategory $category,
int|Kdrmklabs\Bundle\TicketBundle\Entity\TicketStatus $status
int $from_datetime,
int $to_datetime,
boolean $closed ]
)
close ticket
/**
* @Route("/close/{id}")
*/
public function closeAction($id){
$kdrmklabs_ticket_service = $this->get('kdrmklabs_ticket.ticket_service');
$kdrmklabs_ticket_service->closeTicket($id);
return $this->redirectToRoute('kdrmklabs_ticket_index');
}
closeTicket -> Return boolean, (*43)
Description:, (*44)
closeTicket( id|string $id_ticket )
User repository from UserInterface
// access to UserInterface from controller
$this->get('kdrmklabs_ticket.user_repository')->find($id_user);
Example complete of Controller implementation
namespace Kdrmklabs\Bundle\TicketBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\Request;
class DefaultController extends Controller {
/**
* @Route("/", name="kdrmklabs_ticket_index")
* @Template()
*/
public function indexAction(Request $request) {
$kdrmklabs_ticket_service = $this->get('kdrmklabs_ticket.ticket_service');
$query = $kdrmklabs_ticket_service->getTickets();
$paginator = $this->get('knp_paginator');
$pagination = $paginator->paginate(
$query->getQuery(),
$request->query->get('page', 1),
10
);
return array('pagination' => $pagination);
}
/**
* @Route("/create")
*/
public function createAction() {
$id_user = 1;
$id_category = 1;
$id_status = 1;
$kdrmklabs_ticket_service = $this->get('kdrmklabs_ticket.ticket_service');
$ticket = $kdrmklabs_ticket_service->createTicket("message", "subject", $id_user, $id_category, $id_status);
return $this->redirectToRoute('kdrmklabs_ticket_show', array('id' => $ticket->getId()));
}
/**
* @Route("/show/{id}", name="kdrmklabs_ticket_show")
* @Template()
*/
public function showAction($id) {
$kdrmklabs_ticket_service = $this->get('kdrmklabs_ticket.ticket_service');
$ticket = $kdrmklabs_ticket_service->getTicket($id);
return array('ticket' => $ticket);
}
/**
* @Route("/reply/{id}")
*/
public function replyAction($id) {
$id_user = 1;
$kdrmklabs_ticket_service = $this->get('kdrmklabs_ticket.ticket_service');
$ticket = $kdrmklabs_ticket_service->replyTicket($id, $id_user, "reply");
return $this->redirectToRoute('kdrmklabs_ticket_show', array('id' => $ticket->getId()));
}
/**
* @Route("/delete/{id}")
*/
public function deleteAction($id) {
$kdrmklabs_ticket_service = $this->get('kdrmklabs_ticket.ticket_service');
$kdrmklabs_ticket_service->deleteTicket($id);
return $this->redirectToRoute('kdrmklabs_ticket_index');
}
/**
* @Route("/close/{id}")
*/
public function closeAction($id){
$kdrmklabs_ticket_service = $this->get('kdrmklabs_ticket.ticket_service');
$kdrmklabs_ticket_service->closeTicket($id);
return $this->redirectToRoute('kdrmklabs_ticket_index');
}
}