junho 20th, 2011 By Fabio B. Silva Categories: BDD/TDD, Design Patterns, PHP

Olá,

Nesse Post vou mostrar um pouco de desenvolvimento PHP usando BDD (Behaviour-Driven Development).
O BDD é uma prática ágil que tem como objetivo facilitar o desenvolvimento orientado a testes,
onde o software é direcionados por comportamentos, trazendo para o contexto de destes os casos de uso ou historias da aplicação.

Enquanto em TDD (Test Driven Development) testamos a aplicação de forma granular em um ambiente micro
no BDD os testes são globais voltados para a Funcionalidade, Casos de uso, Comportamentos, etc..

Como se em TDD testamos a aplicação de dentro para fora e já em BDD a aplicação é testada de fora para dentro.
Existe muito material sobre esse assunto p\ ai e muita gente mais preparada que eu para abordar esse assunto de forma teorica,
Então nesse Post vou mostrar na pratica um pouco de desenvolvimento PHP usando o Behat

Behat

Behat é um framework BDD em PHP 5.3 construindo sobre de componentes do Symfony2.
Behat foi inspirado no Cucumber do Rails e especialmente a parte da sintaxe das features.

A instalação do Behat pode ser feita baixando diretalente pelo git diretamente pelo do git: http://github.com/Behat/Behat
Ou instalando através do pear :

 
$ pear channel-discover pear.behat.org
$ pear install behat/behat

Se tudo der certo o Behat esta instalado
A versão atualmente disponível no pear é a 1.1.9
Para verificar se esta correto e ver a versão instalada execute :

$ behat -V
Behat version 1.1.9

Depois de concluir a instalação o Behat esta pronto para ser usado.
para isso vamos inicializar o projeto de testes com o Behat

$ cd path-to-my-app
$ behat --init

O comando behat –init vai criara a estruturar de diretórios usada p\ organizar os teste do Behat

|-- features
   |-- steps            ##Diretório dos arquivos que contem os cenários de testes
       |-- steps.php
   |-- support          ##Configurações, requires e configs de ambiente
       |-- bootstrap.php  
       |-- env.php

A definição de um historias e cenários de teste é bem simples.
Utilizando algumas palavras chaves : Feature, Scenario, Given, When, Then, But or And
Os cenários são escritos em arquivos .feature que serão interpretados pelo Behat

features/contacts.feature

Feature: Contacts Registration
    In order to demonstrate the framework
    As a SouDev using BDD
    I want to register contacts

  Scenario: Add new contact
    Given a contact named "Fabio B. Silva" using the email "fabio.bat.silva@gmail.com"
      And the phone "xx xxxx-xxxx"
     When press save
     Then everything will be saved

Com a historia escrita podemos executar o Behat dentro da aplicação
O Behat vai interpretar os arquivos .feature
e mostrar quais funções vc tem que implementar para poder rodas o teste

 
$ cd path-to-my-app
$ behat
1 scenario (1 undefined)
4 steps (4 undefined)
0m0.03s
 
You can implement step definitions for undefined steps with these snippets:
 
$steps->Given('/^a contact named "([^"]*)" using the email "([^"]*)"$/', function($world, $arg1, $arg2) {
    throw new \Behat\Behat\Exception\Pending();
});
$steps->And('/^the phone "([^"]*)"$/', function($world, $arg1) {
    throw new \Behat\Behat\Exception\Pending();
});
$steps->When('/^press save$/', function($world) {
    throw new \Behat\Behat\Exception\Pending();
});
$steps->Then('/^everything will be saved$/', function($world) {
    throw new \Behat\Behat\Exception\Pending();
});

Essa definição dos steps que o Behat lançou pode ser copiada para um arquivo de steps.php o que facilita bastante a implementação dos teste..
Porem escrever historias em inglês pode ser meio confuso, mais o tem suporte a i18n oq nos permite escrever as historias em português.
para isso basta adicionar # language: pt_BR no inicio do arquivo .feature
com isso ganhamos as palavras chaves em português : Funcionalidade,Cenario, Scenario, Quando, Então, Entao, Dado, Mas, E

features/contacts.feature

# language: pt_BR
Funcionalidade: Cadastro de contatos
    Para demostrar o funcionamento do framework
    Como SouDev que usa BDD
    Desejo cadastrar contatos

  Cenario: Adicionar um novo contato
    Dado um usuário chamado "Fabio B. Silva" usando o email "fabio.bat.silva@gmail.com"
      E com o telefone "xx xxxx-xxxx"
     Quando pressionar salvar
     Entao os dados serão salvos

