quinta-feira, 12 de agosto de 2010

Declarações IN e NOT IN no Linq to Entity

Esses dias eu quebrei a cabeça para fazer uma declaração IN e NOT IN em minha query.
Enfim, eu tinha pensado que já tinha arrumado uma solução, que seria utilizar o Contains:

var query =

from i in dm.inspecoes

where i.idtipo_operacao == 6

&& !(from i2 in dm.inspecoes

where i.idtipo_operacao == 5

select i2.chassi)

.Contains(i.chassi)

select i;

foreach (var c in query) Console.WriteLine( c );

Nossa, fiquei super alegre em saber que eu poderia utilizar o Contains, que geraria uma clausula CONTAINS no comando SQL final.
Dai fui implementar...e...nada! :S
Dava o seguinte erro:

LINQ to Entities does not recognize the method 'Boolean Contains[String](System.Linq.IQueryable`1[System.String], System.String)' method, and this method cannot be translated into a store expression.

Igual diz o Milton Leite: "Que beleza!"
Pesquisando na internet, vi que o Entity não tem suporte para o método Contains. Dai pensei: Que padronização maravilhosa! essa é a Microsoft! :(

A SUBQUERY
Uma forma que eu arrumei de solucionar esse problema, é utilizar a clausula Where da minha entidade.
Primeiro de tudo, eu separei a subquery em uma outra variavel.
Nessa subquery, nós possuimos todas as ocorrências que nós queremos inserir dentro da clausula IN:

var subQuery = (from i2 in dm.inspecoes
where idtipo_operacao == 5
select new { chassi = "'" + i2.chassi + "'" });

Como o campo do meu critério é do tipo VARCHAR e não INT, eu preciso inserir uma apostrofe antes e depois do valor de cada campo, dai o resultado seria: { '123455abcde', '987654fedcba'}
Até ai beleza, montamos nossa SubQuery.
Agora, precisamos passar os valores para um array, para que posteriormente tenhamos os valores dentro da clausula IN. Nossa array fica dessa forma:

string[] resultados;
resultados = subQuery.Select(r => r.chassi).ToArray();

Para finalizar, basta inserirmos a clausula IN ou NOT IN em nossa query principal:

A QUERY PRINCIPAL E A SOLUÇÃO
var queryFinal = dm.inspecoes.Where("it.idtipo_operacao = 6 AND it.chassi IN {" + string.Join(",", resultados) + "}");

Notem que eu usei como alias para a minha tabela a sigla "it". Esse alias é criado pelo Emtity por padrão para a entidade selecionada.

Depois, com esse resultado você pode voltar um list ou um array.
return queryFinal.ToList();
return queryFinal.ToArray();

OBSERVAÇÕES
Como o Entity Framework não tem suporte para o Contains, esse foi um método que consegui obter o resultado que queria. Porém, se formos pensar bem, teremos uma queda de desempenho considerável em nossa query.
O que a query acima faz, é o seguinte:
SELECT * FROM inspecoes i WHERE i.chassi NOT IN ('331311233', '2323434244', '2342324234', '2343232423');

Lembra que passamos o resultado da subquery para um array? Então, esse array nada mais é que o seguinte resultado: { '331311233', '2323434244', '2342324234', '2343232423' }

Se o Entity desse suporte para o Contains, o resultado final seria:
SELECT * FROM inspecoes i WHERE i.idtipo_operacao = 6 AND i.chassi NOT IN (SELECT chassi FROM i i2 WHERE i2.idtipo_operacao = 5)

A consulta SQL seria mais rápida, porque o SGBD não precisará verificar valor por valor do conteudo que esta na clausula IN. Sem contar que podemos ter o campo "chassi" indexado, o que ajudaria no desempenho de nossas consultas.

To passando um perrengue danado com esse Entity, mas chego lá!!

quinta-feira, 29 de julho de 2010

Menu dinâmico buscando itens da base de dados (ASP.Net)

Fala pessoaL!
Nossa, faz muito tempo que não posto nada e para falar a verdade, faz tempo que eu nem acesso meu blog. Estou sem tempo e com muitas preocupações. Viajarei para a Australia no fim desse ano e isso esta me deixando ansioso e muito nervoso. Correria total!!
Bom, como o blog não é sobre mim mas sim sobre análise e desenvolvimento de sistemas, vamos ao que interessa.

Devido a um novo projeto da empresa, comecei a programar em asp.net C# há poucos dias. Precisei fazer um controle de login dos usuários e claro, um menu contendo todos os menus que o usuário tem acesso.
Só que esses menus estão cadastrados na base de dados. E agora?
Não achei nada na internet, nenhum blog de pessoas que já fizeram isso em asp.net e disponibilizaram.

TECNOLOGIAS E FERRAMENTAS UTILIZADAS

Estou utilizando o modelo entidade relacional Entity Framework da Microsoft, acessando uma base de dados MySQL (the best database ever! ;) )

Não irei tratar aqui sobre como fazer os relacionamentos das tabelas ou criação e associação entre as classes do nosso modelo objeto relacional, mas sim como criar o menu para o site e seus respectivos filhos.

TABELAS USADAS NO EXEMPLO


Eu utilizei uma tabela com relacionamento Self One to Many. Para quem não conhece esse tipo de relacionamento, vale a pena dar uma olhada nesse outro post em meu blog:

http://devutils.blogspot.com/2008/12/sql-relacionamentos-self-to-self.html

CREATE DATABASE `exemplomenu`

USE `exemplomenu`

DROP TABLE IF EXISTS `menus_web`;

CREATE TABLE `menus_web` (
`idmenus` int(7) unsigned NOT NULL AUTO_INCREMENT,
`nome` varchar(45) NOT NULL COMMENT 'nome do item de menu',
`ordem` int(7) unsigned DEFAULT NULL COMMENT 'para ordenação dos itens de menu',
`pai` int(7) unsigned DEFAULT NULL,
`hint` varchar(255) DEFAULT NULL,
`bitmap` int(7) DEFAULT NULL COMMENT 'icone do item de menu',
`url` varchar(50) DEFAULT NULL,
PRIMARY KEY (`idmenus`),
KEY `fk_menus_menus1` (`pai`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=latin1;

/*Data for the table `menus_web` */

insert into `menus_web`(`idmenus`,`nome`,`ordem`,`pai`,`hint`,`bitmap`,`url`) values (1,'Veículos',50,NULL,NULL,NULL,''),(2,'Relatórios',NULL,1,NULL,NULL,''),(3,'Por responsabilidade',NULL,2,NULL,NULL,'/veiculos/relatorios/responsabilidade.aspx'),(4,'Avarias por montadora',NULL,7,NULL,NULL,''),(5,'Avarias por modelo',NULL,7,NULL,NULL,''),(6,'Avarias por peça',NULL,7,NULL,NULL,''),(7,'Gráficos',NULL,1,NULL,NULL,''),(8,'Por responsabilidade e período',NULL,2,NULL,NULL,''),(9,'Algodão',NULL,NULL,NULL,NULL,''),(10,'Relatórios',NULL,9,NULL,NULL,''),(11,'Sair',NULL,NULL,NULL,NULL,'sair.aspx');


CRIAÇÃO DO MENU

Utilizarei o componente Menu, que se encontra na aba Navigation da ToolBox. Vamos deixar o ID dele como Menu1.

Repare que o menu possui uma propriedade chamada MaximumDynamicDisplayLevels. Essa propriedade diz quantos nodes filhos o menu poderá ter.

//Objeto do tipo MenuItem (node de um menu)
MenuItem vMenu;
//Objeto array, do tipo MenuItem
MenuItem[] vMenu2 = new MenuItem[5];
int vCont = 0;

Primeriamente vamos gerar um procedimento que nos traz todos os menus pais, ou seja, que contenha o valor pai igual a vazio.

private void GerarMenu()
{
using (kerpModel.kerpModelEntities dm = new kerpModel.kerpModelEntities())
{
//SELECIONA OS DADOS DO MENU POR MEIO DO LINQ
var consMenu = (from m in dm.menus_web
where m.pai == null
select m);


//CORRE OS REGISTROS DO MENU
foreach(kerpModel.menus_web row in consMenu)
{
//Cria um novo node para o menu
vMenu = new MenuItem(row.nome.ToString());

vMenu.NavigateUrl = row.url.ToString();
Menu1.Items.Add(vMenu);
//Chama o procedimento que verifica se o menu possui filhos, passando o id do menu como parametro
this.GerarMenuFilho(int.Parse(row.idmenus.ToString()));
}
}
}


//Função que adiciona os filhos do item de menu
private void GerarMenuFilho(int idpai)
{
using (kerpModel.kerpModelEntities dm = new kerpModel.kerpModelEntities())
{
//SELECIONA OS DADOS DO MENU, QUE TEVE O ID PASSADO POR PARAMETRO
var consMenu = (from m in dm.menus_web
where m.pai == idpai
select m);

//CORRE OS REGISTROS DO MENU
foreach (kerpModel.menus_web row in consMenu)
{
//Chama a função que verifica se o menu atual também possui filhos
if (totalFilhos(int.Parse(row.idmenus.ToString())) > 0)
{
//Adiciona o menu ao array de menus, para que ele possa ser recuperado posteriormente
vMenu2[vCont] = vMenu;
//Variavel que conta quantos nodes principais o menu possui
vCont++;
//Adiciona o filho atual ao menu e ao mesmo tempo diz que agora o novo menu é ele mesmo
vMenu.ChildItems.Add(vMenu = new MenuItem(row.nome.ToString(), null, null, row.url.ToString(), null));
//Chama novamente a função, e adiciona seus filhos
this.GerarMenuFilho(int.Parse(row.idmenus.ToString()));
}
else
{
//Caso o item não possua filos, apenas o adiciona como um novo node
vMenu.ChildItems.Add(new MenuItem(row.nome.ToString(), null, null, "~"+row.url.ToString(), null));
}
}

//Aqui esta o segredinho. Foi para isso que eu criei o contador. Cada vez que o node e seus filhos sao criados, ainda é necessário criar os outros nodes faltantes, mas esses nodes precisam ser inseridos em seus pais. Cada vez que o cursor passa por aqui, dizemos que o menu atual é o menu pai anterior. Dificil de entender, né? para entender, debuge a aplicação.
vCont--;
if(vCont >= 0)
vMenu = vMenu2[vCont];

}
}

//Função que verifica se o menu possui filhos
private int totalFilhos(int idmenu)
{
int count = 0;
using (kerpModel.kerpModelEntities dm = new kerpModel.kerpModelEntities())
{
count = (from m in dm.menus_web
where m.pai == idmenu
select m).Count();
}
return count;

}


//Para finalizar, no nosso Page_Load nós chamamos o procedimento
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
this.GerarMenu();
}
}

