[TUTORIAL] Organização do teu projecto web

wowmiguelfcp

Power Member
Boas malta.

Este tópico serve de auxilio à malta que faz projectos web com dimensão já considerável. Aprendi esta estrutura durante o meu tempo de faculdade e acho que pode ser útil para vocês também.

Com esta estrutura, o teu código será organizado por categorias e será mais fácil a detecção de erros, como também o código terá um visual mais apelativo.


Sendo assim, espero que com isto vos dê ideias e que vos ajude em futuros projectos :)


Aqui vai uma imagem daquilo que irá o ser projecto:

Sem_T_tulo.png



Agora a explicação para cada uma das pastas:

  • Actions: Aqui é para onde vão os ficheiros .php que não produzem conteúdo visível mas que irão desempenhar alguma acção na base de dados. Exemplo de código pode ver-se já de seguida. De realçar que algum código presente poderá fazer mais sentido no final do tutorial.
Código:
<?php
  include_once('../../config/init.php');
  include_once($BASE_DIR .'database/users.php');  

  if (!$_POST['username'] || !$_POST['realname'] || !$_POST['password']) {
    $_SESSION['error_messages'][] = 'All fields are mandatory';
    $_SESSION['form_values'] = $_POST;
    header("Location: $BASE_URL" . 'pages/users/register.php');
    exit;
  }

  $realname = strip_tags($_POST['realname']);
  $username = strip_tags($_POST['username']);
  $password = $_POST['password'];

  $photo = $_FILES['photo'];
  $extension = end(explode(".", $photo["name"]));

  try {
    createUser($realname, $username, $password);
    move_uploaded_file($photo["tmp_name"], $BASE_DIR . "images/users/" . $username . '.' . $extension); // this is dangerous
    chmod($BASE_DIR . "images/users/" . $username . '.' . $extension, 0644);
  } catch (PDOException $e) {
    if (strpos($e->getMessage(), 'users_pkey') !== false) {
      $_SESSION['error_messages'][] = 'Duplicate username';
      $_SESSION['field_errors']['username'] = 'Username already exists';
    }
    else $_SESSION['error_messages'][] = 'Error creating user';

    $_SESSION['form_values'] = $_POST;
    header("Location: $BASE_URL" . 'pages/users/register.php');
    exit;
  }
  $_SESSION['success_messages'][] = 'User registered successfully';  
  header("Location: $BASE_URL");
?>


  • API: aqui vai o código que desempenha funções de comunicação com o programa (requisição e resposta HTTP). A maior parte de vocês não deverá precisar disto provavelmente.

  • Config: aqui vai o ficheiro de configuração. Aqui configuramos os cookies, os directórios, smarty e ligação à base de dados:
Código:
<?php
  session_set_cookie_params(3600, '...');
  session_start();

  $BASE_DIR = '...';
  $BASE_URL = '...';

  $conn = new PDO('pgsql:host=vdbm;dbname=exemplosiem', 'exemplosiem', 'password');
  $conn->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
  $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

  include_once($BASE_DIR . 'lib/smarty/Smarty.class.php');
  $smarty = new Smarty;
  $smarty->template_dir = $BASE_DIR . 'templates/';
  $smarty->compile_dir = $BASE_DIR . 'templates_c/';
  $smarty->assign('BASE_URL', $BASE_URL);
  $smarty->assign('ERROR_MESSAGES', $_SESSION['error_messages']);  
  $smarty->assign('FIELD_ERRORS', $_SESSION['field_errors']);
  $smarty->assign('SUCCESS_MESSAGES', $_SESSION['success_messages']);
  $smarty->assign('FORM_VALUES', $_SESSION['form_values']);
  $smarty->assign('USERNAME', $_SESSION['username']);
  unset($_SESSION['success_messages']);
  unset($_SESSION['error_messages']);  
  unset($_SESSION['field_errors']);
  unset($_SESSION['form_values']);