E ao executar novamente o Behat a implementação dos teste agora também vem em português :

 
$ cd path-to-my-app
$ behat
1 scenario (1 undefined)
4 steps (4 undefined)
0m0.03s
 
You can implement step definitions for undefined steps with these snippets:
 
$steps->Dado('/^um usuário chamado "([^"]*)" usando o email "([^"]*)"$/', function($world, $arg1, $arg2) {
    throw new \Behat\Behat\Exception\Pending();
});
$steps->E('/^com o telefone "([^"]*)"$/', function($world, $arg1) {
    throw new \Behat\Behat\Exception\Pending();
});
$steps->Quando('/^pressionar salvar$/', function($world) {
    throw new \Behat\Behat\Exception\Pending();
});
$steps->Entao('/^todos os dados serão salvos$/', function($world) {
    throw new \Behat\Behat\Exception\Pending();
});

Com essa definição a implementação dos testes para essa feature pode ser feita
features/contacts_steps.php

use App\Entities\Contact, App\Entities\Phone, App\Services\ContactService;
 
$steps->Dado('/^um usuário chamado "([^"]*)" usando o email "([^"]*)"$/', function($world, $arg1, $arg2) {
    $contact = new Contact();
    $contact->setName($arg1);
    $contact->setEmail($arg2);
 
    $world->contact = $contact;
});
 
$steps->E('/^com o telefone "([^"]*)"$/', function($world, $arg1) {
    $world->contact->addPhone(new Phone($arg1));
});
 
$steps->Quando('/^pressionar salvar$/', function($world) {
    $world->saveReturn = ContactService::getInstance()->save($world->contact);
});
 
$steps->Entao('/^todos os dados serão salvos$/', function($world) {
     assertTrue($world->saveReturn);
});

O BDD e TDD são ferramentas essenciais para um software bem feito,
Infeliz mente muitos “desenvolvedores” ainda tem resistência a aderir ao teste e por achar perda de tempo, tedioso, etc..
O fato é que uma suite de testes bem feita vai tornar sua aplicação muito mais estável e vai lhe economizar tempo e cabelos ao longo do projeto. rsrs

Gostei bastante do Behat é um projeto muito bem estruturado e em constante evolução a versão 2.0 esta prestes a sair
Vale apena dar uma conferida na Documentação do Behat

E Para quem tiver o interesse deixei a app no git
https://github.com/FabioBatSilva/bdd-php-behat

Abraço e até a próxima….

junho 6th, 2011 By Fabio B. Silva Categories: Java, Sem categoria, Spring

Olá.

Escrevendo o post Java + MongoDB + Spring Data descobri o Spring Data JPA
e fiquei surpreso em descobrir algumas features como a criação de repositórios e consultas dinâmicas.
Neste Post vou falar um pouco sobre o Spring Data JPA e como ele pode lhe proporcionar uma maneira rápida e elegante de implementar seus repositórios.

O Spring Data JPA tem como principal objetivo facilitar a implementação das camadas de acesso a dados.
O Spring fica responsável pela implementação dos repositórios e oferece algumas funcionalidades sofisticadas e comuns na maioria dos CRUDs baseado na entidade que esta sendo gerenciada.

Nessa aplicação vou usar as entidades Contact, Phone, e o repositório ContactRepository.

As entidades são bem simples, é anotadas com o mapeamento de seus atributos e relacionamentos.
Contact.java

 
@Entity
@Table(name="phones")
public class Phone {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;
 
  @ManyToOne
  @JoinColumn(name="id_contact")
  private Contact contact;
  //getter and setter methods 
  ...
}

Phone.java

@Entity
@Table(name="contacts")
public class Contact {
 
   @Id
   @Column(name="id_contact")
   @GeneratedValue(strategy = GenerationType.AUTO)
   private Long id;
 
   @Column(name="name")
   private String name;
 
   @Column(name="email",unique=true)
   private String email;
 
   @OneToMany(mappedBy="contact",cascade=CascadeType.ALL, fetch=FetchType.LAZY)
   @Fetch(FetchMode.JOIN)
   @private Set<Phone> phones = new HashSet<Phone>();
 
