M. Carpeta « srv »

Versión para imprimir.

A. srv / sincroniza.php

1<?php
2
3require_once __DIR__ . "/../lib/php/ejecutaServicio.php";
4require_once __DIR__ . "/../lib/php/recuperaJson.php";
5require_once __DIR__ . "/../lib/php/devuelveJson.php";
6require_once __DIR__ . "/../lib/php/ProblemDetails.php";
7require_once __DIR__ . "/../lib/php/devuelveProblemDetails.php";
8require_once __DIR__ . "/../lib/php/devuelveErrorInterno.php";
9require_once __DIR__ . "/modelo/TABLA_PASATIEMPO.php";
10require_once __DIR__ . "/modelo/validaPasatiempo.php";
11require_once __DIR__ . "/bd/pasatiempoAgrega.php";
12require_once __DIR__ . "/bd/pasatiempoBusca.php";
13require_once __DIR__ . "/bd/pasatiempoConsultaNoEliminados.php";
14require_once __DIR__ . "/bd/pasatiempoModifica.php";
15
16ejecutaServicio(function () {
17
18 $lista = recuperaJson();
19
20 if (!is_array($lista)) {
21 $lista = [];
22 }
23
24 foreach ($lista as $modelo) {
25 $modeloEnElCliente = validaPasatiempo($modelo);
26 $modeloEnElServidor = pasatiempoBusca($modeloEnElCliente[PAS_ID]);
27
28 if ($modeloEnElServidor === false) {
29
30 /* CONFLICTO: El modelo no ha estado en el servidor.
31 * AGREGARLO solamente si no está eliminado. */
32 if ($modeloEnElCliente[PAS_ELIMINADO] === 0) {
33 pasatiempoAgrega($modeloEnElCliente);
34 }
35 } elseif (
36 $modeloEnElServidor[PAS_ELIMINADO] === 0
37 && $modeloEnElCliente[PAS_ELIMINADO] === 1
38 ) {
39
40 /* CONFLICTO: El registro está en el servidor, donde no se ha eliminado, pero
41 * ha sido eliminado en el cliente.
42 * Gana el cliente, porque optamos por no revivir lo eliminado. */
43 pasatiempoModifica($modeloEnElCliente);
44 } else if (
45 $modeloEnElCliente[PAS_ELIMINADO] === 0
46 && $modeloEnElServidor[PAS_ELIMINADO] === 0
47 ) {
48
49 /* CONFLICTO: Registros en el servidor y en el cliente. Pueden ser
50 * diferentes.
51 * GANA FECHA MÁS GRANDE. Cuando gana el servidor, no se hace nada. */
52 if (
53 $modeloEnElCliente[PAS_MODIFICACION] >
54 $modeloEnElServidor[PAS_MODIFICACION]
55 ) {
56 // La versión del cliente es más nueva y prevalece.
57 pasatiempoModifica($modeloEnElCliente);
58 }
59 }
60 }
61
62 $lista = pasatiempoConsultaNoEliminados();
63
64 devuelveJson($lista);
65});
66

B. Carpeta « srv / bd »

Versión para imprimir.

1. srv / bd / Bd.php

1<?php
2
3class Bd
4{
5
6 private static ?PDO $pdo = null;
7
8 static function pdo(): PDO
9 {
10 if (self::$pdo === null) {
11 self::$pdo = new PDO(
12 // cadena de conexión
13 "sqlite:sincronizacion.db",
14 // usuario
15 null,
16 // contraseña
17 null,
18 // Opciones: pdos no persistentes y lanza excepciones.
19 [PDO::ATTR_PERSISTENT => false, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
20 );
21
22 self::$pdo->exec(
23 'CREATE TABLE IF NOT EXISTS PASATIEMPO (
24 PAS_ID TEXT NOT NULL,
25 PAS_NOMBRE TEXT NOT NULL,
26 PAS_MODIFICACION INTEGER NOT NULL,
27 PAS_ELIMINADO INTEGER NOT NULL,
28 CONSTRAINT PAS_PK
29 PRIMARY KEY(PAS_ID),
30 CONSTRAINT PAS_ID_NV
31 CHECK(LENGTH(PAS_ID) > 0),
32 CONSTRAINT PAS_NOM_NV
33 CHECK(LENGTH(PAS_NOMBRE) > 0)
34 )'
35 );
36 }
37
38 return self::$pdo;
39 }
40}
41

2. srv / bd / pasatiempoAgrega.php

1<?php
2
3require_once __DIR__ . "/../../lib/php/validaNombre.php";
4require_once __DIR__ . "/../../lib/php/insert.php";
5require_once __DIR__ . "/Bd.php";
6require_once __DIR__ . "/../modelo/TABLA_PASATIEMPO.php";
7require_once __DIR__ . "/../modelo/validaId.php";
8
9/**
10 * @param array{
11 * PAS_ID: string,
12 * PAS_NOMBRE: string,
13 * PAS_MODIFICACION: int,
14 * PAS_ELIMINADO: int
15 * } $modelo
16 */
17function pasatiempoAgrega(array $modelo)
18{
19 validaId($modelo[PAS_ID]);
20 validaNombre($modelo[PAS_NOMBRE]);
21 insert(pdo: Bd::pdo(), into: PASATIEMPO, values: $modelo);
22}
23

3. srv / bd / pasatiempoBusca.php

1<?php
2
3require_once __DIR__ . "/../../lib/php/selectFirst.php";
4require_once __DIR__ . "/Bd.php";
5require_once __DIR__ . "/../modelo/TABLA_PASATIEMPO.php";
6
7/**
8 * @return false | array{
9 * PAS_ID: string,
10 * PAS_NOMBRE: string,
11 * PAS_MODIFICACION: int,
12 * PAS_ELIMINADO: int
13 * }
14 */
15function pasatiempoBusca(string $id): false|array
16{
17 return selectFirst(
18 pdo: Bd::pdo(),
19 from: PASATIEMPO,
20 where: [PAS_ID => $id]
21 );
22}
23

4. srv / bd / pasatiempoConsultaNoEliminados.php

1<?php
2
3require_once __DIR__ . "/../../lib/php/select.php";
4require_once __DIR__ . "/Bd.php";
5require_once __DIR__ . "/../modelo/TABLA_PASATIEMPO.php";
6
7/**
8 * @return array{
9 * PAS_ID: string,
10 * PAS_NOMBRE: string,
11 * PAS_MODIFICACION: int,
12 * PAS_ELIMINADO: int
13 * }[]
14 */
15function pasatiempoConsultaNoEliminados()
16{
17 return select(
18 pdo: Bd::pdo(),
19 from: PASATIEMPO,
20 where: [PAS_ELIMINADO => 0],
21 orderBy: PAS_NOMBRE
22 );
23}
24

5. srv / bd / pasatiempoModifica.php

1<?php
2
3require_once __DIR__ . "/../../lib/php/validaNombre.php";
4require_once __DIR__ . "/../../lib/php/update.php";
5require_once __DIR__ . "/Bd.php";
6require_once __DIR__ . "/../modelo/TABLA_PASATIEMPO.php";
7require_once __DIR__ . "/../modelo/validaId.php";
8
9/**
10 * @param array{
11 * PAS_ID: string,
12 * PAS_NOMBRE: string,
13 * PAS_MODIFICACION: int,
14 * PAS_ELIMINADO: int
15 * } $modelo
16 */
17function pasatiempoModifica(array $modelo)
18{
19 validaId($modelo[PAS_ID]);
20 validaNombre($modelo[PAS_NOMBRE]);
21 update(
22 pdo: Bd::pdo(),
23 table: PASATIEMPO,
24 set: $modelo,
25 where: [PAS_ID => $modelo[PAS_ID]]
26 );
27}
28

C. Carpeta « srv / modelo »

Versión para imprimir.

1. srv / modelo / TABLA_PASATIEMPO.php

1<?php
2
3const PASATIEMPO = "PASATIEMPO";
4const PAS_ID = "PAS_ID";
5const PAS_NOMBRE = "PAS_NOMBRE";
6const PAS_MODIFICACION = "PAS_MODIFICACION";
7const PAS_ELIMINADO = "PAS_ELIMINADO";
8

2. srv / modelo / validaId.php

1<?php
2
3function validaId(string $id)
4{
5 if ($id === "")
6 throw new ProblemDetails(
7 status: BAD_REQUEST,
8 title: "Falta el id.",
9 type: "/error/faltaid.html",
10 );
11}
12

3. srv / modelo / validaPasatiempo.php

1<?php
2
3require_once __DIR__ . "/../../lib/php/BAD_REQUEST.php";
4require_once __DIR__ . "/../../lib/php/validaJson.php";
5require_once __DIR__ . "/../../lib/php/ProblemDetails.php";
6require_once __DIR__ . "/TABLA_PASATIEMPO.php";
7
8function validaPasatiempo($objeto)
9{
10
11 $objeto = validaJson($objeto);
12
13 if (!isset($objeto->PAS_ID) || !is_string($objeto->PAS_ID))
14 throw new ProblemDetails(
15 status: BAD_REQUEST,
16 title: "El id debe ser texto.",
17 type: "/error/idincorrecto.html",
18 );
19
20 if (!isset($objeto->PAS_NOMBRE) || !is_string($objeto->PAS_NOMBRE))
21 throw new ProblemDetails(
22 status: BAD_REQUEST,
23 title: "El nombre debe ser texto.",
24 type: "/error/nombreincorrecto.html",
25 );
26
27 if (!isset($objeto->PAS_MODIFICACION) || !is_int($objeto->PAS_MODIFICACION))
28 throw new ProblemDetails(
29 status: BAD_REQUEST,
30 title: "La modificacion debe ser número.",
31 type: "/error/modificacionincorrecta.html",
32 );
33
34 if (!isset($objeto->PAS_ELIMINADO) || !is_int($objeto->PAS_ELIMINADO))
35 throw new ProblemDetails(
36 status: BAD_REQUEST,
37 title: "El campo eliminado debe ser entero.",
38 type: "/error/eliminadoincorrecto.html",
39 );
40
41 return [
42 PAS_ID => $objeto->PAS_ID,
43 PAS_NOMBRE => $objeto->PAS_NOMBRE,
44 PAS_MODIFICACION => $objeto->PAS_MODIFICACION,
45 PAS_ELIMINADO => $objeto->PAS_ELIMINADO
46 ];
47}
48