DAI-C8-EC: PHP i Postgres

De Wikijoan
Dreceres ràpides: navegació, cerca

Contingut

Objectius

Unitat Didàctica: UD 8. PHP i Accés a Dades

En una pràctica anterior has treballat sobre els procediments inserir_servei, inserir_detall_servei, calcular_servei, mostra_servei, resum_cambrer, informe_mensual. Es tracta de fer una aplicació mínima PHP que implementi les funcions bàsiques d'un restaurant: el cambrer pren nota d'una taula, es calcula cada taula quan ha de pagar, i es dóna un informe de què han de cobrar els cambrers.

Desenvolupament

Pots veure un exemple del funcionament de la pràctica a

http://192.168.0.10/ec/restaurant/postgresql/

Aquesta és una pràctica acadèmica, on no s'ha tingut en compte el disseny ni la usabilitat, per tal de centrar-nos en el que ens interessa, que és l'execució de procediments emmagatzemats des de PHP. D'aquesta manera, aconseguim ficar les regles del negoci dins la base de dades (les línies de codi PHP són menys, augmenta el codi pl/sql).

La particularitat dels tres últims informes és que són procediments que elaboren un informe on la sortida són línies DBMS_OUTPUT.PUT_LINE. El que s'explica més avall és la manera com aquest buffer de sortida es pot visualitzar des de PHP.

Si és necessari, el professor facilitarà el codi per tal de què els alumnes puguin avançar. Al final de la pràctica es donarà la solució.

Els alumnes poden treballar en local o en remot.

Configuració de EasyPHP i Postgres (usuaris Windows)

Per connectar-se a una base de dades Postgres des de PHP han d'estar habilitades les extensions de Postgres, que per defecte no ho estan. La manera de fer-ho seria (Pau Pérez):