  //getter and setter methods 
  ...
}

ContactRepository.java

public interface ContactRepository extends JpaRepository<Contact, Long> {
 
    public Contact findByEmail(String email);
}

Até aqui nada de novo, porem agora como a “mágica” do Spring JPA ..rsrs

A interface do repositório estende JpaRepository, essa interface tem alguns métodos comuns como findAll, findOne, save, delete, etc…
Normalmente teríamos que implementar essa interface criando uma classe ContactRepositoryImpl e registra-la como um bean do spring
para que então possamos utilizar o repositório.

Com o Spring JPA não é necessário escrever essa implementação :) ..
Não é magia meus amigos, é tecnologia !!!…rsrs

O Spring JPA vai procurar por interfaces de repositórios que estendam a interface JpaRepository,
e então criar uma implementação para a interface e registra-la como um bean.

Para isso so é necessário apenas adicionar a tag jpa:repositories no contexto do spring,
com isso o Spring sabe onde procurar os repositórios que ele teve implementar.

applicationContext.xml

 
// Declaração dos Beans, TransactionManager, DataSource, etc...
 
<jpa:repositories base-package="br.com.flexria.springjpa.repository" />

Com isso a implementação do repositório já esta pronta para ser injetada é utilizada na aplicação.

 
@Autowired
ContactRepository repository;
 
repository.save(contact);
 
repository.delete(contact);
 
List<Contact> list = contactRepository.findAll();

Isso por si so ja é algo incrível so que o Spring Data JPA vai alem.

Algo que ja é comum no Rails, são os Dynamic attribute-based finders que é a possibilidade de realizar buscas dinâmica baseadas nos atributos do objeto
Em rails temos :

//"SQL : SELECT * FROM contacts WHERE email = 'fabio.bat.silva@gmail.com'"
 
Contact.where(:email =>"fabio.bat.silva@gmail.com")
 
//Usando Dynamic attribute-based finders
Contact.find_by_email "fabio.bat.silva@gmail.com"

É exatamente isso que o Spring Data JPA faz,
além de implementar do repositório com ele é possível utilizar buscas dinâmica baseadas nos atributos do objeto.

   // HQL : select c from Contact c where c.email = ?1
    public Contact findByEmail(String email);
 
   // HQL : select c from Contact c where c.name like ?1
    public List<Contact> findByNameLike(String name);

Com base em algumas palavras chaves varias consultas podem ser feitas :

Keyword Sample JPQL snippet
And findByLastnameAndFirstname … where x.lastname = ?1 and
x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or
x.firstname = ?2
Between findByStartDateBetween … where x.startDate between 1? and
?2
LessThan findByAgeLessThan … where x.age < ?1
GreaterThan findByAgeGreaterThan … where x.age > ?1
IsNull findByAgeIsNull … where x.age is null
IsNotNull,NotNull findByAge(Is)NotNull … where x.age not null
Like findByFirstnameLike … where x.firstname like ?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by
x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1

Repositórios dinâmicos, consultas dinâmicas, Buscas baseadas em NamedQuery ou anotações, etc..
com certeza tem muita coisa a ser explorada no Spring Data JPA, me surpreendi com a facilidade e agilidade.

Vale apena dar uma conferida na documentação do Spring Data JPA

E Para quem tiver o interesse deixei a app no git
https://github.com/FabioBatSilva/spring-data-jpa

Abraço e até a próxima….

maio 31st, 2011 By Fabio B. Silva Categories: Design Patterns, Java, NoSQL, Spring

Olá.

A alguns dias escrevi um post sobre PHP + MongoDB e recebi um feedback muito positivo
então resolvi repetir a dose e mostrar um pouco da integração entre Java e MongoDB.

Na minha opinião essa é uma das principais vantagens do MongoDB em relação a outros bancos de dados NoSQL,
O MongoDB e extremamente fácil de se integrar com a maioria das linguagens.

Neste Post vou falar um pouco sobre o MongoDB e a integração com o java utilizando o Spring Data.
O MongoDB fornece o mongo-java-driver que atualmente esta na versão 2.6.X é uma API completa para acessar o MongoDB.
O Spring Data é um projeto recente, lançado em 2010, ele oferecer suporte a novas tecnologias não relacionais, suporte a extensões específicas a bancos de dados relacionais. Spring Data trabalha como uma camada intermediária entre seus POJOs e o MongoDB.

