Symfony 2.6 : The good momentum to implement “official” Symfony best practices
Symfony 2.6 released yesterday. There are ton of features/bug fixes added. There is another thing that awesome! We can implements the “AppBundle way” of the official best practices. Although the
AppBundle
that mentioned in the official documentation brought by Symfony 2.6, is not in Symfony-standard yet ( at least until now), we can generate it by new updated SensioGeneratorBundle that already shipped by new symfony-standard.
So, after you generate :
php app/console generate:bundle --namespace=AppBundle \ --dir=src --format=annotation --no-interaction
Now, you can have bundle without “vendor” namespace.
Then, if you do what mentioned in the best practices, that template location in app/Resources instead (for templates that the bundle only used in your application). The project structure will like the following :
There are complete list of “official” recommended ways to build application using Symfony application including configuration, controllers, templates, forms, internationalization, security, web assets, and tests.
One more thing, now, we can use Symfony Installer to create a new Symfony application that you can download from https://github.com/symfony/symfony-installer . The console interface of installer is pretty good :
References :
1. http://symfony.com/doc/current/best_practices/index.html
2. https://twitter.com/weaverryan/status/538610340020649984
3. https://github.com/symfony/symfony-installer
Zend Framework 2 : Using AbstractConsoleController and ConsoleModel
When using console in ZF2 application, we can extends
AbstractConsoleController
instead of AbstractActionController
. There is overridden dispatch()
function in AbstractConsoleController
which handle access that doesn’t come from console which is tricked like this :
// ... /** * {@inheritdoc} */ public function dispatch(RequestInterface $request, ResponseInterface $response = null) { if (! $request instanceof ConsoleRequest) { throw new InvalidArgumentException(sprintf( '%s can only dispatch requests in a console environment', get_called_class() )); } return parent::dispatch($request, $response); } // ...
So, by extending it, we can reduce its checking. So, our controller will look like the following :
namespace TutorialConsoleModule\Controller; use Zend\Mvc\Controller\AbstractConsoleController; class TutorialConsoleController extends AbstractConsoleController { public function showDataAction() { // ... } }
Now, we need to show something in console, instead of using Response
object, we can use ConsoleModel
so we can return ConsoleModel
that setted with the data like this :
namespace TutorialConsoleModule\Controller; use Zend\Mvc\Controller\AbstractConsoleController; use Zend\Text\Table; use Zend\View\Model\ConsoleModel; class TutorialConsoleController extends AbstractConsoleController { public function showDataAction() { $table = new Table\Table([ 'columnWidths' => [20, 20] ]); $table->setDecorator('ascii'); $table->appendRow(['FirstName', 'LastName']); $table->appendRow(['Abdul Malik', 'Ikhsan']); $table->appendRow(['Sharty', 'Mushlihah']); $consoleModel = new ConsoleModel(); $consoleModel->setResult($table); return $consoleModel; } }
Now, you can just register your controller into module.config.php :
return [ 'controllers' => [ 'invokables' => [ 'TutorialConsoleModule\Controller\TutorialConsole' => 'TutorialConsoleModule\Controller\TutorialConsoleController', ], ], 'console' => [ 'router' => [ 'routes' => [ 'show-data' => [ 'options' => [ 'route' => 'show data', 'defaults' => [ 'controller' => 'TutorialConsoleModule\Controller\TutorialConsole', 'action' => 'show-data' ] ] ] ] ] ], ];
And you can call in console :
php public/index.php show data
and you will get :
Done 😉
Re-fill selectize js value
It’s been a while since I didn’t write a post about non-framework category. Ok, this time, I will show you how to use selectize js on re-fill functionality. Selectize js is a jQuery plugin that useful for tagging and autocomplete. I used it in several projects. Once it’s installed and selectize()
called, your form can be like the following :
In images demo above, I want to re-set the “district” based on the “province” changes by javascript. To make selectize still applied to “district”, you need to do :
- re-set Html option values
- re-set selectize value options
Ok, let’s do a demo application for this.
1. Preparation
1.a make bower.json
for dependency requirements definition
{ "name":"Selectize Demo", "dependencies": { "jquery": "1.11.1", "selectize":"0.11.2" } }
1.b make .bowerrc
for specification
{ "directory": "js", "json": "bower.json" }
1.c install dependencies
bower install
2. Initialize selectize
We can initialize selectize js by include it in the header ( js and css ) like this :
<link href="./js/selectize/dist/css/selectize.default.css" media="screen" rel="stylesheet" type="text/css"> <script type="text/javascript" src="./js/jquery/dist/jquery.min.js"></script> <script type="text/javascript" src="./js/selectize/dist/js/standalone/selectize.min.js"></script>
and then, we create the elements which we want to selectize :
<form method="post"> <select name="province_id" id="province_id"> <option value="0">--Select Province--</option> <option value="1">Jawa Barat</option> <option value="2">Jawa Tengah</option> </select> <select name="district" id="district"> <option value="0">--Select District--</option> </select> </form>
Now, time to execute :
$(document).ready(function() { //initialize selectize for both fields $("#province_id").selectize(); $("#district").selectize(); });
3. Do the awesome
Ok, now what ? We need to re-fill the “district” data on change of “province”, In this case, I wrote a case when using Ajax request and catched by PHP script. So, create a “change-data.php” file :
<?php if (isset($_POST['province_id'])) { $data = []; if ($_POST['province_id'] == 1) { $data = [ 0 => [ 'id' => 1, 'name' => 'Bandung', ], 1 => [ 'id' => 2, 'name' => 'Cimahi', ] ]; } if ($_POST['province_id'] == 2) { $data = [ 0 => [ 'id' => 3, 'name' => 'Kudus', ], 1 => [ 'id' => 4, 'name' => 'Cirebon', ] ]; } echo json_encode($data); }
Basically, the selectize can be filled by json object that have “text” and “value” key, like the following :
[ {text: "Bandung", value: 1 }, {text: "Cimahi", value: 2 } ]
So, we need to get the data, and convert to json object, we can do with eval
:
new_value_options = eval('(' + new_value_options + ')');
Ok, now, let’s do this :
$(document).ready(function() { //initialize selectize for both fields $("#province_id").selectize(); $("#district").selectize(); // onchange $("#province_id").change(function() { $.post('./change-data', { 'province_id' : $(this).val() } , function(jsondata) { var htmldata = ''; var new_value_options = '['; for (var key in jsondata) { htmldata += '<option value="'+jsondata[key].id+'">'+jsondata[key].name+'</option>'; var keyPlus = parseInt(key) + 1; if (keyPlus == jsondata.length) { new_value_options += '{text: "'+jsondata[key].name+'", value: '+jsondata[key].id+'}'; } else { new_value_options += '{text: "'+jsondata[key].name+'", value: '+jsondata[key].id+'},'; } } new_value_options += ']'; //convert to json object new_value_options = eval('(' + new_value_options + ')'); if (new_value_options[0] != undefined) { // re-fill html select option field $("#district").html(htmldata); // re-fill/set the selectize values var selectize = $("#district")[0].selectize; selectize.clear(); selectize.clearOptions(); selectize.renderCache['option'] = {}; selectize.renderCache['item'] = {}; selectize.addOption(new_value_options); selectize.setValue(new_value_options[0].value); } }, 'json'); }); });
That’s it, hope it helpful. Want to grab the code ? grab it from https://github.com/samsonasik/selectize-demo
leave a comment