the Netzke project – RoR CRUD application

In the last few days I was searching RoR CRUD generators on the Internet because I wanted to compare them. I tried these CRUD generators:

rails_admin – https://github.com/sferik/rails_admin

puffer – https://github.com/puffer/puffer

admin-assistant – http://fhwang.github.com/admin_assistant/

bowtie – https://github.com/tomas/bowtie

admin-interface – https://github.com/joost/admin_interface

netzke – http://netzke.org/

I think netzke became my Favorited RoR CRUD solution. It is really great so I would like to write some things about it.
Recently I was working with Symfony2 and I wanted to refresh my Ruby on Rails knowledge so I had read some article and blog post about Rails developing.
Well, I guess Ruby on Rails is very complex and clean programming environment as well as it is handy. But of course it is not better or worse than for example Symfony (or Yii etc.) it is just different. I like both.

Netzke has very good step-by-step installation guide. You should just follow the instructions what this guide contain.

http://writelesscode.com/blog/2012/10/20/extjs-rails-crud-application-in-7-minutes

It use the Ext JS and it makes very easy to add JavaScript grids, forms and other JS components to your application. I think is a one of the the best CRUD what I’ve ever tested. As I mentioned I use Symfony2 and if I need CRUD then I use SonataAdmin for Symfony2. All right, SonataAdmin is really cool and very complex SF2 bundle but I think netzke is contain some better solutions especially it has easier configuration and more flexible front-end features.

That’s it. :–)

Advertisements
Posted in Uncategorized | Tagged , , , | Leave a comment

Node.JS MVC frameworks: Getting started with CompoundJS.

I’ve been looking for one framework written in Node.js and it is similar to Symfony. Yes, I know PHP and Node.js is different as well as them have completely different philosophy therefore any MVC framework written in PHP will be working a little bit different than it would be written in Node.js.

When I found CompoundJS, I was doubting because it seemed too simple but it turned out I just had prejudices. 🙂 Now I think CompoudJS is a great framework. I like it and I would like to show CompoudJS installation and its CRUD generator. CompoudJS is a HMVC framework.

Installation

I installed it on Ubuntu Linux. I have used MySQL database during the testing so I needed to install the JugglingDb MySQL plugin. (CompoundJS has an ORM its name is JugglingDB.)

1. I installed CompoundJS.
2. I initialized new project as Book
3. I installed JugglingDb MySQL extension

 sudo npm install compound -g  
 compound init book  
 cd book  
 sudo npm install -l  
 sudo npm install jugglingdb-mysql  

4. Configure database.

As I told it I use MySQL so my db configuration is that (config/database.js)

 module.exports =   
 { "development":  
  { "driver":  "mysql"  
  , "host" : "127.0.0.1"  
  , "username": "root"  
  , "password": ""  
  , "database": "compound_test"  
  }  
  ,  
  "production":  
  { "driver":  "mysql"  
  , "host" : "127.0.0.1"  
  , "username": "root"  
  , "password": ""  
  , "database": "compound_test"  
  }  
 }  

5. Create your test database schema.

 var Book = describe('Book', function () {  
   property('id', String);  
   property('title', String);  
   property('description', String);  
   property('ISBN', String);  
   property('createdAt', Date);  
   property('modifiedAt', Date);  
   set('restPath', pathTo.books);  
 });  

If you wants to generate database table you should use CompoundJS command line tool:

 compound db update  

This command creates database tables if it doesn’t exist and it will updating tables if your schema was changed.

6. Create simple CRUD

It is very simple you only need this command:

 compound g scaffold book id title description ISBN createdAt:date modifiedAt:date  

This command generates controllers, helpers, models etc.

7. Start web server and try your first CompoundJS CRUD.

 compound server  

You will be able to start with this URL: http://127.0.0.1:3000/books

CRUD screenshot

CRUD screenshot

One screenshot 🙂

