1 | <?php |
2 | |
3 | function bdCrea(PDO $con) |
4 | { |
5 | $con->exec( |
6 | 'CREATE TABLE IF NOT EXISTS ARCHIVO ( |
7 | ARCH_ID INTEGER, |
8 | ARCH_BYTES BLOB NOT NULL, |
9 | CONSTRAINT ARCH_PK |
10 | PRIMARY KEY(ARCH_ID) |
11 | )' |
12 | ); |
13 | $con->exec( |
14 | 'CREATE TABLE IF NOT EXISTS PRODUCTO ( |
15 | PROD_ID INTEGER, |
16 | PROD_NOMBRE TEXT NOT NULL, |
17 | ARCH_ID INTEGER NOT NULL, |
18 | CONSTRAINT PROD_PK |
19 | PRIMARY KEY(PROD_ID), |
20 | CONSTRAINT PROD_NOM_UNQ |
21 | UNIQUE(PROD_NOMBRE) |
22 | CONSTRAINT PROD_ARCH_FK |
23 | FOREIGN KEY (ARCH_ID) REFERENCES ARCHIVO(ARCH_ID) |
24 | )' |
25 | ); |
26 | } |
27 |
1 | <?php |
2 | |
3 | require_once __DIR__ . "/bdCrea.php"; |
4 | |
5 | class Bd |
6 | { |
7 | |
8 | private static ?PDO $conexion = null; |
9 | |
10 | static function getConexion(): PDO |
11 | { |
12 | if (self::$conexion === null) { |
13 | |
14 | self::$conexion = new PDO( |
15 | // cadena de conexión |
16 | "sqlite:srvarchivos.db", |
17 | // usuario |
18 | null, |
19 | // contraseña |
20 | null, |
21 | // Opciones: conexiones persistentes y lanza excepciones. |
22 | [PDO::ATTR_PERSISTENT => true, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION] |
23 | ); |
24 | |
25 | bdCrea(self::$conexion); |
26 | } |
27 | |
28 | return self::$conexion; |
29 | } |
30 | } |
31 |
1 | <?php |
2 | |
3 | require_once __DIR__ . "/../modelo/Archivo.php"; |
4 | require_once __DIR__ . "/Bd.php"; |
5 | |
6 | function archivoAgrega(Archivo $modelo) |
7 | { |
8 | $modelo->valida(); |
9 | $con = Bd::getConexion(); |
10 | $stmt = $con->prepare( |
11 | "INSERT INTO ARCHIVO |
12 | (ARCH_BYTES) |
13 | VALUES |
14 | (:bytes)" |
15 | ); |
16 | $stmt->execute([ |
17 | ":bytes" => $modelo->bytes |
18 | ]); |
19 | /* Si usas una secuencia para generar el id, |
20 | * pasa como parámetro de lastInsertId el |
21 | * nombre de dicha secuencia, debes |
22 | * ejecutarlo antes del INSERT y pasarle el |
23 | * id generado al SQL. */ |
24 | $modelo->id = $con->lastInsertId(); |
25 | } |
26 |
1 | <?php |
2 | |
3 | require_once __DIR__ . "/../modelo/Archivo.php"; |
4 | require_once __DIR__ . "/Bd.php"; |
5 | |
6 | function archivoBusca(int $id): false|Archivo |
7 | { |
8 | $con = Bd::getConexion(); |
9 | $stmt = $con->prepare( |
10 | "SELECT |
11 | ARCH_ID AS id, |
12 | ARCH_BYTES AS bytes |
13 | FROM ARCHIVO |
14 | WHERE ARCH_ID = :id" |
15 | ); |
16 | $stmt->execute([":id" => $id]); |
17 | $stmt->setFetchMode( |
18 | PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, |
19 | Archivo::class |
20 | ); |
21 | return $stmt->fetch(); |
22 | } |
23 |
1 | <?php |
2 | |
3 | require_once __DIR__ . "/Bd.php"; |
4 | |
5 | function archivoElimina(int $id) |
6 | { |
7 | $con = Bd::getConexion(); |
8 | $stmt = $con->prepare( |
9 | "DELETE FROM ARCHIVO |
10 | WHERE ARCH_ID = :id" |
11 | ); |
12 | $stmt->execute([":id" => $id]); |
13 | } |
14 |
1 | <?php |
2 | |
3 | require_once __DIR__ . "/../modelo/Archivo.php"; |
4 | require_once __DIR__ . "/Bd.php"; |
5 | |
6 | function archivoModifica(Archivo $modelo) |
7 | { |
8 | $modelo->valida(); |
9 | $con = Bd::getConexion(); |
10 | $stmt = $con->prepare( |
11 | "UPDATE ARCHIVO |
12 | SET ARCH_BYTES = :bytes |
13 | WHERE ARCH_ID = :id" |
14 | ); |
15 | $stmt->execute([ |
16 | ":bytes" => $modelo->bytes, |
17 | ":id" => $modelo->id |
18 | ]); |
19 | } |
20 |
1 | <?php |
2 | |
3 | require_once __DIR__ . "/../modelo/Archivo.php"; |
4 | require_once __DIR__ . "/Bd.php"; |
5 | require_once __DIR__ . "/archivoAgrega.php"; |
6 | |
7 | function productoAgrega(Producto $modelo) |
8 | { |
9 | $modelo->validaNuevo(); |
10 | $con = Bd::getConexion(); |
11 | $con->beginTransaction(); |
12 | archivoAgrega($modelo->archivo); |
13 | $stmt = $con->prepare( |
14 | "INSERT INTO PRODUCTO |
15 | (PROD_NOMBRE, ARCH_ID) |
16 | VALUES |
17 | (:nombre, :archId)" |
18 | ); |
19 | $stmt->execute([ |
20 | ":nombre" => $modelo->nombre, |
21 | ":archId" => $modelo->archivo->id |
22 | ]); |
23 | /* Si usas una secuencia para generar el id, |
24 | * pasa como parámetro de lastInsertId el |
25 | * nombre de dicha secuencia, debes |
26 | * ejecutarlo antes del INSERT y pasarle el |
27 | * id generado al SQL. */ |
28 | $modelo->id = $con->lastInsertId(); |
29 | $con->commit(); |
30 | } |
31 |
1 | <?php |
2 | |
3 | require_once __DIR__ . "/../modelo/Archivo.php"; |
4 | require_once __DIR__ . "/../modelo/Producto.php"; |
5 | require_once __DIR__ . "/Bd.php"; |
6 | |
7 | function productoBusca(int $prodId) |
8 | { |
9 | $con = Bd::getConexion(); |
10 | $stmt = $con->prepare( |
11 | "SELECT |
12 | P.PROD_ID AS prodId, |
13 | P.PROD_NOMBRE AS prodNombre, |
14 | A.ARCH_ID AS archId |
15 | FROM PRODUCTO P |
16 | LEFT JOIN ARCHIVO A |
17 | ON P.ARCH_ID = A.ARCH_ID |
18 | WHERE P.PROD_ID = :prodId" |
19 | ); |
20 | $stmt->execute([ |
21 | ":prodId" => $prodId |
22 | ]); |
23 | $stmt->setFetchMode(PDO::FETCH_OBJ); |
24 | $obj = $stmt->fetch(); |
25 | if ($obj === false) { |
26 | return false; |
27 | } else { |
28 | $id = $obj->prodId; |
29 | $nombre = $obj->prodNombre; |
30 | $archId = $obj->archId; |
31 | $archivo = $archId === null ? null : new Archivo(id: $archId); |
32 | $producto = new Producto( |
33 | id: $id, |
34 | nombre: $nombre, |
35 | archivo: $archivo |
36 | ); |
37 | return $producto; |
38 | } |
39 | } |
40 |
1 | <?php |
2 | |
3 | require_once __DIR__ . "/../../lib/php/recibeFetchAll.php"; |
4 | require_once __DIR__ . "/../modelo/Producto.php"; |
5 | require_once __DIR__ . "/Bd.php"; |
6 | |
7 | function productoConsulta() |
8 | { |
9 | $con = Bd::getConexion(); |
10 | $stmt = $con->query( |
11 | "SELECT |
12 | P.PROD_ID AS prodId, |
13 | P.PROD_NOMBRE AS prodNombre, |
14 | A.ARCH_ID AS archId |
15 | FROM PRODUCTO P |
16 | LEFT JOIN ARCHIVO A |
17 | ON P.ARCH_ID = A.ARCH_ID |
18 | ORDER BY P.PROD_NOMBRE" |
19 | ); |
20 | $resultado = $stmt->fetchAll(PDO::FETCH_OBJ); |
21 | return recibeFetchAll($resultado); |
22 | } |
23 |
1 | <?php |
2 | |
3 | require_once __DIR__ . "/Bd.php"; |
4 | require_once __DIR__ . "/archivoElimina.php"; |
5 | require_once __DIR__ . "/productoBusca.php"; |
6 | |
7 | function productoElimina(int $id) |
8 | { |
9 | $con = Bd::getConexion(); |
10 | $con->beginTransaction(); |
11 | $modelo = productoBusca($id); |
12 | if ($modelo === false) { |
13 | $con->rollBack(); |
14 | } else { |
15 | archivoElimina($modelo->archivo->id); |
16 | $stmt = $con->prepare( |
17 | "DELETE FROM PRODUCTO |
18 | WHERE PROD_ID = :id" |
19 | ); |
20 | $stmt->execute([":id" => $modelo->id]); |
21 | $con->commit(); |
22 | } |
23 | } |
24 |
1 | <?php |
2 | |
3 | require_once __DIR__ . "/../modelo/Producto.php"; |
4 | require_once __DIR__ . "/Bd.php"; |
5 | require_once __DIR__ . "/productoBusca.php"; |
6 | require_once __DIR__ . "/archivoModifica.php"; |
7 | |
8 | function productoModifica(Producto $modelo) |
9 | { |
10 | $modelo->valida(); |
11 | $con = Bd::getConexion(); |
12 | $con->beginTransaction(); |
13 | $archivo = $modelo->archivo; |
14 | $anterior = productoBusca($modelo->id); |
15 | if ($anterior === false) { |
16 | throw new Exception("Producto no encontrado."); |
17 | } |
18 | if ($anterior->archivo === null) { |
19 | throw new Exception("Falta el archivo anterior."); |
20 | } |
21 | if ($archivo === null) { |
22 | $archivo = $anterior->archivo; |
23 | $modelo->archivo = $archivo; |
24 | } else { |
25 | $archivo->id = $anterior->archivo->id; |
26 | archivoModifica($archivo); |
27 | } |
28 | $stmt = $con->prepare( |
29 | "UPDATE PRODUCTO |
30 | SET |
31 | PROD_NOMBRE = :nombre, |
32 | ARCH_ID = :archId |
33 | WHERE PROD_ID = :id" |
34 | ); |
35 | $stmt->execute([ |
36 | ":id" => $modelo->id, |
37 | ":nombre" => $modelo->nombre, |
38 | ":archId" => $archivo->id |
39 | ]); |
40 | $con->commit(); |
41 | } |
42 |