Caniplay 2

From Laboratório MM 5

Revision as of 00:39, 2 February 2012 by Hugonogueira (Talk | contribs)
Jump to: navigation, search

Logo lettering white.jpgLogo lettering black.jpg

Universidade de Aveiro | DeCA | 2012

Laboratório Multimédia 5 | NTC


Hugo Nogueira - 51387


Contents

Introdução

Atualmente, a interação com a Web caracteriza-se pela gestão dos conteúdos por parte dos utilizadores, contrariamente aos primórdios da rede, em que esta gestão dos conteúdos era responsabilidade do Webmaster. Os web developers têm agora o papel de criar a estrutura do site e dotar o utilizador de ferramentas para personalizar os seus conteúdos.

Foi graças ao surgimento de novas tecnologias web, que passou a ser possível desenvolver aplicações Web 2.0 baseadas em três camadas: física, lógica e de apresentação. A camada física, de acesso aos dados, suportada por um SGBR, a lógica, por uma linguagem de programação server-side e a camada de apresentação, com o auxílio das tecnologias cliente-side.

Na unidade curricular de Laboratório 5, pretende-se com os conhecimentos obtidos, desenvolver uma desta aplicação Web, baseada no modelo de 3 camadas. Assim, o acesso aos dados ficará ao cargo do servidor MySQL e o tratamento dos dados na camada lógica encarregue ao PHP. Para apresentação ao cliente, serão utilizadas tecnologias estudadas em UC’s anteriores, nomeadamente o XHTML, CSS, Javascript e XML.

Esta aplicação Web deverá permitir as operações básicas da manipulação de dados (CRUD - Create, Read, Update e Delete), permitir autenticação e gestão de sessões, entre outros requisitos.


Objetivo do documento

Este documento tem como objetivo reportar o desenvolvimento da aplicação “Can I Play”, iniciada em época normal por Tiago Teixeira, Yauhen Kavalionak e Hugo Nogueira, e continuada por Hugo Nogueira.

Seguidamente serão apresentados os objetivos definidos para a aplicação e as funcionalidades implementadas e o modo como foram implementadas. Serão abordados os maiores desafios técnicos encontrados, soluções encontradas e bugs associados.

Como a avaliação da disciplina valoriza maioritariamente o desenvolvimento server-side, as implementações relativas à apresentação não serão tão focadas.


Visão Geral do Projeto

A plataforma a ser desenvolvida, intitulada “Can I Play”, deveria permitir aos utilizadores, preferencialmente os praticantes de futebol, encontrar outras pessoas, na sua zona de residência ou local preferido para a prática do desporto, para combinar jogos de futebol. Assim, um utilizador que pretende começar a jogar futebol, mas que não tem amigos conhecidos para isso, poderia utilizar a plataforma e encontrar outras pessoas com o mesmo problema, nomeadamente, pessoas que necessitassem de mais um jogador para poderem realizar os jogos.

Complementarmente, e como objetivo base proposto pela UC, a plataforma deveria permitir interagir socialmente com outros utilizadores (como se tratasse de uma rede social), permitindo aos utilizadores deixar comentários em diversas páginas, enviar mensagens a outros utilizadores e fazer a personalização do seu perfil.

Para incentivar o desportivismo e as boas normas, mas também a rivalidade positiva e o espírito de competição, pretendeu-se desenvolver um sistema de avaliação para os jogadores e equipas. Os jogadores teriam uma avaliação gerida pela restante comunidade, abordando os atributos “Habilidade”, “Desportivismo” e “Assiduidade”. Tal como as equipas, os resultados dos jogos oficiais combinados pela plataforma seriam registados no perfil do jogador ou equipa.

No entanto, pretende-se que não seja apenas o processo de formação de equipas que seja facilitado, mas também a reserva de espaços para praticar o desporto. Assim, para maior comodidade dos utilizadores, a plataforma deveria permitir encontrar campos de acordo com as preferências do utilizador (piso, localização, preço), permitir a reserva e consultar as horas já ocupadas.

Por fim, outro grande objetivo era a gestão de competições através da plataforma.


Base de dados desenvolvida

O desenvolvimento de uma aplicação Web 2.0 deve começar logo na camada mais baixa, a lógica. Esta irá influenciar as soluções lógicas a implementar (por vezes poderá ocorrer uma influência no sentido inverso) e, por isso, o seu desenvolvimento deverá ser cuidado para reduzir o número de futuros problemas.