I think CompoundJS is very promising. I had just one problem that it is little bit undocumented. I was looking for a few things in its documentation but I didn’t find it (for example about routing, Ajax etc.).

Posted in Uncategorized | 11 Comments

Zombie.JS (the brilliant testing tool) and PHP

“Zombie.js is a lightweight framework for testing client-side JavaScript code in a simulated environment. No browser required.” Source: http://zombie.labnotes.org/

I think this quote is absolutely true. I’d like to show some examples how you can use Zombie.js and PHP together.

You will need the Node.js you must install it by it’s documentation: https://github.com/joyent/node/wiki/Installation

After the Node.js installation you should install Zombie.js. I use Ubuntu Linux therefore I installed it with this command:

  sudo npm install zombie  

It’s easy. 🙂

I offen use Selenium and I think the Selenium is very good testing tool I like it, but I have some problems with it. For example sometimes it is slow. Zombie.js is not replaces Selenium just it is in addition to the Selenium. I use both.

1. my test PHP file test_ajax.php ( yes. i know. It is trivial but…it is just example.)

 <?php   
 if (isset($_GET) && !empty($_GET)){  
   if (isset($_GET['param1'])) {  
     switch($_GET['param1']){  
       case "1":    echo "ok"; exit;  
       case "2":    echo "ok"; exit;  
       case "3":    echo "ok"; exit;  
       case "4":    echo "ERROR"; exit;  
       default: echo "error";exit;  
     }  
   }  
 }  
 ?>  
 <!DOCTYPE html>  
 <html lang="en">  
 <head>  
 <meta charset="utf-8">  
 <title>Test Ajax</title>  
 <link rel="stylesheet" href="css/style.css">  
 <script>  
 function loadAjaxResult()  
 {  
   xmlhttp = new XMLHttpRequest();  
   if (xmlhttp) {  
     xmlhttp.open("GET", 'http://localhost/test_ajax.php?param1=Hello',true);  
     xmlhttp.onreadystatechange=function() {  
       if (xmlhttp.readyState==4) {  
         ds=xmlhttp.responseText;  
         document.getElementById('testResult').innerHTML = xmlhttp.responseText;;  
       }  
     }  
     xmlhttp.send(null)  
   }  
 }  

 function loadAjaxResult2()  
 {  
   var myspan=document.getElementById('span_data');  
   var test_value = myspan.getAttribute("data-ajax-test");  
   xmlhttp = new XMLHttpRequest();  
   if (xmlhttp) {  
     xmlhttp.open("GET", 'http://localhost/test_ajax.php?param1='+test_value,true);  
     xmlhttp.onreadystatechange=function() {  
       if (xmlhttp.readyState==4) {  
         ds=xmlhttp.responseText;  
         document.getElementById('testResult2').innerHTML = xmlhttp.responseText;  
       }  
     }  
     xmlhttp.send(null)  
   }  
 }  
 </script>  
 </head>  
 <body>  

   <h2>Test Form</h2>  

   <div id="testResult"></div>  
   <button id="button1" type="button" onclick="loadAjaxResult()">BUTTON1</button>  

   <div id="testResult2"></div>  
   <span id="span_data" data-ajax-test="1"></span>  
   <button id="button2" type="button" onclick="loadAjaxResult2()">BUTTON2</button>  
 </body>  
 </html>  

2. the test1.js (node.js source code) file

 var Browser = require("zombie");  
 var assert = require("assert");  

 // Load the page from localhost  
 browser = new Browser();  

 browser.visit("http://localhost/test_ajax.php").  
  then(function() {  

   console.log(browser.html()); //show HTML source  

   assert.equal(browser.text("H2"), "Test Form"); //simple assertion  

   //simple test Ajax method  
   browser.pressButton("BUTTON2", function() {  
     assert.equal( browser.document.getElementById('testResult2').innerHTML, "ok"); //simple assertion  
   });  

   //test Ajax method with different parameters -- it is going to throw error 🙂  
      for (var i = 1; i < 5; i++) {  
     var myspan = browser.document.getElementById('span_data');  
     myspan.setAttribute("data-ajax-test", i); //set new data to data attributes  
       browser.pressButton("BUTTON2", function() { //press simple button and start ajax request  
         assert.equal( browser.document.getElementById('testResult2').innerHTML, "ok"); //simple assertion  
     });  
    }  

  }).  
  fail(function(error) {  
   console.log("Oops", error);  
  });  