Mirant la documentació de PHP (http://www.php.net/manual/en/pgsql.installation.php) he trobat una possible solució als problemes d'instalació del pgsql.dll.

";extension=php_pgsql.dll"

(treure el ; del davant) de l'arxiu de configuració de PHP (php.ini)

LoadFile "C:/Archivos de programa/PostgreSQL/9.0/bin/libpq.dll"

(amb la ruta correcta per a cada cas de la teva instal.lació del Postgres, evidentment).

En algun cas s'ha hagut de descomentar la linia següent del php.ini (a més de la ja comentada).

;extension=php_pdo_pgsql.dll

Com treballar en el servidor 192.168.0.10

Per fer una pàgina web en el servidor:

entres al servidor via SSH:

$ ssh dai2aXX@192.168.0.10 (o amb Putty)
$ cd /var/www/alumnes/dai2aXX (aquest és el teu espai, amb permisos d'escriptura)(no cal fer-ho, ja estàs aquí)

Per fer una prova, crea el fitxer hola.htm (o hola.php)

http://192.168.0.10/alumnes/dai2aXX/hola.htm

També pots enviar els fitxers via FTP:

Per entrar al PostgreSQL del servidor dins del servidor:

$ psql -h localhost -p 5432 -U dai2aXX -d dai2aXX
dai2aXX# \i script_examen.sql

Per entrar al PostgreSQL del servidor des de la teva màquina:

C:/Archiv.../psql.exe -h 192.168.0.10 -p 5432 -U dai2aXX -d dai2aXX
dai2aXX# \i C:/examen_EC/script_examen.sql (psql s'està executant en la teva màquina local!! (Windows o el que sigui)

Entrega

Recursos

-- inserir_servei(id_cambrer,id_taula): ha d'inserir un registre en la taula servei, amb la data del sistema. El preu es deixa NULL (es calcularà a posteriori). El valor id_servei s'agafa a partir de la seqüència corresponent. És el procediment que s'executa quan el cambrer comença a prendre nota a una taula.
-- inserir_detall_servei(id_servei,id_plat,quantitat): insereix un registre en la taula DETALL_SERVEI. És el procediment que s'executa quan el cambrer pren nota de què menjaran els comensals.
-- calcular_servei(id_servei): s'executa quan hem de generar el ticket, per saber quan ha de pagar la taula pel servei. S'ha de fer un UPDATE de SERVEI.preu
-- mostra_servei(id_servei): mostrar tots els plats que s'han de servir a la taula (de l'últim servei que s'ha demanat en aquesta taula)
-- resum_cambrer(id_cambrer,dia): mostrar un informe de tots els serveis que ha fet un cambrer en un dia. Informar de què ha facturat a cada servei, i el total del dia.
-- informe_mensual(mes,any): per al mes indicat, fer un informe del que han facturat tots els cambrers, ordenats de major a menor. 


CREATE OR REPLACE FUNCTION inserir_servei(v_id_cambrer integer, v_id_taula integer) RETURNS integer AS $$
DECLARE
   vid_cambrer CAMBRER.id_cambrer%TYPE;
   vid_taula TAULA.id_taula%TYPE;
	vid_servei SERVEI.id_servei%TYPE;
BEGIN
   SELECT id_cambrer into vid_cambrer FROM CAMBRER WHERE id_cambrer=v_id_cambrer;
   SELECT id_taula into vid_taula FROM TAULA WHERE id_taula=v_id_taula;
   INSERT INTO SERVEI VALUES(nextval('seq_servei'),v_id_cambrer,v_id_taula,now(),NULL);
   SELECT currval('seq_servei') INTO vid_servei;
	RETURN vid_servei;
END;
$$ LANGUAGE plpgsql;


CREATE OR REPLACE FUNCTION inserir_detall_servei(v_id_servei integer, v_id_plat integer,v_quantitat integer) RETURNS VOID AS $$
DECLARE
   vid_servei SERVEI.id_servei%TYPE;
   vid_plat CARTA.id_plat%TYPE;
   vquantitat DETALL_SERVEI.quantitat%TYPE;
BEGIN
   IF (v_quantitat<1) THEN 
      raise exception 'quantitat negativa';
   END IF;
   SELECT id_servei into vid_servei FROM SERVEI WHERE id_servei=v_id_servei;
	IF NOT FOUND THEN
		raise exception 'servei no trobat';
	END IF;
   SELECT id_plat into vid_plat FROM CARTA WHERE id_plat=v_id_plat;
	IF NOT FOUND THEN
		raise exception 'plat no trobat';
	END IF;
   INSERT INTO DETALL_SERVEI VALUES(v_id_servei,v_id_plat,v_quantitat);
END;
$$ LANGUAGE plpgsql;


CREATE OR REPLACE FUNCTION calcular_servei(v_id_servei integer) RETURNS real AS $$
DECLARE
   vid_servei SERVEI.id_servei%TYPE;
   vtotal SERVEI.preu%TYPE;
BEGIN
   SELECT id_servei into vid_servei FROM SERVEI WHERE id_servei=v_id_servei;
	IF NOT FOUND THEN
		raise exception 'servei no trobat';
	END IF;
   SELECT SUM(preu*quantitat) into vtotal FROM DETALL_SERVEI DS, CARTA C WHERE DS.id_plat=C.id_plat GROUP BY id_servei having id_servei=v_id_servei;
   UPDATE SERVEI SET preu=vtotal WHERE id_servei=v_id_servei;
   RAISE NOTICE 'Total: %',vtotal;
   RETURN vtotal;
END;
$$ LANGUAGE plpgsql;



CREATE OR REPLACE FUNCTION mostra_servei(v_id_servei integer) RETURNS void AS $$
DECLARE
   vtotal SERVEI.preu%TYPE;
   c_plats CURSOR FOR SELECT plat,tipus,preu,quantitat FROM DETALL_SERVEI DS, CARTA C WHERE DS.id_plat=C.id_plat and id_servei=v_id_servei;
   vr_plats RECORD;
   cad varchar(1024);
BEGIN
   cad:='<table border="1"><tr><td>id_cambrer</td><td>nom</td><td>total</td></tr>';
   OPEN c_plats;

   FETCH c_plats INTO vr_plats;
   WHILE FOUND LOOP
      cad := cad || '<tr><td>' || vr_plats.plat|| '</td><td>' || vr_plats.preu || '</td><td>' || vr_plats.quantitat || '</td></tr>';
		-- RAISE NOTICE '%',cad;

      FETCH c_plats INTO vr_plats;
   END LOOP;
   cad := cad || '</table>';

   SELECT SUM(preu*quantitat) into vtotal FROM DETALL_SERVEI DS, CARTA C WHERE DS.id_plat=C.id_plat GROUP BY id_servei having id_servei=v_id_servei;
   cad := cad || '<b>Total:</b> '|| vtotal || ' euros';
	RAISE NOTICE '%',cad;
   RETURN;
END;
$$ LANGUAGE plpgsql;



CREATE OR REPLACE FUNCTION resum_cambrer(v_id_cambrer integer,dia char) RETURNS void AS $$
DECLARE
   c_cambrer CURSOR FOR SELECT C.id_cambrer,id_servei,nom,preu FROM CAMBRER C,SERVEI S WHERE C.id_cambrer=S.id_cambrer and c.id_cambrer=v_id_cambrer and to_char(dia_hora,'DD/MM/YYYY')=dia;
   vr_cambrer RECORD;
   cad varchar(1024);
BEGIN
   cad := '<table border="1"><tr><td>id_cambrer</td><td>id_servei</td><td>nom</td><td>preu</td></tr>';
   OPEN c_cambrer;
   FETCH c_cambrer INTO vr_cambrer;
   WHILE FOUND LOOP
	cad := cad || '<tr><td>' || vr_cambrer.id_cambrer || '</td><td>' || vr_cambrer.id_servei || '</td><td>' || vr_cambrer.nom || '</td><td>' || vr_cambrer.preu || '</td></tr>';
	FETCH c_cambrer INTO vr_cambrer;
   END LOOP;
   cad:= cad || '</table>';
   RAISE NOTICE '%',cad;
   RETURN;
END;
$$ LANGUAGE plpgsql;


CREATE OR REPLACE FUNCTION informe_mensual(v_mes integer,v_any integer) RETURNS void AS $$
DECLARE
   c_informe CURSOR FOR SELECT C.id_cambrer,nom,SUM(preu) as total FROM CAMBRER C, SERVEI S WHERE C.id_cambrer=S.id_cambrer and to_number(to_char(dia_hora,'MM'),'99')=v_mes and to_number(to_char(dia_hora,'YYYY'),'9999')=v_any GROUP BY C.id_cambrer,nom;
   vr_informe RECORD;
   cad varchar(1024);
BEGIN
   cad := '<table border="1"><tr><td>id_cambrer</td><td>nom</td><td>total</td></tr>';
   OPEN c_informe;
   FETCH c_informe INTO vr_informe;
   WHILE FOUND LOOP
      cad := cad || '<tr><td>' || vr_informe.id_cambrer || '</td><td>' || vr_informe.nom || '</td><td>' || vr_informe.total || '</td></tr>';
      FETCH c_informe INTO vr_informe;
   END LOOP;
   cad:= cad || '</table>';
   RAISE NOTICE '%',cad;
   RETURN;
END;
$$ LANGUAGE plpgsql;


REM *********** JOC DE PROVES ****************************

select inserir_servei(1,1);

REM substituir el primer argument pel id_servei actual
select inserir_detall_servei(1,1,1);
select inserir_detall_servei(1,2,2);
select inserir_detall_servei(1,4,2);
select inserir_detall_servei(1,5,1);
select inserir_detall_servei(1,11,3);
select inserir_detall_servei(1,15,1);
select inserir_detall_servei(1,16,1);
select inserir_detall_servei(1,17,1);
select inserir_detall_servei(1,19,1);
select inserir_detall_servei(1,20,1);


select calcular_servei(1);
select mostra_servei(1);

select inserir_servei(3,2);

select inserir_detall_servei(2,2,1);
select inserir_detall_servei(2,3,2);
select inserir_detall_servei(2,7,1);
select inserir_detall_servei(2,8,1);
select inserir_detall_servei(2,11,1);
select inserir_detall_servei(2,12,2);
select inserir_detall_servei(2,15,3);
select inserir_detall_servei(2,19,2);
select inserir_detall_servei(2,20,1);

select calcular_servei(2);
select mostra_servei(2);

select resum_cambrer(1,'30/10/2009');
select resum_cambrer(3,'30/10/2009');

select informe_mensual(10,2009);

funcions de PHP per accedir a Postgres de forma nadiua (pg_):

Codi que se't proporciona:


open_db.php

<?php
//postgresql connection variables
$pg_user = 	'profe';	//username
$pg_pass =	'profe';	//user password
$pg_host =	'localhost';		//host name or server ip address
$pg_db   = 	'restaurant';	//database name

$conn_string = "host=$pg_host port=5432 dbname=$pg_db user=$pg_user password=$pg_pass";
$conn = pg_connect($conn_string) or die('connection failed');;

if (!$conn) {
  echo "Hi ha hagut un error en la connexió.\n";
  exit;
}
?>

close_db.php:

<?php
	pg_close($conn); //de fet, no cal
?>

agafar_taula2.php:

<?php include( "inc_head.php" ); ?>
<?php include( "open_db.php" ); ?>
<?php
$vid_cambrer=trim($_POST['id_cambrer']);
$vid_taula=trim($_POST['id_taula']);M
$result = pg_query($conn, "SELECT inserir_servei($vid_cambrer,$vid_taula)");
$row=pg_fetch_assoc($result);
$vid_servei=$row['inserir_servei'];

echo "Hem introduït el servei ".$vid_servei.": id_cambrer: ".$vid_cambrer. " -
?>

<?php include( "close_db.php" ); ?>
<?php include( "inc_peu.php" ); ?>

Nota: normalment les solucions no són úniques, i l'alumne pot experimentar amb altres funcions per arribar al mateix resultat.

solució

Un altre exemple: prova març 2012

Funció obrir_bug()

CREATE OR REPLACE FUNCTION obrir_bug(vid_software integer, vdescripcio varchar, vid_informador integer, OUT vid_bug integer, OUT vid_punts integer) AS $$
DECLARE
    vr_bug RECORD;
    cad varchar(40);
    cad1 varchar(2048);
    cad2 varchar(1024);
	vbugs_total integer;
	vbugs_total_soft integer;
BEGIN
    INSERT INTO bug VALUES(nextval('seq_bug'), vid_software, vdescripcio, now(),NULL,'OBERT',vid_informador);
	SELECT currval('seq_bug') INTO vid_bug;
	UPDATE usuari SET punts=punts+10 WHERE id_usuari=vid_informador;
	SELECT punts INTO vid_punts FROM usuari WHERE id_usuari=vid_informador;
	SELECT count(*) INTO vbugs_total FROM bug WHERE estat='OBERT';
	SELECT count(*) INTO vbugs_total_soft FROM bug WHERE estat='OBERT' and id_software=vid_software;

	cad1 := 'Total bugs oberts: ' || vbugs_total;
	cad2 := 'Total bugs oberts software: ' || vbugs_total_soft;
	cad1 := cad1 || '<br />' || cad2 || '<br />';
	RAISE NOTICE '%',cad1;
	
END;
$$  LANGUAGE plpgsql;

obrir_bug.php:

<?php include( "inc_head.php" ); ?>

<?php include( "open_db.php" ); ?>

<?php 
if(isset($_REQUEST['en'])){

	$id_usuari=trim($_POST['id_usuari']);

	$id_software=trim($_POST['id_software']);

	$des=trim($_POST['des']);



	$result= pg_query($conn,"select obrir_bug($id_software,'$des', $id_usuari)");

	$row = pg_fetch_assoc($result);

	echo $row['obrir_bug'];
	echo '<br />';
	$pieces = explode(",", $row['obrir_bug']);
	echo 'id bug: '. substr($pieces[0],1,strlen($pieces[0])-1);
	echo '<br />';
	echo 'Número de punts: '. substr($pieces[1],0,strlen($pieces[1])-1);
	echo '<br />';

	$notice = str_replace("NOTICE:","",pg_last_notice($conn));

	echo $notice;

}else{

?>

<form name="obrir_bug" method="post" action="obrir_bug.php" >

Usuari: <select name="id_usuari">

<?php

	$sql="select * from usuari";

	$result=pg_query($conn, $sql);

	while($row=pg_fetch_assoc($result)){

		echo "<option value=\"".$row['id_usuari']."\">".$row['nom_usuari']."</option>";

	}

?>

</select><br>

Software: <select name="id_software">

<?php

	$sql="select * from software";

	$result=pg_query($conn, $sql);

	while($row=pg_fetch_assoc($result)){

		echo "<option value=\"".$row['id_software']."\">".$row['nom_software']."</option>";

	}

?>

</select><br>

Descripcio: <input id="text" name="des" value=""/> 

<br>

<input type="submit" name="en" value="Enviar"/>

</form>

<?php } ?>

<?php include( "close_db.php" ); ?>

<?php include( "inc_peu.php" ); ?>

Durarda

6 hores



creat per Joan Quintana Compte, octubre 2009

Eines de l'usuari
Espais de noms
Variants
Accions
Navegació
Institut Jaume Balmes
Màquines recreatives
CNC
Informàtica musical
joanillo.org Planet
Eines