?>


  • CSS: Aqui fica o ficheiro de CSS

  • Database: Aqui vão os ficheiros .php que têm as funções de query à base de dados. Exemplo:
Código:
<?php
  function createUser($realname, $username, $password) {
    global $conn;
    $stmt = $conn->prepare("INSERT INTO users VALUES (?, ?, ?)");
    $stmt->execute(array($realname, $username, sha1($password)));
  }
?>


  • Imagens: Aqui é para onde vão as imagens que se usa nas web pages

  • Javascript: Aqui temos o ficheiro main.js onde ficará todas as nossas funções de javascript

  • lib: Esta pasta contém a pasta smarty (php template engine) que pode ser descarregada aqui

  • Pages: Para aqui vão os nossos ficheiros .php que irão apresentar as páginas no browser. Por outras palavras, sempre que quiserem apresentar o ficheiro a um utilizador, são estes ficheiros que terão de ser encaminhados pelo servidor ao cliente. O código consiste apenas nisto:
Código:
<?php
  include_once('../../config/init.php');
  include_once($BASE_DIR .'database/tweets.php');

  if (!$_GET['username']) {
    $_SESSION['error_messages'][] = 'Undefined username';
    header("Location: $BASE_URL");
    exit;
  }
  $username = $_GET['username'];
  $tweets = getUserTweets($username);  
  foreach ($tweets as $key => $tweet) {
    unset($photo);
    if (file_exists($BASE_DIR.'images/users/'.$tweet['username'].'.png'))
      $photo = 'images/users/'.$tweet['username'].'.png';
    if (file_exists($BASE_DIR.'images/users/'.$tweet['username'].'.jpg'))
      $photo = 'images/users/'.$tweet['username'].'.jpg';
    if (!$photo) $photo = 'images/assets/default.png';
    $tweets[$key]['photo'] = $photo;
  }

  
  $smarty->assign('tweets', $tweets);
  $smarty->display('tweets/list.tpl');
?>

Se a página que querem apresentar não tiver nenhum conteúdo acedido à base de dados, basta apenas por os seguintes itens:

Código:
<?php
  include_once('../../config/init.php');
  $smarty->display('users/register.tpl');
?>

O $smarty->display('users/register.tpl'); serve para apresentar o conteúdo HTML que está num template smarty, que veremos em seguida.


  • Templates: aqui vão os templates smarty como disse em cima. Esta pasta é subdivida em duas principais:
    • Common: Que fica os ficheiros header.tpl e footer.tpl:
Header.tpl

Código:
<!DOCTYPE html>
<html>
  <head>
    <title>......</title>
    <meta charset='utf-8'>
    <link rel="stylesheet" href="{$BASE_URL}/css/style.css">
    <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
    <script src="{$BASE_URL}javascript/main.js"></script>
  </head>
  <body>
    <header>
     ..........
    </header>

    <div id="error_messages">
    {foreach $ERROR_MESSAGES as $error}
      <div class="error">{$error}<a class="close" href="#">X</a></div>
    {/foreach}
    </div>
    <div id="success_messages">
    {foreach $SUCCESS_MESSAGES as $success}
      <div class="success">{$success}<a class="close" href="#">X</a></div>
    {/foreach}
    </div>

Footer.tpl:

Código:
  </body>
</html>


  • Pages: aqui estão os templates smarty para as páginas que iremos apresentar. São programados em HTML e seguem a seguinte estrutura:
Código:
{include file='common/header.tpl'}

<section id="register">
  <h2>Register</h2>

  <form action="{$BASE_URL}actions/users/register.php" method="post" enctype="multipart/form-data">
    <label>Name:<br> 
      <input type="text" name="realname" value="{$FORM_VALUES.realname}"> 
      <span class="field_error">{$FIELD_ERRORS.username}</span>
    </label>
    <br>
    <label>Username:<br> 
      <input type="text" name="username" value="{$FORM_VALUES.username}">
    </label>
    <br>
    <label>Password:<br> 
      <input type="password" name="password" value="">
    </label>
    <br>
    <label>Photo:<br>
      <input type="file" name="photo">
    </label>
    <input type="submit" value="Register">
  </form>