A complexidade das funcionalidades a desenvolver vai refletir-se na complexidade da nossa base de dados (fig. 1). Infelizmente ficaram por implementar várias funcionalidades, como mensagens multidestinatários, reservas, etc, daí que apenas parte da BD esteja a ser utilizada. Sendo assim, é possível que o desenvolvimento das funcionalidades em falta visse a alterar a estrutura da BD, no entanto, a BD apresentada já está muito próxima à final.

Visao geral.jpg


De modo a facilitar a análise da BD, dividimos em quatro cores:


Um utilizador, inicialmente descativado, deveria confirmar o registo e assinalar as suas informações básicas na tabela principal (Utilizadores). Deverá escolher os horários pretendidos para jogar, disponíveis na tabela Horários (catálogo). Como se pretendia que fosse possível registar várias localizações, implementou-se uma tabela Localizações_Utilizador, embora só tenha sido usada uma localização por jogador. A cada grupo deveriam estar associados vários utilizadores e membros. Para garantir o funcionamento das classificações, seriam registados os votos de cada utilizador numa tabela relativa ao atributo em questão, no qual seriam registados o utilizador a votar e o alvo da votação (não permitiria batota nas votações). Finalmente, para implementar as notificações, optou-se por, à medida que estas seriam geradas na aplicação, por exemplo, quando alguém nos pedisse em amizade, seriam registadas na tabela de notificações com o nosso ID. Isto, em vez de detetar periodicamente novas atividades na rede, permitiria uma diminuição do processamento do servidor.

Os comentários seriam guardados numa tabela geral e relacionados com as diversas entidades através de tabela intermédias, por exemplo, Comentarios_Utilizador. Isto permite-nos facilmente aceder, tanto aos comentários apenas de uma entidade, como de toda a aplicação. As mensagens são guardadas na respetiva tabela e os destinatários noutra, permitindo a uma mensagem ter vários destinatários e a um utilizador ter várias mensagens. Os incidentes seriam um tipo especial de mensagem visível apenas aos moderadores da aplicação.

Na secção vermelha, os utilizadores podem organizar-se num jogo, registando o utilizador_id e o jogo_id. Para permitir que fossem resgistados vários convidados externos à aplicação, adicionamos um campo n_slots que apenas seria diferente de 0 neste caso (nos outros, cada utilizador ocupa apenas um slot). Este jogo poderá ser um jogo de competição, daí a tabela de especialização Jogos_Competicao, e a ligação desta à competição. Como pretendíamos que os jogadores se organizassem em equipas, fizemos a distinção entre Equipa_Plantel , com todos os utilizadores registado numa equipa e Equipa_Competicao, que podendo ou não corresponder a uma equipa já formada, necessita da inscrição individual dos jogadores na Convocatória_Competicao. Uma equipa registada e participante numa competição, permitiria registar os resultados no seu histórico. Para diminuir o esforço de processamento, preferimos ir atualizando os resultados obtidos dos utilizadores e equipas à medida que eram gerados, em vez de executar uma query pesada no sistema.


Implementação

Descrição das principais funcionalidades da aplicação WEB

Infelizmente não foi possível concretizar todos os objetivos definidos inicialmente, sendo que apenas algumas das funcionalidades foram implementadas. Assim, a plataforma, à data presente, suporta as seguintes funcionalidades:


Mapa de Páginas

Mapa dos maus.png



Server Behavior Utilizados

A nível de rotinas efetuadas periodicamente através do servidor de MySQL ou PHP, não foi implementada nenhuma solução. No entanto, em muitas funcionalidades, ao efetuar uma ação, o servidor PHP foi programado para executar outras ações de forma a automatizar a utilização da plataforma. O registo de uma nova conta, para além da validação de Javascript e PHP inclui a confirmação do email. Para isto, para além da configuração necessária no servidor, foi programado para que uma nova conta se encontrasse desativada, fosse adicionado o utilizador na tabela de desativados e um código de confirmação, gerado através da codificação SHA1 de um número aleatório de 1 a 100, e o envio deste para o email registado. Ao aceder à conta, o utilizador dispõe de um link que envia o parâmetro do código e do ID de utilizador para a página de confirmação. Se coincidirem, a conta fica registada.

Para ativar o serviço de email no servidor deverá configurar-se o ficheiro sendmail.ini com a seguinte informação:

[sendmail]
smtp_server=smtp.gmail.com
smtp_port=25
error_logfile=error.log
debug_logfile=debug.log
auth_username=mail.teste.ua@gmail.com
auth_password=SuaPassword
force_sender=Can I Play