Nesse exemplo estou usando o maven para gerencias as dependências do projeto
Então alem das dependências habituais do projeto: Spring, JUnit e etc.. vamos precisar adiciona ao pow.xml as dependências do MongoDB e Spring Data

pow.xml

<dependency>
<!-- Spring dependencies -->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-core</artifactId>
	<version>${spring.version}</version>
	<exclusions>
		<exclusion>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
		</exclusion>
	</exclusions>
</dependency>
 
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>${spring.version}</version>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-aop</artifactId>
	<version>${spring.version}</version>
</dependency>
<dependency>
	<groupId>org.springframework.data</groupId>
	<artifactId>spring-data-mongodb</artifactId>
	<version>${spring.data.mongo.version}</version>
</dependency>
 
<!-- Querydsl -->
<dependency>
	<groupId>com.mysema.querydsl</groupId>
	<artifactId>querydsl-mongodb</artifactId>
	<version>${querydsl.version}</version>
	<optional>true</optional>
	<exclusions>
		<exclusion>
			<groupId>com.google.code.morphia</groupId>
			<artifactId>morphia</artifactId>
		</exclusion>
	</exclusions>
</dependency>
 
<dependency>
	<groupId>com.mysema.querydsl</groupId>
	<artifactId>querydsl-apt</artifactId>
	<version>${querydsl.version}</version>
	<scope>provided</scope>
</dependency>

Feito isso as dependências do projeto estão configuradas e podemos partir para a configuração do spring.
A configuração é bem simples, nesse exemplo existem apenas 2 beans que configuram o MongoDB e Spring Data mongoTemplate e mongo

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mongo="http://www.springframework.org/schema/data/mongo"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
 
    <context:annotation-config/>
 
 
    <context:component-scan base-package="br.com.flexria.contacts"/>
 
    <bean id="mongoTemplate" class="org.springframework.data.document.mongodb.MongoTemplate">
    	<constructor-arg name="mongo" ref="mongo"/>
    	<constructor-arg name="databaseName" value="test"/>
    	<constructor-arg name="defaultCollectionName" value="contacts"/>
    </bean>
 
    <bean id="mongo" class="org.springframework.data.document.mongodb.MongoFactoryBean">
    	<property name="host" value="localhost"/>
    </bean>
 
</beans>

O Spring Data oferece uma serie de anotações que permitem mapear o POJO de forma bem similar ao Hibernate/JPA
Contact.java

 
@Document(collection="contacts")
public class Contact {
    @Id
    private ObjectId id;
    private String name;
    private String email;
 
  //getter and setter methods 
  ...
}

E é através do mongoTemplate que vamos interagir com o MongoDB por exemplo :

 
@Autowired
MongoTemplate template;
 
// insere um novo registro		
template.insert("contacts", contact);
 
// insere/altera um registro
template.save("contacts", contact);
 
// remove um registro
template.remove(contact);
 
// lista todos os registros
List<Contact> list = template.getCollection(collectionName, Contact.class);

Apesar do Spring Data suportar o JPA repository fiz uma implementação genérica para um repositório usando o Spring Data.

GenericRepositoryWithMongo.java – Repositório genérico

public abstract class GenericRepositoryWithMongo<T, ID extends Serializable> {
 
  @Autowired
  protected MongoTemplate template;
  protected Class<T> targetClass;
  protected String collectionName;
 
  @SuppressWarnings("unchecked")
  public GenericRepositoryWithMongo() {
     this.targetClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
  }
 
  @PostConstruct
  public void initCollection() {
    if(this.targetClass.isAnnotationPresent(Document.class)){
      Document document   = this.targetClass.getAnnotation(Document.class);
      this.collectionName = document.collection();
    }
    else{
      this.collectionName = this.targetClass.getSimpleName().toLowerCase();
    }
  }
 
  public List<T> getCollection() {
    return template.getCollection(collectionName, targetClass);
  }
 
  public void persist(T entity) {
    template.insert(collectionName, entity);
  }
 
  public void merge(T entity) {
    template.save(collectionName, entity);
  }
 
  public void remove(T entity) {
    template.remove(entity);
  }
 
  public List<T> findAll() {
    return getCollection();
  }
 
  public long count() {
    return getCollection().size();
  }
}

E então a interface do repositório e sua implementação

ContactRepository.java – Repositório de contatos

public interface ContactRepository {
 
    public Contact findByEmail(String email);
 
    public void persist(Contact entity);
 
    public void merge(Contact entity);
 
    public void remove(Contact entity);
 
    public List<Contact> findAll();
}

ContactRepositoryImpl.java – Implementação do repositório de contatos

@Service("contactRepository")
@Repository
public class ContactRepositoryImpl extends GenericRepositoryWithMongo<Contact, ObjectId> implements ContactRepository{
 
	public Contact findByEmail(String email) {
	   Criteria criteria	 = Criteria.where("email").is(email);
	   Query query 	         = new Query(criteria);
	   return template.findOne(query, targetClass);
	}	
}

Realmente me surpreendi com a facilidade da integração usando o Spring Data
é um exemplo bem simples da integração porem mais da o caminho das pedras para quem esta se aventurando no mundo NoSQL.
Espero que seja util..

Para quem tiver o interesse deixei app no git
https://github.com/FabioBatSilva/spring-mongodb

Abraço e até a próxima….

maio 13th, 2011 By Fabio B. Silva Categories: Design Patterns, JavaScript

Olá,

Com a chegada eminente do HTML5 e outras tecnologias baseadas em javascript como MongoDB e node.js
tenho deixado o Flex o meio de lado e me dedicado um pouco mais ao javascript.
Porem fica a questão, Como ter um front-end com a mesma performance, escalabilidade e desacoplamento que o flex permite ?
Realmente nesses termos ainda não encontrei nada que me proporcione o que o Flex proporciona.

Nesse Post vou falar um pouco sobre Framework JavaScriptMVC
Me perece uma das melhores alternativas para manter um frond-end JavaScript/HTML

JavaScriptMVC é formado por uma seria de ferramentas para construção de aplicativos JavaScript e consiste nos seguintes componentes:

O JavaScriptMVC pode ser utilizado com qualquer back-end , java,php,rails, etc…
Ele pode ser instalado baixando diretamente aqui ou instalando cada componente individualmente atreves do github.

Os componentes devem ficar nas raiz do diretório web da sua aplicação, nesse caso a pasta public.
Então as estrutura da aplicação fica assim.

public
  /documentjs
  /funcunit
  /jquery
  /steal
  /js

O JavaScriptMVC tem ferramentas de geração de código para auxiliar na criação da aplicação.
Vamos começar criando a aplicação pelo terminal, então o JavaScriptMVC vai gerar toda a estrutura do projeto.

    cd path-to-application/public/
   ./js jquery/generate/app contacts

Assim como o rails o JavaScriptMVC possui scaffolds que podem gerar seu CRUD.
Para isso basta executar o comando scaffold passando como parâmetro o nome do modelo.
Os nomes das classes seguem o seguinte padrão : <Nome da Aplicação>.<Pacote>.<Nome da Classe>
então temos o model “Contacts.Models.Contact”

     ./js jquery/generate/scaffold Contacts.Models.Contact

O JavaScriptMVC vai gerar o controlador, modelos, views e testes unitários da aplicação.
Porem o único arquivo que sera incluído na aplicação é o steal.js ele é responsável por gerenciar as dependências da aplicação.
No ambiente de desenvolvimento ele vai incluir individualmente todos os controladores, modelos, etc..

<script type='text/javascript'  src='../steal/steal.js?contacts,development'></script>

O parâmetro “?contacts” na tag de inclusão indica o nome do arquivo de configuração que tem o mesmo nome da aplicação nesse caso contacts.js
nele ficam mapeados todas dependências do projeto que serão gerenciadas pelo StealJS
contacts/contacts.js – Arquivo de configuração

steal.plugins(	
    'jquery/controller',	
    'jquery/controller/subscribe',
    'jquery/view/ejs',		
    'jquery/controller/view',	
    'jquery/model',		
    'jquery/lang/json',
    'jquery/dom/form_params')
 
.css('contacts')
 
.resources()
.models('contact')
.controllers('contact')
.views();

Depois de fazer uma refatoração a aplicação ficou assim :

contacts/view/contact/contacts.html – Tela inicial da aplicação

<html>
    <head>
        <title>JS - MVC</title>
        <script type='text/javascript'  src='../steal/steal.production.js?contacts'></script>
    </head>
    <body>
        <div id='contacts'>
            <h1>Contacts</h1>
            <div id='contact'></div>
        </div>
    </body>
</html>

contacts/view/contact/list_view.ejs – Template para a listagem de contatos

<div class="link">
    <a href="javascript://" class='text_button create' >Create</a>
    <hr/>
</div>
<table class="table">
    <thead>
        <tr>
            <th>Name</th>
            <th>E-Mail</th>
            <th>&nbsp;</th>
        </tr>
    </thead>
    <tbody>
        <%for(var i = 0; i < contacts.length ; i++){%>
        <tr <%= contacts[i]%>>
            <td><%= contacts[i].name%></td>
            <td><%= contacts[i].email%></td>
            <td class="last">
                <a href='javascript://' class='edit'>edit</a>|<a href='javascript://' class='destroy'>destroy</a>
            </td>
        </tr>
        <%}%>
    </tbody>
</table>

contacts/view/contact/list_view.ejs – Template para o formulario de contatos

<div <%= contact%> >
    <form action="#" class="form">
        <div>
            <label class="label">Name</label>
            <input type="text" class="text_field" id="name" name="name" value="<%= contact.name%>" />          
            <label class="label">E-Mail</label>
            <input type="text" class="text_field" id="email" name="email" value="<%= contact.email%>" />
        </div>
        <div class="link">
            <a href="javascript://" class="text_button save">Save</a>
            <a href="javascript://" class="text_button cancel">Cancel</a>
        </div>
    </form>
</div>

contacts/models/contact.js – Classe ‘Contacts.Models.Contact’ Reponsavel pela abstração do acesso aos serviços

$.Model.extend('Application.Models.Contact',
/* @Static */
{
    /**
     * Service url.
     */
    url: 'http://localhost/patho-to-app/contacts/',
 
    /**
     * Recupera os dados dos contacts do serviço no backend.
     * @param {Object} params
     * @param {Function} success
     * @param {Function} error
     */
    findAll: function( params, success, error ){
        $.ajax({
            url     : this.url,
            type    : 'get',
            dataType: 'json',
            data    : params,
            success : this.callback(['wrapMany',success]),
            error   : error
        });
    },
    /**
     * Cria um novo contacto
     * @param {Object} attrs
     * @param {Function} success
     * @param {Function} error
     */
    create: function( attrs, success, error ){
        $.ajax({
            url     : this.url + 'save',
            type    : 'post',
            dataType: 'json',
            error   : error,
            success : success,
            data    : {contact:attrs}
        });
    }
    /**
     * Altera os dados de um contacto
     * @param {String} id
     * @param {Object} attrs
     * @param {Function} success
     * @param {Function} error
    */
    update: function( id, attrs, success, error ){
        $.ajax({
            url     : this.url + 'save',
            type    : 'post',
            dataType: 'json',
            data    : {contact:attrs},
            success : success,
            error   : error
        });
    },
    /**
     * Remove um contacto
     * @param {String} id
     * @param {Function} success
     * @param {Function} error
     */
    destroy: function( id, success, error ){
        $.ajax({
            url     : this.url + 'destroy/id/'+id,
            type    : 'post',
            dataType: 'json',
            error   : error,
            success : success
        });
    },
},
{});

contacts/controllers/contact_controller.js – Classe ‘Contacts.Controllers.Contact’ Responde a eventos da view e do modelo

$.Controller.extend('Contacts.Controllers.Contact',{onDocument: true},
{      
     /**
     * Função chamada quando a página é carregada
     */
     load: function(){
        this.findAll();
     },
 
     /**
     * Função que renderiza a listagem de contatos apartir do template /contacts/views/list_view.ejs
     * @param {Array} contacts
     */
     listView: function( contacts ){
        $('#contact').html(this.view('list_view', {contacts:contacts} ));
     },
 
     /**
     * Função que renderiza o formulario de contatos apartir do template /contacts/views/form_view.ejs
     * @param {Contacts.Models.Contact} contact
     */
     formView: function(contact){ 
        $('#contact').html(this.view('form_view', {contact:contact}));
     },
 
     /**
     * Função que lista os contatos atraves do model e renderiza a tela quando obtem resultado
     */
     findAll: function(){ 
        Contacts.Models.Contact.findAll({}, this.callback('listView'));
     },
 
    /**
     * Listener para o evento 'click' no link create
     */
    '.create click': function(){
        // cria um novo contato e monta o formulario
        var contact = new Contacts.Models.Contact();
        this.formView(contact);
    },
 
     /**
     * Listener para o evento 'click' no link edit
     * @param {jQuery} el
     */
    '.edit click': function( el ){
        // Recupera o contato selecionado e monta o formulario
        var contact = el.closest('.contact').model();
        this.formView(contact);
    },
 
     /**
     * Listener para o evento 'click' no link destroy
     * @param {jQuery} el
     */
    '.destroy click': function( el ){
        if(confirm("Are you sure you want to destroy?")){
            // Recupera o contato selecionado e o remove
            var contact = el.closest('.contact').model();
            contact.destroy();
        }
     },
 
    /**
     * Listener para o evento 'click' no link save
     * @param {jQuery} el
     */
    '.save click': function(el){
        // Recupera o contato selecionado
        var contact = el.closest('.contact').model();
        // Recupera os dados do formulario
        var attrs   = $('.form').formParams();
        // Atualiza os dados no "objeto"
        contact.attrs(attrs);  
        // Salva
        contact.save();      	// a função save é erdada do objeto Model
                               // ela verifica se o objeto ja existe e chama o metodo create ou update
    },
 
    /**
     * Listener para o evento 'click' no link cancel
     */
    '.cancel click': function(){
        this.findAll();
    },
 
    /**
     * Listener para o evento 'created' disparado pelo "objeto" Contacts.Models.Contact
     * @param {String} called
     * @param {Event} contact
     */
    'contact.created subscribe': function( called, contact ){
        this.findAll();
    },
 
    /**
     * Listener para o evento 'updated' disparado pelo "objeto" Contacts.Models.Contact
     * @param {String} called
     * @param {Event} contact
     */
    'contact.updated subscribe': function( called, contact ){
        this.findAll();
    },
 
     /**
     * Listener para o evento 'destroyed' disparado pelo "objeto" Contacts.Models.Contact
     * @param {String} called
     * @param {Event} contact
     */
    "contact.destroyed subscribe": function(called, contact){
        this.findAll();
     }
});

Agora antes de colocar a aplicação em ambiente de produção podemos compactar todos os arquivos .js e .css gerando uma versão final.

 ./js contacts/scripts/build.js

O StealJS utiliza o Google Closure para compactar todos os arquivos
e gerar arquivos compactados/concatenados que serão usados em produção contacts/production.js e contacts/production.css .

Com isso reduzimos todos os arquivos da aplicação, estilos, plugins, etc.. são reduzidos a apenas um arquivo .js e um arquivo .css.
E para mudar as configuração do ambiente temos apelas que mudar o tag de inclusão do StealJS

<script type='text/javascript'  src='../steal/steal.production.js?contacts'></script>

Esse foi apenas uma pequena amostra do JavaScriptMVC.
Com essa estrutura ele nos permite construir grandes aplicações de forma modular
com um bom ambiente de teste, velocidade no desenvolvimento e performance no ambiente de produção.

Essa aplicação esta rodando aqui : http://flexria.com.br/labs/js-mvc/
E os fontes estão disponíveis no github : https://github.com/FabioBatSilva/js-mvc

Abraço e até a próxima…. ;-)

abril 29th, 2011 By Fabio B. Silva Categories: JavaScript, NoSQL, PHP

Olá.

Ultimamente me tenho dedicado bastante a melhora da performance das aplicações que desenvolvo.
Resolvi compartilhar aqui um pouco do que aprendi sobre NoSql.
Esses bancos de dados seguem uma abordagem diferente para o armazenamento de dados em comparação com o modelo relacional tradicional.
E estão rapidamente se popularizando entre os desenvolvedores da Web, devido à sua flexibilidade, simplicidade e fácil integração.

Neste Post vou falar um pouco sobre o MongoDB e a integração com o php.
MongoDB é um banco de dados orientado a documentos uma solução escalável, de alto desempenho e código aberto.

Você vai encontrar nesse link instruções sobre como instalar o MongoDB no seu ambiente : http://www.mongodb.org/display/DOCS/Quickstart

Se você assim como eu estiver usando o Ubuntu, você pode instalar MongoDB usando apt-get.
Para fazer isso, adicione a seguinte linha ao seu arquivo /etc/apt/sources.list:

deb http://downloads-distro.mongodb.org/repo/debian-sysvinit dist 10gen

Em seguida, instale o pacote com apt-get executando os seguintes comandos:

sudo apt-get update 
sudo apt-get install mongodb-10gen

Se tudo der certo depois de concluir a instalação você pode acessar o MongoDB via linha de comando, como abaixo:

mongo
> show dbs
admin	(empty)
my_db	0.0625GB

Agora pode enviar comandos para o servidor, assim como faria em cliente mysql, porem utilizando a sintaxe do javascript.
A documentação do mongo é bem completa, la você pode encontrar mais detalhes sobre sua utilização : http://www.mongodb.org/display/DOCS/Home

 
// Exibe a versão banco de dados
> db.version()
1.8.1
 
// Cria uma nava coleção
> db.createCollection("contacts")
 
// Lista todas as coleções
> db.getCollectionNames()
[ "contacts", "system.indexes" ]
 
// Insere um novo item na coleção
> db.contacts.insert({"name" : "Fabio B. Silva", "email" : "fabio.bat.silva@gmail.com"})
 
// Lista todos os itens da coleção
> db.contacts.find()
{ "_id" : ObjectId("4db82c83a6510c5c77d67ebe"), "name" : "Fabio B. Silva", "email" : "fabio.bat.silva@gmail.com" }

Observe que quando você adiciona um novo registro a coleção o MongoDB anexa automaticamente um identificador único ( _id ).
Esse identificador pode ser usado para recuperar ou modificar um documento específico, similar a um id auto-increment em um banco de dados relacional.

Agora vamos partir para o código php.
existe uma extensão/drive para o php que fornece uma API completa para acessar o MongoDB, Ela está disponível gratuitamente a partir do PECL.
A extensão é estável e permite que você execute a maioria das tarefas comuns relacionadas ao acesso e utilização de um banco de dados MongoDB partir de uma aplicação PHP.

Para instalar você precisa ter o pear/pecl previamente instalados e executar o comando

pecl install mongo

E então adicionar a extensão no seu php.ini e reiniciar o seu apache

extension=mongo.so

Se tudo der certo na instalação você terá as classes do mongo disponíveis no php, as principais são:
* Mongo
* MongoDB
* MongoCollection
* MongoCursor

Mongo – Usado para interagir com o MongoDB

// Conexão com o banco de dados
 $mongo  = new Mongo();
 
// Conecta ao MongoDB
$mongo->connect();
 
// Remove um esquema
$mongo->dropDB("my_db_copy");
 
// Seleciona um esquema
$mongo->selectDB("my_db");
 
// Lista esquemas  
$list   = $mongo->listDBs();
 
// Fecha conexão
$mongo->close();

MongoDB – Usado para interagir com um esquema

 
// Seleciona um esquema
$db = $mongo->selectDB("my_db");
 
// Cria uma nova coleção
$db->createCollection("contacts");
 
// Seleciona uma coleção
$db->selectCollection ("contacts");
 
// Remove uma coleção
$db->dropCollection("contacts");
 
// Lista todas as coleções
$db->listCollections();

MongoCollection – Representa uma coleção

// Novo registro
$data = array(
    'name'  => 'Fabio B. Silva',
    'email' => 'fabio.bat.silva@gmail.com',
);
$contacts->insert($data);  // Insere um novo registro na coleção
$id = $data['_id'];        // O índice '_id' é anexado automaticamente pelo MongoDB
 
 
$data['name']  = 'Fábio Silva';         // Alterar o atributo
$criteria      = array('_id'=>$id);     // Critério do update|
$contacts->update($criteria, $data);    // Altera registro na coleção
 
 
$criteria  = array('_id'=>$id); // Critério para remoção
$contacts->remove($criteria);   // remove registro da coleção
 
 
 
$contacts->find();     // Lista todos os registros da coleção

MongoCursor – Resultado de uma consulta a uma coleção

 
// Lista todos os registros da coleção
$cursor = $contacts->find();
 
// Numero de registros encontrados
$cursor->count();
 
foreach ($cursor as $item)
{
    echo $item['name'];
}

Existem varias outras funcionalidades e classes que podem ser exploradas no MongoDB,
Essa é apenas uma pequena demostração do que ele pode fazer por você. ;-)
Para quem tiver o interesse deixei uma pequena app no git que demonstra algumas outras funcionalidades do MongoDB
https://github.com/FabioBatSilva/mongo-demo

Abraço e até a próxima….

Switch to our mobile site