3. start test

  node test1.js   

Quite simple. 🙂

Posted in ajax, node.js, php, Uncategorized | Tagged , , , | 1 Comment

PHPUnit and PHPUnit_Selenium extension – simple Ajax test

I have used the PHPUnit 3.7.13 and selenium-server-standalone-2.28.0.

1. Install or refresh the PHPUnit and PHPUnit_Selenium

 sudo pear install pear.phpunit.de/PHPUnit  
sudo pear install pear.phpunit.de/PHPUnit_Selenium

2. Very, very simple PHP test page :)))

 <?php   
if (isset($_GET) && !empty($_GET)){
if (isset($_GET['param1'])) {
switch($_GET['param1']){
case "Hello": echo "ok"; exit;
case "123456789": echo "ok"; exit;
case "value2": echo "ok"; exit;
case "value3": echo "ERROR"; exit;
default: echo "error";exit;
}
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Test Ajax</title>
<link rel="stylesheet" href="css/style.css">
<script>
function loadAjaxResult()
{
xmlhttp = new XMLHttpRequest();
if (xmlhttp) {
xmlhttp.open("GET", 'http://localhost/kortebacsi/test_ajax.php?param1=Hello',true);
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4) {
ds=xmlhttp.responseText;
document.getElementById('testResult').innerHTML = xmlhttp.responseText;;
}
}
xmlhttp.send(null)
}
}

function loadAjaxResult2()
{
var text_ajax_value = document.getElementById('text_ajax_value');
var data_unittest = text_ajax_value.value;
xmlhttp = new XMLHttpRequest();
if (xmlhttp) {
xmlhttp.open("GET", 'http://localhost/kortebacsi/test_ajax.php?param1='+data_unittest,true);
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4) {
ds=xmlhttp.responseText;
document.getElementById('testResult2').innerHTML = xmlhttp.responseText;;
}
}
xmlhttp.send(null)
}
}
</script>
</head>
<body>
<div id="testResult"></div>
<button id="button1" type="button" onclick="loadAjaxResult()">BUTTON1</button>

<div id="testResult2"></div>
<input type="text" name="text_ajax_value" id="text_ajax_value">
<button id="button2" type="button" onclick="loadAjaxResult2()">BUTTON2</button>
</body>
</html>

3. Unit test

 <?php  
require_once 'PHPUnit/Extensions/SeleniumTestCase.php';

class almatest extends PHPUnit_Extensions_Selenium2TestCase
{
const WAIT_SECOND = 1;
const AJAX_RESULT_OK = "ok";

var $url = "http://localhost/test/test_ajax.php";
var $url2 = "http://localhost/test/test_ajax.php";
var $main_test_page_title = "Test Ajax";
/**
* Set Up PHPUnit Selenium extension parameters
*/
protected function setUp()
{
$this->setBrowser('firefox');
$this->setBrowserUrl($this->url);
}

public function testSimpleAjax()
{
$this->url($this->url);
$button1 = $this->byId('button1');
$button1->click();
sleep(self::WAIT_SECOND);
$ajax_response = $this->byId('testResult')->text();
$this->assertEquals(self::AJAX_RESULT_OK, $ajax_response);
}

public function testAjaxWithParams()
{
$this->url($this->url);
$test_param_input = $this->byName('text_ajax_value');
$test_param_input->value( '123456789');
$button2 = $this->byId('button2');
$button2->click();sleep(self::WAIT_SECOND);
$ajax_response = $this->byId('testResult2')->text();
$this->assertEquals(self::AJAX_RESULT_OK, $ajax_response);
}

}
?>

4. Run test.

 java -jar selenium-server-standalone-2.28.0.jar  

phpunit test_selenium_phpunit.php
Posted in ajax, HTML5, PHPUnit, PHPUnit_Selenium | 2 Comments

Getting started with selenium & PHP

If you want to use Selenium from your PHP application you could try the php-webdriver project: https://github.com/facebook/php-webdriver

1. Create directory into your work or home directory and intsall php-webdriver.

1:  mkdir selenium_test  
2: cd selenium_test
3: git clone git://github.com/facebook/php-webdriver.git

2. Download Selenium server

http://seleniumhq.org/download

3. Start Selenium server

 java -jar selenium-server-standalone-2.28.0.jar  

5. Make your test form.

 <?php   
if (isset($_POST) && !empty($_POST)){
var_dump($_POST);
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Test HTML5 Form</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div id="test-form">
<form id="contact" method="post" action="">
<fieldset>
<label for="name">Name</label>
<input type="text" name="name">
<label for="email">E-mail</label>
<input type="email" name="email">
<label for="phone">Phone</label>
<input type="text" name="phone">
<label for="website">Website</label>
<input type="url" name="url">
<label for="message">Question/Comment</label>
<textarea name="message"></textarea>
<input type="submit" name="submit" id="test_submit_button" value="Send" />
</fieldset>
</form>
</div><!-- end form -->
</body>
</html>

Save this file to the testform.php and move it into your www directory or create direct link.

6. Your first simple selenium test PHP.

1:  <?php  
2:
3: require_once('php-webdriver/__init__.php');
4: $wd_host = 'http://localhost:4444/wd/hub';
5: $web_driver = new WebDriver($wd_host);
6: $session = $web_driver->session('firefox');
7: $session->open('http://localhost/localhost/testform.php');
8:
9: echo $session->title(); //
10:
11: $session->element( "name", "name") -> value( split_keys("Test John"));
12: $session->element( "name", "email") -> value( split_keys("testmail@emailserver.com"));
13: $session->element( "name", "phone") -> value( split_keys("111111111"));
14: $session->element( "name", "url") -> value( split_keys("http://localhost/test_form.php"));
15: $session->element( "name", "message") -> value( split_keys("Hello world!"));
16:
17: $session->element('id', 'test_submit_button')->click();
18:
19: function split_keys($toSend){
20: $payload = array("value" => preg_split("//u", $toSend, -1, PREG_SPLIT_NO_EMPTY));
21: return $payload;
22: }
23: ?>
24:

This simple PHP is going to put values into your testform fields and posting it.

7. Start your test.

php test.php  

Thats it. 🙂

Posted in php, selenium | 4 Comments

Silex & Twitter Botstrap

Silex: “Silex is a PHP microframework for PHP 5.3. It is built on the shoulders of Symfony2 and Pimple and also inspired by sinatra.”

Twitter Boostrap: “Sleek, intuitive, and powerful front-end framework for faster and easier web development.”

🙂 The project Silex – Kitchen Edition is only sample but it is very interesting.

https://github.com/lyrixx/Silex-Kitchen-Edition

Video: Silex: From Micro to Full Stack

Posted in Silex, Symfony2, Twitter Bootstrap | Leave a comment

Symfony2: My Form Type Class generator

Symfony2 has a Doctrine Form Generator. It is work properly but it always needs Entity as a parameter and it only generates one Form Type Class at the same time.
I’ve rebuild the generator. My generator supports bulk form generation and it has got one new parameter type: “rewrite”. (it rewrites old Form Type Class file if exists).

The original generator path:

 \vendor\sensio\generator-bundle\Sensio\Bundle\GeneratorBundle\Command\GenerateDoctrineFormCommand.php  

I have rewritten the original file. 🙂 The original command was (example):

 php app/console generate:doctrine:form CompanyTestBundle:Customer  

the hew command is:

 php app/console generate:doctrine:form CompanyTestBundle:Customer --rewrite=true  

and if you don’t give the Entity Name it will generate each Form Classes in the bundle:

 php app/console generate:doctrine:form CompanyTestBundle --rewrite=true  

Changes in the original source code:

1. add InputOption Class

 use Symfony\Component\Console\Input\InputOption;  

2. new parameter in the configure() method:

   protected function configure()  
{
$this
->setDefinition(
array(
new InputArgument('entity', InputArgument::OPTIONAL, 'The entity class name to initialize (shortcut notation)'),
new InputOption('rewrite', null, null, 'Second addend'),
))
->setDescription('Generates a form type class based on a Doctrine entity')
->setHelp(<<<EOT
The <info>doctrine:generate:form</info> command generates a form class based on a Doctrine entity.
<info>php app/console doctrine:generate:form AcmeBlogBundle:Post</info>
EOT
)
->setName('doctrine:generate:form')
->setAliases(array('generate:doctrine:form'))
;
}

3. the new execute method:

   protected function execute(InputInterface $input, OutputInterface $output)  
{
$generate_all_entity = false;
$rewrite_files = false;
if ( $input->hasOption('rewrite'))
{
if ( $input->getOption('rewrite') == "true" )
{
$rewrite_files = true;
}
}
if ( $input->hasArgument('entity'))
{
if (false === $pos = strpos($input->getArgument('entity'), ':')) {
$bundle = $input->getArgument('entity');
$generate_all_entity = true;
} else {
$entity = Validators::validateEntityName($input->getArgument('entity'));
list($bundle, $entity) = $this->parseShortcutNotation($entity);
}
}
if ($generate_all_entity == false)
{
$entityClass = $this->getContainer()->get('doctrine')->getEntityNamespace($bundle).'\\'.$entity;
$metadata = $this->getEntityMetadata($entityClass);
$bundle = $this->getApplication()->getKernel()->getBundle($bundle);
if ( $rewrite_files)
{
$form_type_class_file = $bundle->getPath().DIRECTORY_SEPARATOR."Form".DIRECTORY_SEPARATOR.$entity."Type".".php";
if (is_file( $form_type_class_file))
{
unlink($form_type_class_file);
}
}
$generator = new DoctrineFormGenerator($this->getContainer()->get('filesystem'), __DIR__.'/../Resources/skeleton/form');
$generator->generate($bundle, $entity, $metadata[0]);
$output->writeln(sprintf(
'The new %s.php class file has been created under %s.',
$generator->getClassName(),
$generator->getClassPath()
));
}
else
{
$bundle_name = $bundle;
$bundle = $this->getApplication()->getKernel()->getBundle($bundle);
$generator = new DoctrineFormGenerator($this->getContainer()->get('filesystem'), __DIR__.'/../Resources/skeleton/form');
$finder = new Finder();
$finder->name('/\.php$/');
$finder->files()->in( $bundle->getPath().DIRECTORY_SEPARATOR.'Entity' );
foreach ($finder as $file) {
$entity = basename($file->getFileName(), '.php');
if ( $rewrite_files)
{
$form_type_class_file = $bundle->getPath().DIRECTORY_SEPARATOR."Form".DIRECTORY_SEPARATOR.$entity."Type".".php";
if (is_file( $form_type_class_file))
{
unlink($form_type_class_file);
}
}
$entityClass = $this->getContainer()->get('doctrine')->getEntityNamespace($bundle_name).'\\'.$entity;
$metadata = $this->getEntityMetadata($entityClass);
$generator->generate($bundle, $entity, $metadata[0]);
$output->writeln(sprintf(
'The new %s.php class file has been created under %s.',
$generator->getClassName(),
$generator->getClassPath()
));
}
}
}

That is it. I hope it will be useful 🙂

Posted in Doctrine, form generator, Symfony2 | Leave a comment