e o php.ini com:

[mail function]
sendmail_path = "\"C:\xampp\sendmail\sendmail.exe\" -t"

Para facilitar, foi usada uma conta Gmail, cuja autenticação é menos exigente que a da UA (por exemplo, não é necessário VPN’s nem SSL).


A implementação do calendário foi feita utilizando uma tabela dinâmica em PHP, que lendo os dados da BD, associa a cada <td> um id (correspondente aos ids da tabela Horários) e uma classe (correspondente ao estado). Os eventos de clique permitem alternar a própria <td> entre classes. Ao submeter a página, através do botão para guardar o horário, estamos a concatenar todos os ids com a classe pretendida e a enviar num campo hidden essa string. Ao ler novamente a página, a função explode irá separar todos os ids num array. Os valores desse array são então inseridos na tabela respetiva (para a evitar verificar quais os ids que já estão presentes, optou-se por remover todos as horas já inseridas e correr apenas uma vez o array, inserindo os valores.

Os comentários foram implementados utilizando por base uma segunda página com o código relativo à leitura, escrita e desativação dos comentários. Para enviar informação para esta segunda página foi utilizada o XmlHttpRequest, passando dados por GET e POST. De modo a distinguir os comentários “pai” das respostas, foi adicionado um campo “pai” que, para comentários sem “pai” tomaria o valor zero, correspondente a um comentário desativado.

O sistema de votos foi desenhado de modo a não permitir que o próprio utilizador votasse em si próprio, não expondo a interface para efetuar o voto. Os outros utilizadores ao efetuarem um voto, é verificado se não está a repetir o voto e se for o caso, atualiza-o. Os utilizadores podem saber facilmente se já votaram numa pessoa, porque ao carregar a página é carregado o último voto efetuado naquele perfil.

No sistema de amizades, uma ligação entre dois utilizadores poderá apresentar um de três estados, os utilizadores são indiferentes um ao outro (não existe nenhum registo entre os dois); um utilizador pediu o outro em amizade (existe um registo apenas na direção de quem pediu para o outro, mas encontra-se desativado) e os utilizadores são amigos (existem dois registos em ambos os sentidos e estão ativos). Ao fazer um pedido de amizade, encontramo-nos no segundo estado e é enviada uma notificação automaticamente ao utilizador alvo. Lendo este estado, podemos então apresentar um pedido de amizade na página do utilizador alvo e um aviso que o pedido já foi enviado no caso do emissor. Ao aceitar o pedido, a relação é ativada, criando o registo inverso e atualizando os campos. A recusa do pedido elimina o registo temporário de amizade.

A barra de notificações é atualizada com a página, consultando as novas notificações e mensagens que esperam por ser observadas. Ao carregar num, atualizamos o registo para “lido”, não voltando a estar presente neste menu. Este comportamento também ocorre ao ler as notificações e mensagens na sua área específica da aplicação.

O sistema de pesquisa recorre a uma segunda página que procura nas tabelas correspondentes pelos termos inseridos. De modo a tornar a pesquisa dinâmica, um evento onkeydown na caixa de pesquisa envia o seu conteúdo como parâmetro para a segunda página – jQuery.load(). Esta segunda página, procura, limita os resultados e escreve no ecrã. De modo a não ficar com uma lista muito extensa, limitamos o tamanho do recordset a 6 registos e apresentamos apenas 5. Se o recordset tem 6 (ou mais, não sabemos) surge um link para ver os resultados todos.

A utilização dos grupos dispõe de alguns comportamentos programados em PHP muito específicos. Adicionalmente aos normais comportamentos de criação e verificação da exclusividade do nome, verificação se o utilizador pertence ou não ao grupo, números de membros, etc, foram adicionados dois comportamentos para evitar que o grupo fique sem administrador e sem membros. Como, nesta versão, não foram implementadas as tabelas de moderadores do grupo, o campo criador foi entendido como administrador do grupo. Apenas este tem capacidade de aceitar pedidos de novos membros e expulsar os existentes. Assim, torna-se vital que caso este utilizador saia do grupo, o membro mais antigo seja registado como novo administrador. Por outro lado, através do PHP, também se definiu que ao sair de um grupo, se o grupo ficasse vazio, torna-se automaticamente inativo, impedindo que existam grupos “fantasma” na aplicação.

O upload das imagens verifica qual é o tipo do ficheiro através do header. Se for uma imagem PNG ou JPEG, irá redimensiona-la para o tamanho correto e guardá-la com nome “imagem” numa pasta com o id do perfil (utilizador, grupo, etc). Por exemplo, o caminho da imagem do grupo de id 4 será “photos/groups/4/imagem.png”. A utilização do mesmo nome faz com que o servidor substituía a imagem pela anterior, não ficando imagens antigas acumuladas. No entanto, como os browsers guardam uma cache de ficheiros temporários, por vezes a alteração não é logo visível. De modo a verificar se a pasta do perfil já existe, utiliza-se os comandos “is_dir” para verificar a existência e “mkdir” para criar.

Sendo a base de dados muito complexa, é normal que algumas das atividades mais básicas se tornem mais complexas. Tal como a simples consulta envolve várias tabelas de modo a recolher os dados corretos, também o processo de inserção ocorre simultaneamente em várias, por exemplo, ao adicionar um comentário, não basta adiciona-lo na tabela Comentários, mas também será necessário recuperar o novo ID gerado através da informação em cache (guardada ainda nas variáveis) e inserir um novo registo na tabela que o associa a um perfil. Este comportamento ocorre em diversas funcionalidades.


RecordSets/Queries Utilizados

Ao longo da utilização da aplicação vão sendo constantemente consultados dados à BD. Na maioria, os recordsets gerados são resultado de uma query que seleciona os campos de uma ou duas tabelas, podendo ou não (dependendo se é informação do tipo “master” ou “detail”) serem filtrados os registos a consultar. No entanto, existem diversas query mais complexas e que serão analisadas abaixo:


Consultar voto

Hugo q1.png

Esta query vai devolver as informações relativas à habilidade do perfil de um utilizador. Para o utilizador de id “$user_id”, irá devolver o número de votos contabilizados e a média obtida para este atributo.


Grupos e equipas do utilizador

Hugo q2.png

O recordset é o resultado de uma query bastante simples, resultando da consulta da tabela Membros_Grupo com interceção com a grupos e sendo verificado se tanto o grupo como a ligação estão activas.


Estado da amizade

Hugo q3.png

Esta query vai devolver um registo se existir alguma ligação entre alguém e o nosso ID. Assim, se não existir nenhum registo ( mysql_num_rows($rs_amigos)==0 ) é porque não somos amigos. Se existir, vemos o conteúdo do campo activo. Se este for 0, o outro utilizador está a pedir-nos em amizade, se for 1, é porque já somos amigos.


Comentários e respostas

Hugo q4.png

Este script vai permitir-nos listar toda a informação relativa aos comentários no perfil do $user_id, que sejam principais (logo o “pai” é 0) e que estejam ativo. Estes comentários são ordenados do mais recente para o mais antigo e limitados a 10 registos. Agora, para encontrar as respostas a estes comentários, em cada instância da escrita de um comentário, vamos correr uma nova query.

Hugo q5.png

Esta query vai buscar os mesmos dados, mas utiliza o id obtido anteriormente como comentario_pai. Assim, temos todas as repostas, para cada comentário, que estejam ativas e ordenadas cronologicamente.


Pesquisa

Hugo q6.png

A pesquisa utiliza os wildcards % aliados ao operador LIKE para procurar um nome ou apelido que contenha no seu interior o termo da pesquisa. Neste caso, limita os resultados a 6 registos.


Amigos em Comum

Hugo q7.png

Este script é das queries mais complexas utilizadas no projecto. Vai criar uma auto-associação entre a nossa tabela Amigos com ela própria, de modo a podermos consultar informação de amigos dos nossos amigos e a contar o número de vezes que o registo se repete (quer dizer, o número de amigos em comum). Para que apenas surjam nas recomendações de amigos correctas, é necessário garantir que: o utilizador está ativo, assim como o nosso amigo e ambas as amizades; que estas pessoas não são nossas amigas; que não somos nós (porque nós seriamos sempre o registo com mais amigos em comum com os nossos amigos). Assim, as clausulas definidas em Where servem para: Hugo q8.png

Resultado, ordena decrescentemente os utilizadores pelo número de amigos em comum connosco, dando todas as informações necessárias e o número de amigos em comum.


Pessoas que não são nossas amigas mais próximas geograficamente

Hugo q9.png

Esta query destina-se a sugerir amigos a pessoas que ainda não tenham amigos e, por isso, não é possível procurar amigos em comum. Vai calcular para todos os utilizadores a distância entre as coordenadas do utilizador e as nossas, utilizando o Teorema de Pitágoras. Assim, temos a raiz quadrada (SQRT) da soma do quadrado dos catetos (cada cateto corresponde à distância entre latitudes ou entre longitudes). Devemos apenas ter o cuidado que nos filtrar, de modo a não sermos sempre o utilizador mais próximo de nós e, ordenando pela distância, temos os três utilizadores mais próximos.


Informações de um grupo

Hugo q10.png

Na página de gestão dos nossos grupos, como pretendemos consultar a informação básica do grupo e também o número de membros, utilizamos esta query. Ela irá verificar se a nossa participação no grupo está ativa e o estado do próprio grupo.


Pesquisa de destinatários

Hugo q11.png

A pesquisa de destinatário funciona como a pesquisa normal, no entanto tem como base as tabelas de amigos e de utilizadores, sendo por isso necessário verificar o estado da amizade e do utilizador amigo.

Parâmetros Passados entre Páginas

Durante o projeto, pretendeu-se explorar um pouco as diversas possibilidades de passar informação entre páginas e interagir com o servidor. A passagem de parâmetro mais básica ocorrer através da gestão de sessões, na qual o id do utilizador é guardado numa variável $_SESSION. A utilização da funcionalidade de manter sessão ativa é suportada pela utilização de cookies. Através dos cookies é possível guardar e consultar os dados de autenticação guardados no servidor (nota: para que as palavras-chave não pudessem ser reconhecidas por alguém com acesso à BD ou aos cookies, foram codificadas utilizando SHA1).

A utilização do método GET foi bastante utilizada para passar dados entre páginas, como o ID do utilizador a consultar ou de uma mensagem ou para executar certas operações (p.e. a página de registo, dependendo do parâmetro recebido pode permitir editar dados; o parâmetro del=3 indica em algumas páginas para eliminar o registo de id igual a 3).

O método POST devido à maior segurança e capacidade, foi utilizado para transportar formulários de maior informação ou com campos mais sensíveis (passwords). Também foi utilizado para fazer o upload de imagens.

A utilização do método GET e POST foi explorada com recurso a diferentes técnicas:


Integração

De modo a facilitar e agilizar o desenvolvimento da aplicação, foram utilizadas diversas tecnologias. O recurso a jquery é praticamente indispensável, quer através dos métodos e funções que são disponibilizados pelo jquery, quer por causa das inúmeras aplicações que já existem disponiveis. Destas, utilizámos na nossa aplicação o RATY, para facilitar a classificação dos utilizadores, o Autosizer, redimensionamento dinâmico de textareas e o BValidator, validação de formulários em javascript.
Uma das funções que se destacaram no jquery foi a utilização do .load() que permitiu actualizar com dados da BD, certos conteúdos da página.
O GoogleMaps API V3 foi útil de maneira a facilitar o registo da localização do utilizador. A utilização do geocoder() e da geometry permitiram fazer a correspondência de um local às suas coordenadas geográficas, e o cálculo de distâncias entre pontos.


Desenvolvimentos Futuros

Infelizmente, não foi possível desenvolver e implementar todas as funcionalidades propostas e ainda existem vários bugs a corrigir. Dos bugs encontrados, podemos destacar: - A caixa de pesquisa do Google Maps API deveria mover o marcador após redirecionar a câmara (o objecto marker parece estar definido como sendo privado e, por isso, não é possível aceder a este dentro da função codeAddress()); - A adição de novos comentários ou respostas provoca um problema na paginação dos comentários, obrigando a clicar em “Comentários anteriores” para aceder à informação.


Quanto a funcionalidades que não foram desenvolvidas podemos identificar:


Conclusões

O processo de desenvolvimento de uma aplicação Web baseada em 3 camadas é um processo muito demorado e complexo e, por isso, deverá ser iniciado o mais cedo possível (para não ficar quase tudo por fazer :p). Esta complexidade é fruto da maior liberdade que o utilizador tem neste tipo de plataforma e, por isso, obriga os “developers” a anteverem muitos erros e situações.

Embora não tenha sido tudo concluído, considero que também ficou muito trabalho feito e com um nível bastante satisfatório. Ambas as tecnologias abordadas na UC são muito gratificantes, quer pela sua versatilidade, quer pela sua vulgarização no mercado.


Referências bibliográficas

"W3Schools Online Web Tutorials", [1]
"Jquery", [2]
"GoogleMaps Api V3", [3]

Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox