K. Carpeta « php »

Versión para imprimir.

A. php / Bd.php

1
<?php
2
3
require_once __DIR__ . "/lib/rolBusca.php";
4
require_once __DIR__ . "/lib/rolAgrega.php";
5
6
class Bd
7
{
8
9
 private static ?PDO $pdo = null;
10
11
 static function pdo(): PDO
12
 {
13
  if (self::$pdo === null) {
14
15
   self::$pdo = new PDO(
16
    // cadena de conexión
17
    "sqlite:" . __DIR__ . "/srvamuchos.db",
18
    // usuario
19
    null,
20
    // contraseña
21
    null,
22
    // Opciones: pdos no persistentes y lanza excepciones.
23
    [PDO::ATTR_PERSISTENT => false, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
24
   );
25
26
   self::$pdo->exec(
27
    'CREATE TABLE IF NOT EXISTS USUARIO (
28
      USU_ID INTEGER,
29
      USU_SAN TEXT NOT NULL,
30
      CONSTRAINT USU_PK
31
       PRIMARY KEY(USU_ID),
32
      CONSTRAINT USU_SAN_UNQ
33
       UNIQUE(USU_SAN),
34
      CONSTRAINT USU_SAN_NV
35
       CHECK(LENGTH(USU_SAN) > 0)
36
     )'
37
   );
38
   self::$pdo->exec(
39
    'CREATE TABLE IF NOT EXISTS ROL (
40
      ROL_ID TEXT NOT NULL,
41
      ROL_DESCRIPCION TEXT NOT NULL,
42
      CONSTRAINT ROL_PK
43
       PRIMARY KEY(ROL_ID),
44
      CONSTRAINT ROL_ID_NV
45
       CHECK(LENGTH(ROL_ID) > 0),
46
      CONSTRAINT ROL_DESCR_UNQ
47
       UNIQUE(ROL_DESCRIPCION),
48
      CONSTRAINT ROL_DESCR_NV
49
       CHECK(LENGTH(ROL_DESCRIPCION) > 0)
50
     )'
51
   );
52
   self::$pdo->exec(
53
    'CREATE TABLE IF NOT EXISTS USU_ROL (
54
      USU_ID INTEGER NOT NULL,
55
      ROL_ID TEXT NOT NULL,
56
      CONSTRAINT USU_ROL_PK
57
       PRIMARY KEY(USU_ID, ROL_ID),
58
      CONSTRAINT USU_ROL_USU_FK
59
       FOREIGN KEY (USU_ID) REFERENCES USUARIO(USU_ID),
60
      CONSTRAINT USU_ROL_ROL_FK
61
       FOREIGN KEY (ROL_ID) REFERENCES ROL(ROL_ID)
62
     )'
63
   );
64
65
   self::$pdo->beginTransaction();
66
67
   if (rolBusca(self::$pdo, "Administrador") === false) {
68
    rolAgrega(
69
     bd: self::$pdo,
70
     id: "Administrador",
71
     descripcion: "Administra el sistema."
72
    );
73
   }
74
75
   if (rolBusca(self::$pdo, "Cliente") === false) {
76
    rolAgrega(
77
     bd: self::$pdo,
78
     id: "Cliente",
79
     descripcion: "Realiza compras."
80
    );
81
   }
82
83
   self::$pdo->commit();
84
  }
85
86
  return self::$pdo;
87
 }
88
}
89

B. php / rolCheckboxes.php

1
<?php
2
3
require_once __DIR__ . "/Bd.php";
4
5
function rolCheckboxes()
6
{
7
 $bd = Bd::pdo();
8
 $lista =
9
  $bd->query("SELECT * FROM ROL ORDER BY ROL_ID")->fetchAll(PDO::FETCH_ASSOC);
10
11
 $render = "<legend>Roles</legend>";
12
 foreach ($lista as $modelo) {
13
  $id = htmlentities($modelo["ROL_ID"]);
14
  $descripcion = htmlentities($modelo["ROL_DESCRIPCION"]);
15
  $render .=
16
   "<p>
17
    <label style='display: flex'>
18
     <input type='checkbox' name='rolIds[]' value='$id'>
19
     <span>
20
      <strong style='display: block'>$id</strong>
21
      $descripcion
22
     </span>
23
    </label>
24
   </p>";
25
 }
26
27
 return $render;
28
}
29

C. php / usuario-agrega.php

1
<?php
2
3
require_once __DIR__ . "/lib/manejaErrores.php";
4
require_once __DIR__ . "/lib/recibeTextoObligatorio.php";
5
require_once __DIR__ . "/lib/recibeArray.php";
6
require_once __DIR__ . "/lib/usuRolAgrega.php";
7
require_once __DIR__ . "/lib/devuelveCreated.php";
8
require_once __DIR__ . "/Bd.php";
9
require_once __DIR__ . "/rolCheckboxes.php";
10
11
$san = recibeTextoObligatorio("san");
12
$rolIds = recibeArray("rolIds");
13
14
$bd = Bd::pdo();
15
$bd->beginTransaction();
16
17
$stmt = $bd->prepare(
18
 "INSERT INTO USUARIO (
19
    USU_SAN
20
   ) values (
21
    :USU_SAN
22
   )"
23
);
24
$stmt->execute([
25
 ":USU_SAN" => $san
26
]);
27
$usuId = $bd->lastInsertId();
28
29
usuRolAgrega($bd, $usuId, $rolIds);
30
31
$bd->commit();
32
33
$encodeUsuId = urlencode($usuId);
34
devuelveCreated("/php/usuario-vista-modifica.php?id=$encodeUsuId", [
35
 "id" => ["value" => $usuId],
36
 "san" => ["value" => $san],
37
 "roles" => ["innerHTML" =>  rolCheckboxes()],
38
 "rolIds[]" => ["value" => $rolIds],
39
]);
40

D. php / usuario-elimina.php

1
<?php
2
3
require_once __DIR__ . "/lib/manejaErrores.php";
4
require_once __DIR__ . "/lib/recibeEnteroObligatorio.php";
5
require_once __DIR__ . "/lib/devuelveNoContent.php";
6
require_once __DIR__ . "/Bd.php";
7
require_once __DIR__ . "/usuRolElimina.php";
8
9
$usuId = recibeEnteroObligatorio("id");
10
11
$bd = Bd::pdo();
12
$bd->beginTransaction();
13
14
usuRolElimina($bd, $usuId);
15
16
$stmt = $bd->prepare("DELETE FROM USUARIO WHERE USU_ID = :USU_ID");
17
$stmt->execute([":USU_ID" => $usuId]);
18
19
$bd->commit();
20
21
devuelveNoContent();
22

E. php / usuario-modifica.php

1
<?php
2
3
require_once __DIR__ . "/lib/manejaErrores.php";
4
require_once __DIR__ . "/lib/recibeEnteroObligatorio.php";
5
require_once __DIR__ . "/lib/recibeTextoObligatorio.php";
6
require_once __DIR__ . "/lib/recibeArray.php";
7
require_once __DIR__ . "/lib/usuRolAgrega.php";
8
require_once __DIR__ . "/lib/devuelveJson.php";
9
require_once __DIR__ . "/Bd.php";
10
require_once __DIR__ . "/usuRolElimina.php";
11
require_once __DIR__ . "/rolCheckboxes.php";
12
13
$usuId = recibeEnteroObligatorio("id");
14
$san = recibeTextoObligatorio("san");
15
$rolIds = recibeArray("rolIds");
16
17
$bd = Bd::pdo();
18
$bd->beginTransaction();
19
20
$stmt = $bd->prepare(
21
 "UPDATE USUARIO
22
   SET
23
    USU_SAN = :USU_SAN
24
   WHERE
25
    USU_ID = :USU_ID"
26
);
27
$stmt->execute([
28
 ":USU_SAN" => $san,
29
 ":USU_ID" => $usuId,
30
]);
31
32
usuRolElimina($bd, $usuId);
33
34
usuRolAgrega($bd, $usuId, $rolIds);
35
36
$bd->commit();
37
38
devuelveJson([
39
 "id" => ["value" => $usuId],
40
 "san" => ["value" => $san],
41
 "roles" => ["innerHTML" =>  rolCheckboxes()],
42
 "rolIds" => ["value" => $rolIds],
43
]);
44

F. php / usuario-vista-agrega.php

1
<?php
2
3
require_once __DIR__ . "/lib/manejaErrores.php";
4
require_once __DIR__ . "/lib/devuelveJson.php";
5
require_once __DIR__ . "/rolCheckboxes.php";
6
7
devuelveJson(["roles" => ["innerHTML" =>  rolCheckboxes()]]);
8

G. php / usuario-vista-index.php

1
<?php
2
3
require_once __DIR__ . "/lib/manejaErrores.php";
4
require_once __DIR__ . "/lib/devuelveJson.php";
5
require_once __DIR__ . "/Bd.php";
6
7
$bd = Bd::pdo();
8
$stmt = $bd->query(
9
 "SELECT
10
    U.USU_ID,
11
    U.USU_SAN,
12
    GROUP_CONCAT(UR.ROL_ID, ', ') AS roles
13
   FROM
14
    USUARIO U LEFT JOIN USU_ROL UR
15
     ON U.USU_ID = UR.USU_ID
16
   GROUP BY
17
    U.USU_SAN
18
   ORDER BY
19
    U.USU_SAN"
20
);
21
$lista = $stmt->fetchAll(PDO::FETCH_ASSOC);
22
23
$render = "";
24
foreach ($lista as $modelo) {
25
 $encodeUsuId = urlencode($modelo["USU_ID"]);
26
 $usuId = htmlentities($encodeUsuId);
27
 $usuSan = htmlentities($modelo["USU_SAN"]);
28
 $roles = $modelo["roles"] === null || $modelo["roles"] === ""
29
  ? "<em>-- Sin roles --</em>"
30
  : htmlentities($modelo["roles"]);
31
 $render .=
32
  "<dt><a href='modifica.html?id=$usuId'>$usuSan</a></dt>
33
    <dd><a href='modifica.html?id=$usuId'>$roles</a></dd>";
34
}
35
36
devuelveJson(["lista" => ["innerHTML" => $render]]);
37

H. php / usuario-vista-modifica.php

1
<?php
2
3
require_once __DIR__ . "/lib/manejaErrores.php";
4
require_once __DIR__ . "/lib/recibeEnteroObligatorio.php";
5
require_once __DIR__ . "/lib/validaEntidadObligatoria.php";
6
require_once __DIR__ . "/lib/devuelveJson.php";
7
require_once __DIR__ . "/lib/rolIdsParaUsuId.php";
8
require_once __DIR__ . "/Bd.php";
9
require_once __DIR__ . "/rolCheckboxes.php";
10
11
$usuId = recibeEnteroObligatorio("id");
12
13
$bd = Bd::pdo();
14
15
$stmt = $bd->prepare("SELECT * FROM USUARIO WHERE USU_ID = :USU_ID");
16
$stmt->execute([":USU_ID" => $usuId]);
17
$modelo = $stmt->fetch(PDO::FETCH_ASSOC);
18
19
$modelo = validaEntidadObligatoria("Usuario",  $modelo);
20
21
$rolIds = rolIdsParaUsuId(Bd::pdo(), $usuId);
22
23
devuelveJson([
24
 "id" => ["value" => $usuId],
25
 "san" => ["value" => $modelo["USU_SAN"]],
26
 "roles" => ["innerHTML" =>  rolCheckboxes()],
27
 "rolIds[]" => $rolIds
28
]);
29

I. php / usuRolElimina.php

1
<?php
2
3
function usuRolElimina(\PDO $bd, string $usuId)
4
{
5
 $usuRolElimina = $bd->prepare("DELETE FROM USU_ROL WHERE USU_ID = :USU_ID");
6
 $usuRolElimina->execute([":USU_ID" => $usuId]);
7
}
8

J. Carpeta « php / lib »

Versión para imprimir.

1. php / lib / BAD_REQUEST.php

1
<?php
2
3
const BAD_REQUEST = 400;
4

2. php / lib / devuelveCreated.php

1
<?php
2
3
require_once __DIR__ . "/devuelveResultadoNoJson.php";
4
5
function devuelveCreated($urlDelNuevo, $resultado)
6
{
7
 $json = json_encode($resultado);
8
 if ($json === false) {
9
  devuelveResultadoNoJson();
10
 } else {
11
  http_response_code(201);
12
  header("Location: $urlDelNuevo");
13
  header("Content-Type: application/json; charset=utf-8");
14
  echo $json;
15
 }
16
}
17

3. php / lib / devuelveJson.php

1
<?php
2
3
require_once __DIR__ . "/devuelveResultadoNoJson.php";
4
5
function devuelveJson($resultado)
6
{
7
 $json = json_encode($resultado);
8
 if ($json === false) {
9
  devuelveResultadoNoJson();
10
 } else {
11
  header("Content-Type: application/json; charset=utf-8");
12
  echo $json;
13
 }
14
 exit();
15
}
16

4. php / lib / devuelveNoContent.php

1
<?php
2
3
function devuelveNoContent()
4
{
5
 http_response_code(204);
6
}
7

5. php / lib / devuelveResultadoNoJson.php

1
<?php
2
3
require_once __DIR__ . "/INTERNAL_SERVER_ERROR.php";
4
5
function devuelveResultadoNoJson()
6
{
7
 http_response_code(INTERNAL_SERVER_ERROR);
8
 header("Content-Type: application/problem+json; charset=utf-8");
9
10
 echo '{' .
11
  "status: " . INTERNAL_SERVER_ERROR .
12
  '"title": "El resultado no puede representarse como JSON."' .
13
  '"type": "/errors/resultadonojson.html"' .
14
  '}';
15
}
16

6. php / lib / INTERNAL_SERVER_ERROR.php

1
<?php
2
3
const INTERNAL_SERVER_ERROR = 500;

7. php / lib / manejaErrores.php

1
<?php
2
3
require_once __DIR__ . "/INTERNAL_SERVER_ERROR.php";
4
require_once __DIR__ . "/ProblemDetailsException.php";
5
6
// Hace que se lance una excepción automáticamente cuando se genere un error.
7
set_error_handler(function ($severity, $message, $file, $line) {
8
 throw new ErrorException($message, 0, $severity, $file, $line);
9
});
10
11
// Código cuando una excepción no es atrapada.
12
set_exception_handler(function (Throwable $excepcion) {
13
 if ($excepcion instanceof ProblemDetailsException) {
14
  devuelveProblemDetails($excepcion->problemDetails);
15
 } else {
16
  devuelveProblemDetails([
17
   "status" => INTERNAL_SERVER_ERROR,
18
   "title" => "Error interno del servidor",
19
   "detail" => $excepcion->getMessage(),
20
   "type" => "/errors/errorinterno.html",
21
  ]);
22
 }
23
 exit();
24
});
25
26
function devuelveProblemDetails(array $array)
27
{
28
 $json = json_encode($array);
29
 if ($json === false) {
30
  devuelveResultadoNoJson();
31
 } else {
32
  http_response_code(isset($array["status"]) ? $array["status"] : 500);
33
  header("Content-Type: application/problem+json; charset=utf-8");
34
  echo $json;
35
 }
36
}
37

8. php / lib / NOT_FOUND.php

1
<?php
2
3
const NOT_FOUND = 404;
4

9. php / lib / ProblemDetailsException.php

1
<?php
2
3
require_once __DIR__ . "/INTERNAL_SERVER_ERROR.php";
4
5
/**
6
 * Detalle de los errores devueltos por un servicio.
7
 */
8
class ProblemDetailsException extends Exception
9
{
10
11
 public array $problemDetails;
12
13
 public function __construct(
14
  array $problemDetails,
15
 ) {
16
  
17
  parent::__construct(
18
   isset($problemDetails["detail"])
19
    ? $problemDetails["detail"]
20
    : (isset($problemDetails["title"])
21
     ? $problemDetails["title"]
22
     : "Error"),
23
   $problemDetails["status"]
24
    ? $problemDetails["status"]
25
    : INTERNAL_SERVER_ERROR
26
  );
27
28
  $this->problemDetails = $problemDetails;
29
 }
30
}
31

10. php / lib / recibeArray.php

1
<?php
2
3
/**
4
 * Devuelve los valores asociados a un
5
 * parámetro multivaluado; por ejemplo, un
6
 * grupo de checkbox, recibido en el servidor
7
 * por medio de GET, POST o cookie.
8
 * 
9
 * Si no se recibe el parámetro, devuelve [].
10
 * 
11
 * Si el valor recibido no es un arreglo, lo
12
 * coloca dentro de uno.
13
 */
14
function recibeArray(string $parametro)
15
{
16
 if (isset($_REQUEST[$parametro])) {
17
  $valor = $_REQUEST[$parametro];
18
  return is_array($valor)
19
   ? $valor
20
   : [$valor];
21
 } else {
22
  return [];
23
 }
24
}
25

11. php / lib / recibeEntero.php

1
<?php
2
3
require_once __DIR__ . "/recibeTexto.php";
4
5
/**
6
 * Devuelve el valor entero de un parámetro recibido en el
7
 * servidor por medio de GET, POST o cookie.
8
 * 
9
 * Si el parámetro no se recibe, devuelve false
10
 *
11
 * Si se recibe una cadena vacía, se devuelve null.
12
 * 
13
 * Si parámetro no se puede convertir a entero, se genera
14
 * un error.
15
 */
16
function recibeEntero(string $parametro): false|null|int
17
{
18
 $valor = recibeTexto($parametro);
19
 if ($valor === false) {
20
  return false;
21
 } else {
22
  $valor = trim($valor);
23
  if ($valor === "") {
24
   return null;
25
  } else {
26
   return (int) $valor;
27
  }
28
 }
29
}
30

12. php / lib / recibeEnteroObligatorio.php

1
<?php
2
3
require_once __DIR__ . "/BAD_REQUEST.php";
4
require_once __DIR__ . "/recibeEntero.php";
5
require_once __DIR__ . "/ProblemDetailsException.php";
6
7
function recibeEnteroObligatorio(string $parametro)
8
{
9
 $entero = recibeEntero($parametro);
10
11
 if ($entero === false)
12
  throw new ProblemDetailsException([
13
   "status" => BAD_REQUEST,
14
   "title" => "Falta el valor $parametro.",
15
   "type" => "/errors/faltavalor.html",
16
   "detail" => "La solicitud no tiene el valor de $parametro."
17
  ]);
18
19
 if ($entero === null)
20
  throw new ProblemDetailsException([
21
   "status" => BAD_REQUEST,
22
   "title" => "Campo $parametro en blanco.",
23
   "type" => "/errors/campoenteroenblanco.html",
24
   "detail" => "Pon un número entero en el campo $parametro."
25
  ]);
26
27
 return $entero;
28
}
29

13. php / lib / recibeTexto.php

1
<?php
2
3
/**
4
 * Devuelve el texto de un parámetro enviado al
5
 * servidor por medio de GET, POST o cookie.
6
 * 
7
 * Si el parámetro no se recibe, devuelve false.
8
 */
9
function recibeTexto(string $parametro): false|string
10
{
11
 /* Si el parámetro está asignado en $_REQUEST,
12
  * devuelve su valor; de lo contrario, devuelve false.
13
  */
14
 $valor = isset($_REQUEST[$parametro])
15
  ? $_REQUEST[$parametro]
16
  : false;
17
 return $valor;
18
}
19

14. php / lib / recibeTextoObligatorio.php

1
<?php
2
3
require_once __DIR__ . "/BAD_REQUEST.php";
4
require_once __DIR__ . "/recibeTexto.php";
5
require_once __DIR__ . "/ProblemDetailsException.php";
6
7
function recibeTextoObligatorio(string $parametro)
8
{
9
 $texto = recibeTexto($parametro);
10
11
 if ($texto === false)
12
  throw new ProblemDetailsException([
13
   "status" => BAD_REQUEST,
14
   "title" => "Falta el valor $parametro.",
15
   "type" => "/errors/faltavalor.html",
16
   "detail" => "La solicitud no tiene el valor de $parametro."
17
  ]);
18
19
 $trimTexto = trim($texto);
20
21
 if ($trimTexto === "")
22
  throw new ProblemDetailsException([
23
   "status" => BAD_REQUEST,
24
   "title" => "Campo $parametro en blanco.",
25
   "type" => "/errors/campoenblanco.html",
26
   "detail" => "Pon texto en el campo $parametro."
27
  ]);
28
29
 return $trimTexto;
30
}
31

15. php / lib / rolAgrega.php

1
<?php
2
3
function rolAgrega(\PDO $bd, string $id, string $descripcion)
4
{
5
 $rolAgrega = $bd->prepare(
6
  "INSERT INTO ROL (
7
     ROL_ID, ROL_DESCRIPCION
8
    ) VALUES (
9
     :ROL_ID, :ROL_DESCRIPCION
10
    )"
11
 );
12
 $rolAgrega->execute([
13
  ":ROL_ID" => $id,
14
  ":ROL_DESCRIPCION" => $descripcion,
15
 ]);
16
}
17

16. php / lib / rolBusca.php

1
<?php
2
3
function rolBusca(\PDO $bd, string $id)
4
{
5
 $rolBusca =  $bd->prepare("SELECT * FROM ROL WHERE ROL_ID = :ROL_ID");
6
 $rolBusca->execute([":ROL_ID" => $id]);
7
 $rol = $rolBusca->fetch(PDO::FETCH_ASSOC);
8
 return $rol;
9
}
10

17. php / lib / rolIdsParaUsuId.php

1
<?php
2
3
function rolIdsParaUsuId(\PDO $bd, int $usuId)
4
{
5
 $stmt = $bd->prepare(
6
  "SELECT ROL_ID
7
   FROM USU_ROL
8
   WHERE USU_ID = :USU_ID
9
   ORDER BY USU_ID"
10
 );
11
 $stmt->execute([":USU_ID" => $usuId]);
12
 $rolIds = $stmt->fetchAll(PDO::FETCH_COLUMN, 0);
13
 return $rolIds;
14
}
15

18. php / lib / usuRolAgrega.php

1
<?php
2
3
function usuRolAgrega(\PDO $bd, string $usuId, array $rolIds)
4
{
5
 $usuRolAgrega = $bd->prepare(
6
  "INSERT INTO USU_ROL (USU_ID, ROL_ID) values (:USU_ID, :ROL_ID)"
7
 );
8
 foreach ($rolIds as $rolId) {
9
  $usuRolAgrega->execute([
10
   ":USU_ID" => $usuId,
11
   ":ROL_ID" => $rolId,
12
  ]);
13
 }
14
}
15

19. php / lib / validaEntidadObligatoria.php

1
<?php
2
3
require_once __DIR__ . "/NOT_FOUND.php";
4
require_once __DIR__ . "/ProblemDetailsException.php";
5
6
function validaEntidadObligatoria(string $nombre,  $entidad)
7
{
8
9
 if ($entidad === false)
10
  throw new ProblemDetailsException([
11
  "status" => NOT_FOUND,
12
  "title" => "Registro de $nombre no encontrado.",
13
  "type" => "/errors/entidadnoencontrada.html",
14
  "detail" => "No se encontró ningún registro de $nombre con el id solicitado.",
15
  ]);
16
17
 return $entidad;
18
}
19