</section>

{include file='common/footer.tpl'}

O código exemplo penso que seja auto explicativo mas qualquer dúvida é só postarem ;)


  • templates_c: Aqui a gente não faz nada, cria a pasta e fica quieto. Esta pasta é para onde vão os ficheiros template compilados quando são invocados pelo utilizador. Basta ter a pasta e não se faz mais nada.


  • Index.php: Serve apenas para não fornecermos um link gigante e feio ao utilizador. O ficheiro redirecciona o utilizador para onde queremos.
Código:
<?php
  header('Location: pages/tweets/list_all.php');
?>



Bem espero que este tutorial vos sirva de ajuda e qualquer dúvida que tenham chutem à vontade :)

Cumprimentos
 
O meu projeto web, e o de muitos, tem uma pasta de development (src) e uma pasta da build para produção. Até porque muita coisa do que faço em development tem de ser compilado para produção.
 
Projetos php? Por exemplo?
É que aqui tenho por exemplo o minify do js e css.. o less etc.. mas ele gera o ficheiros na mesma pasta.. se não só em regras do htacess/rotas era quase um mega script :P
(eu não uso esta forma, mas sim os principios base de mvc.. app/web.. app logica.. web o que é publico)
 
Projetos php? Por exemplo?
É que aqui tenho por exemplo o minify do js e css.. o less etc.. mas ele gera o ficheiros na mesma pasta.. se não só em regras do htacess/rotas era quase um mega script :P
(eu não uso esta forma, mas sim os principios base de mvc.. app/web.. app logica.. web o que é publico)

Por projectos php digo páginas web com base de dados incluídas e código javascript. Ou até somente páginas puramente HTML, esta estrutura também ajuda para esses casos. Evita-se repetição de código.
 
Projetos php? Por exemplo?
É que aqui tenho por exemplo o minify do js e css.. o less etc.. mas ele gera o ficheiros na mesma pasta.. se não só em regras do htacess/rotas era quase um mega script :P
(eu não uso esta forma, mas sim os principios base de mvc.. app/web.. app logica.. web o que é publico)
Não. Mas ele está a fazer um tutorial para projetos web. Podia ser mais especifico e dizer para o que é.
 
Não. Mas ele está a fazer um tutorial para projetos web. Podia ser mais especifico e dizer para o que é.

já o disse no post acima do teu.
Esta proposta de organização podes usar no que tu quiseres basicamente.

Tens apenas páginas visuais? Podes seguir isto.
Tens páginas com ligação à BD? Melhor ainda.

Tu depois adaptas isto à tua maneira. Eu apenas quis dar uma ajuda à malta. Isto já me ajudou e muito.
 
O meu projeto web, e o de muitos, tem uma pasta de development (src) e uma pasta da build para produção. Até porque muita coisa do que faço em development tem de ser compilado para produção.

+1.
Isto é fundamental em qualquer projeto que não seja trivial.
Tens de ter um diretório de source e outro onde vai estar o CSS e imagens minificadas, o bundle de JS, etc...
 
Nos dias de hoje tenta-se evitar esse tipo de estrutura porque não é segura, é melhor ter o public num nível diferente do resto, para as pessoas apenas acederem ao que é publico (imagens, css, javascript), tudo o que é de programação e base de dados está num nível abaixo não acessível pelo utilizador.

Recomendaria usarem uma framework em vez de tentarem perceber essa estrutura, dou o exemplo da Laravel, das mais usadas, fácil de usar, documentação mediana, segurança mediana, e a instalação também não é difícil, e ficam logo com uma estrutura MVC pronta a usar (além de já ter login e tokens csrf).
 
Back
Topo