Pessoal, peço desculpas por estar ausente do blog. Esta muito dificil de acessá-lo. Mas assim que for possível, responderei a seus comentários. Obrigado.

quinta-feira, 20 de agosto de 2009

Dump com FirePHP/FireBUG e Zend Framework

Esses dias que eu estava me atualizando na internet, me deparei com um artigo falando sobre o FirePHP, que até aquele momento me era desconhecido.
Para todos os desenvolvedores que trabalham com Javascript em especialmente Ajax, o Firebug do Firefox é uma ferramenta "ferrada" para o debug e dump das informações que foram criadas via Javascript.

E que tal termos algo parecido só que para o PHP? Seria legal, não é verdade? É exatamente isso que o FirePHP faz.

Eu não falarei exatamente sobre o FirePHP, mas falarei sim sobre como utilizálo no Zend Framework por meio das classes já existentes no nosso maravilhoso framework que é uma mão na roda!

Quem quiser saber mais sobre o FirePHP, aconselho ler o mesmo artigo que li no imasters:
http://imasters.uol.com.br/artigo/13959/php/_como_debugar_aplicacoes_ajaxphp_com_firephp/

E também indico o manual do Zend que fala sobre o FirePHP:
http://framework.zend.com/manual/en/zend.log.writers.html#zend.log.writers.firebug

É por isso que gosto do Zend, pela sua vasta documentação :)


CRIANDO AS INSTÂNCIAS NECESSÁRIAS

O FirePHP funciona como um log. Do mesmo jeito que criamos log por meio da classe Zend_Log. É o Zend_Log quem delega o log atual registrado para os "log writers" e o Zend_Log_Writer_FireBug é um componente writer que envia o log para o FirePHP.

Em seu bootstrap, antes de você dar um dispatcher em seu controller, insira as linhas abaixo:

$logger = new Zend_Log();
$writer = new Zend_Log_Writer_Firebug();

//DIZ AO LOG QUEM É O WRITER, OU SEJA, QUEM IRÁ GRAVAR OS LOGS
$logger->addWriter($writer);

Para utilizar seu log em todo o seu projeto, você pode manter uma instancia do seu Logger para toda a aplicação e usar em suas views, controllers e models:
Zend_Registry::set('logger',$logger);

Utilizando o Logger:
$logger = Zend_Registry::get('logger');
$logger->log('Mensagem de log para o FirePHP!', Zend_Log::INFO);

Repare na constante INFO da classe Zend_Log.
Toda vez que chamarmos um Log, no FireBug do firefox será mostrada um ícone de informação com a mensagem do primeiro parametro.
Você também pode utilizar as constantes WARN ou ALERT como referência de log ou prioridade das mensagens.

Um exemplo disso, é utilizarmos esse log em blocos Try catch.
Exemplo:
try {
// Caso tenha ocorrido algum erro
} catch(Exception $e) {
Zend_Registry::get('logger')->err($e)
}

ou também de outra forma:

try {
// Caso tenha ocorrido algum erro
} catch(Exception $e) {
$logger->log('Erro em bloco try catch ao tentar inserir dados na Base: '.$e, Zend_Log::ALERT);
}


DUMP DE INFORMAÇÕES PROCESSADAS NA BASE DE DADOS

Seria legal nós termos um dump de todas as operações que são feitas em nossa base de dados, não acha?
Mas seria um saco, cansativo e de grande manutenabilidade termos que chamar nosso log toda hora.

Mas..olha só como o Zend é camarada...rs
No seu bootstrap mesmo, insira as seguintes linhas de código depois de ter setado o seu Adapter e antes do dispatcher do seu controller:

$profiler = new Zend_Db_Profiler_Firebug('All DB Queries');
$profiler->setEnabled(true);
//$db SERIA O SEU ADAPTER CONFIGURADO PARA ACESSAR A BASE DE DADOS.
$db->setProfiler($profiler);

Com esse código, toda vez que for enviada uma instrução SQL para nossa base, o FirePHP nos mostrará os dados enviados para o servidor, parecido com a imagem abaixo:


DICAS

Em meu firebug, eu tive que habilitar a opção Rede (Última aba da janela do FireBug).
Não esqueça de habilitar o seu FirePHP.
Insira seu site na lista de (allowed Sites) do FirePHP
Seria chato se os usuários que acessam o site visualizassem todos os dumps que usamos para nos basear em tempo de produção, não é verdade?
Para não enviarmos mais o dump, não é necessário tirar todas as linhas de código dos nossos objetos. Basta fazer o seguinte:

$writer->setEnabled(false);
$profiler->setEnabled(false);

Espero que tenham gostado da matéria e por favor, enviem sugestões, criticas ou elogios.
Abraços.

segunda-feira, 3 de agosto de 2009

Upload de arquivos com Zend Framework - Parte 2

Pessoal,
Criei uma classe que utiliza o Zend_File para o upload de arquivos.
Como sempre tive problemas ao postar códigos nesse blog, tive novamente que dar um printscreen da tela...

Eu criei uma classe abstrata chamada Utils, onde implemento todos os métodos que utilizo frequentemente em meu projeto.
Os métodos que crio nessa classe são estáticos, pq não precisarei criar uma estância deles cada vez que eu for utilizá-los.
Eu criei um diretório chamado "classes" dentro de application. Basta adicionar o include_path desse diretório em seu bootstrap.

Essa classe faz upload de todos os campos do tipo file que tiver na página.
@UploadDir: Diretório para onde será encaminhado o arquivo
@renameFile: Caso deseja renomear os arquivos para que não haja overwrite, deixe este parâmetro como true. Caso contrário, o arquivo sofrerá overwrite.
@allowedFiles: Caso filtrar os tipos de arquivos à enviar, crie um array contendo os formatos permitidos.



Reparem que eu utilizei um método da própria classe, que serve para identificar a extensão do arquivo.
Segue abaixo o código desse método estático:
static function findexts($filename)
{
$filename = strtolower($filename) ;

$exts = split("[/\\.]", $filename) ;

$n = count($exts)-1;

$exts = $exts[$n];

return $exts;
}


Para chamar a classe em Seus controllers:



Caso você queira permitir todos os tipos de arquivos, basta não passar o 3º parâmetro para a classe.

Caso o nome dos arquivos sejam renomeados, o nome inicial do arquivo será o nome do input, por exemplo: foto_perfil....jpg
Para verificar se houve erro no envio de algum arquivo, você pode fazer o seguinte tratamento:
//LOOP EM CIMA DOS ARQUIVOS ENVIADOS
foreach($filesUploaded as $fileUploaded)
{
//HOUVE ERRO NO ARQUIVO?
if(!strpos($fileUploaded, 'Erro:')) {...}
}


Qualquer dúvida, fiquem avontade de incluir comentários.


Instead of reinventing the wheel, I use Frameworks. ZEND FRAMEWORK! ;)

sexta-feira, 17 de julho de 2009

FUNÇÃO AJAX C/ JQUERY

E ai pessoal,
Tenho demorado para postar pq estou muuuuuito sem tempo :(

Está mais correria do que nunca, mas a vida honesta é dura, faz parte.

Eu comecei outro projeto nesse mes.
É um site de relacionamentos e terá muitas coisas em Ajax.
Eu pensei então em escrever uma função que me auxiliasse toda vez que fosse preciso carregar meus dados sem dar um Refresh na página inteira.
Essa função que eu desenvolvi é bem simples de utilizar.
Eu testei várias vezes e até agora tem suprido minhas necessidades.


As funções Javascript.

Infelizmente, o blog não me permite inserir códigos javascript. Então dei um printscreen da minha tela..e estou passando para vocês.

A PRIMERA FUNÇÃO QUE CHAMEI DE isArray, É RESPONSÁVEL POR VERIFICAR SE O OBJETO PASSADO É UM ARRAY

A SEGUNDA FUNÇÃO É A ALMA DO NEGÓCIO, A FUNÇÃO callAjax.
Segue abaixo alguns detalhes sobre os parâmetros
@CAMPO = NOME DO CONTAINER(DIV) QUE VOCÊ DESEJA ATUALIZAR
@PARAMETRO = PARAMETROS QUE DESEJA PASSAR PARA A URL (PODE SER UM ARRAY)
@CAMPOVALOR = CAMPOS QUE POSSUEM OS VALORES REFERENTES AOS PARAMETROS (A SEQUENCIA DOS VALORES AQUI DEVEM ESTAR NA MESMA ORDEM QUE VOCÊ PASSOU O PARAMETRO. TAMBÉM PODE SER UM ARRAY)
@METODO = MÉTODO GET OU POST
@VARURL = URL QUE VOCÊ DESEJA CHAMAR




Módo de utilização

Passando parâmetros e valores simples (não Array)
//TODA VEZ QUE UM COMPONENTE COM O ID "button1" FOR CLICADO, REQUISITA A FUNÇÃO JS.
$("#button1").click(function(){
callAjax('p_email', 'email', 'email', 'GET', 'verificaemail.php');
});


Passando parâmetros e valores compostos (Array)
//TODA VEZ QUE UM COMPONENTE COM O ID "button1" FOR CLICADO, REQUISITA A FUNÇÃO JS.
//PASSANDO 3 PARAMETROS PARA A PAGINA verificaemail.php
parametros = new Array(3);
parametros[0] = 'email';
parametros[1] = 'idcliente';
parametros[2] = 'idade';

//PASSANDO 3 VALORES PARA A PAGINA verificaemail.php.
//AQUI OS VALORES (id dos campos input por exemplo) DEVEM ESTAR NA MESMA SEQUENCIA DOS PARÂMETROS
valores = new Array(3);
valores[0] = 'campo_email';
valores[1] = 'campo_idcliente';
valores[2] = 'campo_idade';

O que seria enviado para a pagina verificaemail.php, seria o seguinte Querystring:
?email=valordocampo&idcliente=valordocampo&idade=valordocampo

Para chamar a função, é a mesma coisa. Idêntica como chamamos pelo primeiro exemplo:
$("#button1").click(function(){
callAjax('p_email', parametros, valores, 'GET', 'verificaemail.php');
});

A função callAjax você pode colocar dentro de um arquivo .js por exemplo, incluindo junto com sua biblioteca de scripts.

Para chamar a função como no exemplo acima, vc deve chamar dentro do ready do Jquery. Ficaria assim:

$(document).ready(function() {

$("#button1").click(function(){
callAjax('p_email', parametros, valores, 'GET', 'verificaemail.php');
});

});


Blz pessoal?
Desculpem a demora para postar.
No outro post, espero postar algumas coisas a mais sobre o Zend Framework.
Abraços...t+

terça-feira, 23 de junho de 2009

Carrinho de compras com Zend Framework

E ai pessoal,
Desculpem minha ausência, tenho me ocupado muito com alguns projetos que tenho feito por fora.

Tenho mexido bastante com o Zend Framework e só tenho uma coisa a dizer: Estou tendo bem menos dor de cabeça do que quando programava com PHP puro. Isso sem falar da organização do projeto em MVC, os benefícios do Zend_Layout, etc.

Em um dos projetos, tive que construir um carrinho de compras utilizando Session.
Eu li um livro sobre Zend Framework, que ensina a criar um carrinho de compras com o Zend_Registry.
O problema do Zend_Registry é que ele não utiliza sessões, mas sim variáveis globais.

Eu não me basiei nesse livro, então caso saiba de qual livro estou me referindo, esqueça o carrinho que você aprendeu lá caso queira fazer um carrinho baseado em Session.

Para a criação de Sessions no Zend, nós utilizamos a classe Zend_Session_Namespace();

Como essa é uma classe singleton, caso já tenha sido criada uma instância da mesma, apenas é retornado a instância já criada. Você pode tentar criá-la várias vezes, mas ela apenas retornará a instância que já foi criada, até que ela seja liberada da memória.
Ou seja, o Zend simplesmente ignora a criação do novo objeto vazio e continua a session com os mesmos valores já gravados.


Eu ajustei uma classe que peguei em um forum sobre ZF. Ela "manuseia" uma session e achei que valeria a pena incluí-la no meu projeto.

Como tive muito problemas ao postar o código nesse blog, eu printei as telas.
Pois o blog não estava permitindo que eu colocasse os conteudos

Segue abaixo a classe. Você pode ajustá-la conforme suas necessidades. Para nosso carrinho, creio que seja o suficiente da forma como a deixei.

CLASSE "CONTROLADORA" DAS NOSSAS SESSIONS


Eu já dei o name do meu namespace de carrinho, mas você pode colocar no construtor da classe um parâmetro que seria o nome do seu namespace. Caso você não de um nome para o namespace, ele adota o valor Default.
Ficaria assim: Zend_Session_Namespace('Default');


ACTION DE INCLUSÃO DE ITEM NO CARRINHO



LISTANDO OS ITENS NO CARRINHO

Para listar os itens no carrinho é simples, basta fazer um foreach da variavel carrinho, que atribuimos o valor no nosso controller: "$this->view->carrinho = $carrinho;"

$carrinho = $this->carrinho;
$chave = @array_keys($carrinho);
for($ i = 0; $i < count ($chave);$ i ++){
$indice = $chave[$i];

//CRIANDO O OBJETO DA NOSSA CLASSE DE PERSISTENCIA COM A BASE DE DADOS, DA TABELA PRODUTOS.

$produtos = new Produtos();
$where = "idproduto = ".$carrinho[$indice]['idproduto'];
//PUXANDO OS DADOS DO PRODUTO
$produto = $produtos->fetchRow($where);
}


Eu estou criando um objeto da nossa classe de persistencia (model), para poder visualizar o nome do produto, qtde em estoque, entre outras coisas.
Você pode usar seu próprio modelo.
Caso queira apenas mostrar o código do produto e quantidade escolhida pelo usuário, você poderia implementar o código abaixo:

$carrinho = $this->carrinho;
$chave = @array_keys($carrinho);

for($ i = 0;$ i< sizeof ($chave); $ i ++){
//GUARDANDO O INDICE DO ARRAY
$indice = $chave[$i];
//MOSTRANDO OS DADOS INCLUIDOS NO CARRINHO
echo $carrinho[$indice]['idproduto']." - ".$carrinho[$indice]['qtde'];

}


ATUALIZANDO E EXCLUINDO ITENS DO CARRINHO
Para atualizar ou excluir itens de um carrinho, eu coloquei um checkbox em nosso carrinho de compras, contendo o indice do mesmo ($indice), então eu aplico um submit do formulário contendo os itens incluidos.
O formulário nos enviará para uma action chamada udcarrinhoAction().

Segue abaixo minha action udcarrinho:



Caso vocês queiram apagar todos os itens do carrinho, basta usar o método emptySess da nossa classe.

Caso tenham dúvidas em como montar o formulário do carrinho, entrem em contato comigo. Farei de tudo para ajudar.

The Best regards for you guys!! ;)

quarta-feira, 20 de maio de 2009

Prova da IBM

Para aqueles que estão terminando a faculdade e querem estagiar na IBM, é necessário fazer uma prova que é válida por 1 ano.
A prova não é nenhum bicho de 7 cabeças, mas o que a torna difícil é o tempo para finalização das questões.

A prova é dividida em 3 módulos: Exercícios de Lógica, Inglês e Redação.


TESTE DE LÓGICA

Os problemas de lógica são divididos em 3 partes onde a primeira você possui 25 minutos, a segunda 15 minutos e a terceira 20 minutos. A cada 4 questões erradas 1 certa é anulada.

Todas as questões possuem 5 alternativas, sendo que na primeira parte, a alternativa (E) diz que todas as alternativas anteriores estão incorretas.
As questões da primeira parte são parecidas com as de baixo, mas claro que eu não me lembro exatamente como foram as questões, mas são bem parecidas:

Ex 1.: Antônio possui 60 reais e deseja comprar caixas de bombom para a namorada. Cada caixa custa 12,25. Quantas caixas Antônio poderá comprar?

Ex 2: Um ônibus possui 15 assentos de cada lado, porém 2 assentos foi retirado do lado direito para dar espaço à deficientes físicos.
No fundo, o ônibus possui 5 assentos. Quantos assentos tem no total?



A segunda parte é mais fácil. Você tem 5 códigos onde cada um diz respeito a uma categoria. Exemplo:

Serviços de almoxarifado e organização dos eventos da Empresa - Cód A

Instalações Elétricas e segurança - Cód B

Serviços e materiais de Limpeza - Cód C

Manutenção de equipamentos eletrônicos - Cód D


Em cada pergunta você deve responder à que categoria a pergunta melhor se adequa.
Exemplo:

1 - Repor produtos de limpeza
2 - Arrumar impressora com defeito
3 - Repor folhas para o almoxarifado
4 - Consertar vazamento no banheiro do 13º andar.
5 - Comprar canetas e folhas para impressão.


E por aí vai. Essa é a parte mais fácill da prova de lógica.

A terceira parte é um pouco mais chata, pelo menos na minha opinião.
É dada uma tabela com horários de saída e chegada de aviões de 4 aeroportos e em cima disso, é dada algumas perguntas referente aos horarios.
Sinceramente eu não me lembro de uma pergunta das questões dessa última parte, portanto eu ficarei devendo.


TESTE DE INGLÊS

A prova de inglês é super fácil e tem o prazo de 15 minutos. Creio que com um nível intermediário você conseguirá gabaritar a prova facilmente.
As questões de inglês possuem apenas 3 alternativas, o que torna ainda mais fácil a prova, porém neste teste a cada 1 erro, 1 questão certa é anulada. Portanto responda apenas as questões que você tenha certeza.

Tipos de questão:

1 - Have you ever _____ in Los Angeles?
a) stay b) been c) be

2 - Did you ______ Maurício yesterday?
a) see b) saw c) look


REDAÇÃO

Na redação você escolhe um dos 3 assuntos listados e possui prazo de 20 minutos:
1 - Team working (trabalho em equipe)
2 - Foco no cliente
3 - Alguma coisa relacionada a novas idéias no trabalho, algo do tipo: Boas idéias, novas soluções, etc.


Não tem como eu lembrar tudo, mas creio que isso já ajuda à quem quer fazer a prova e deseja se preparar.


ATUALIZAÇÃO - 09/06/2009


Pessoal, estou atualizando o blog para lhes informar que passei na prova.
Depois da prova, me chamaram para uma dinâmica em grupo.

Hasta Luego y buena prueba.