anilton.junior/ext-direct-bundle
composer require ghua/ext-direct-bundle
new Ext\DirectBundle\ExtDirectBundle() to AppKernel.php under $bundles.app/config/routing.yml:
ext_direct:
resource: "@ExtDirectBundle/Resources/config/routing.yml"
app/config/extdirect_routing.yml with basic routes:
getCustomers:
defaults: { _controller: AcmeDemoBundle:Demo:getCustomers, params: true }
reader: { root: root }
<script type="text/javascript" src="{{ url('ExtDirectBundle_api') }}"></script>
Ext.direct.Manager.addProvider(Ext.app.REMOTING_API);
Create a controller action returning raw data:
// src/Acme/DemoBundle/Controller/DemoController.php
public function getCustomersAction()
{
$data = $this->getDoctrine()
->getRepository('AcmeDemoBundle:Customer')
->findAll();
return $data;
}
Define an ExtJS model:
Ext.define('ACME.model.Customer', {
extend: 'Ext.data.Model',
fields: ['id', 'name', 'email'],
proxy: {
type: 'direct',
api: {
read: Actions.AcmeDemo_Demo.getCustomers
}
}
});
Define routes in extdirect_routing.yml:
getCountries:
defaults: { _controller: AcmeDemoBundle:Demo:getCountries }
reader: { root: 'data', successProperty: 'success' }
updateCustomer:
defaults: { _controller: AcmeDemoBundle:Demo:updateCustomer, params: true, form: true }
writer: { root: 'result' }
Use annotations in controllers:
use Ext\DirectBundle\Annotation\Route;
use Ext\DirectBundle\Annotation\Reader;
use Ext\DirectBundle\Annotation\Writer;
/**
* @Route(name="acmeTest", isWithParams=true)
* @Reader(root="data", successProperty="success")
* @Writer(root="result")
*/
public function testAction($_data) { ... }
// Controller
public function getRolesAction()
{
return $this->getDoctrine()
->getRepository('AcmeDemoBundle:Role')
->findAll();
}
ExtJS Model:
Ext.define('ACME.store.Role', {
extend: 'Ext.data.Store',
model: 'ACME.model.Role',
proxy: {
type: 'direct',
api: {
read: Actions.AcmeDemo_Demo.getRoles
}
}
});
// Controller
public function getCustomersAction($page = 1, $limit = 10)
{
$query = $this->getDoctrine()
->getRepository('AcmeDemoBundle:Customer')
->createQueryBuilder('c')
->getQuery()
->setHydrationMode(\Doctrine\ORM\Query::HYDRATE_ARRAY);
$paginator = $this->get('knp_paginator')->paginate($query, $page, $limit);
return $this->get('ext_direct')
->createResponse(new \Ext\DirectBundle\Response\KnpPaginator(), $paginator);
}
// Controller
public function createCustomerAction($_data)
{
$customer = new Customer();
$form = $this->createForm(CustomerType::class, $customer);
$form->bind($_data);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($customer);
$em->flush();
return $this->get('ext_direct')->createResponse()->setSuccess(true);
}
return $this->get('ext_direct')
->createResponse(new \Ext\DirectBundle\Response\FormError(), $form);
}
ExtJS Form:
Ext.define('ACME.view.CustomerForm', {
extend: 'Ext.form.Panel',
api: {
submit: Actions.AcmeDemo_Demo.createCustomer
},
items: [
{ xtype: 'textfield', name: 'name', fieldLabel: 'Name' }
]
});
// Event Subscriber
class CompactCustomerRolesSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [\Ext\DirectBundle\Event\DirectEvents::POST_QUERY_EXECUTE => 'transformData'];
}
public function transformData(\Ext\DirectBundle\Event\ResponseEvent $event)
{
$data = $event->getData();
// Transform data here
$event->setData($transformedData);
}
}
Parameter Binding:
params: true in routing for dynamic parameters.{page: 1, limit: 10}, the controller must define getCustomersAction($page, $limit).Hydration Mode:
KnpPaginator, always set HYDRATE_ARRAY in Doctrine queries to avoid hydration issues:
$query->setHydrationMode(\Doctrine\ORM\Query::HYDRATE_ARRAY);
Form Data Binding:
array_intersect_key($_data, $form->all()) to filter out unsupported fields before binding:
$_data = array_intersect_key($_data, $form->all());
CORS Issues:
# config/packages/nelmio_cors.yaml
nelmio_cors:
defaults:
allow_origin: ["*"]
allow_methods: ["GET", "POST", "PUT", "PATCH", "DELETE"]
allow_headers: ["Content-Type", "Authorization"]
expose_headers: ["Link"]
Annotation Loading:
composer.json:
"autoload": {
"psr-4": {
"": "src/"
},
"classmap": ["app/AppKernel.php", "app/AppCache.php"]
}
Check ExtJS Console:
ExtDirect.Symfony Profiler:
// app/config/config_dev.yml
framework:
profiler: { only_exceptions: false }
Logging DirectBundle Events:
// In an event subscriber
public function transformData(ResponseEvent $event)
{
$this->logger->debug('Event data:', ['data' => $event->getData()]);
// ...
}
Validate Routing:
php bin/console cache:clear
php bin/console debug:router | grep ext_direct
Custom Response Classes:
\Ext\DirectBundle\Response\Response to add custom logic:
class CustomResponse extends \Ext\DirectBundle\Response\Response
{
public function setCustomData($data)
{
$this->data['custom'] = $data;
return $this;
}
}
Event Subscribers:
PRE_QUERY_EXECUTE or POST_QUERY_EXECUTE to modify data:
// src/Acme/DemoBundle/EventListener/CustomSubscriber.php
class CustomSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
\Ext\DirectBundle\Event\DirectEvents::PRE_QUERY_EXECUTE => 'preExecute',
\Ext\DirectBundle\Event\DirectEvents::POST_QUERY_EXECUTE => 'postExecute'
];
}
}
Override Templates:
config.yml:
ext_direct:
error_template: "@AcmeDemo/extdirect/error_template.html.twig"
Batch Processing:
$_list) by iteratingHow can I help you explore Laravel packages today?