Un lector de base de datos MySQL de WordPress para recuperación de un sitio muerto.

Esta aplicación fue desarrollada en Linux Debian 8 y Typhon64, pero el mismo código debería funcionar en Windows o cualquier otra plataforma soportada  por Lazarus/Typhon/FreePascal. En Ubuntu con Unity puede encontrar algunas dificultades al correr aplicaciones visuales con menúes y otros componentes visuales.  Para resolver este problema simplemente ejecute el siguiente script antes de llamar a su aplicación.

#!/bin/bash
export LIBOVERLAY_SCROLLBAR=0
export UBUNTU_MENUPROXY=0
./yourapplication

Por más información  pueden leer aquí. Invocamos a Lazarus/Typhon. Cuando abre presionamos File|New…  Aparece un formulario y seleccionamos Application.

File New… Application

Con esto se crea un esqueleto de una aplicación y un formulario, para una aplicación visual. En Lazarus el formulario aparece en una ventana independiente, mientras que en Typhon aparece en la pestaña de Designer. Si el formulario no aparece puede que haya quedado fuera del espacio de las pantallas. Al menos me ocurre cuando trabajo en un entorno con muchas pantallas.

New Application

Para traer al formulario dentro de la ventana de Designer presionamos el botón de centrar. Allí nos aparece nuestro formulario.

Form Visible

Arriba generalmente (puede estar abajo si así lo configuraron) se encuentra la barra de componentes y el menú principal del ambiente. Allí se encuentran las principales operaciones para desarrollo, compilación y edición del código. También hay un conjunto importante de componentes visuales que se agregarán al código simplemente clickeando en el componente y luego en el formulario donde se agrega.

Main and Component Frame

Lo básico de nuestro proyecto está construído. Ahora debemos salvarlo y darle un nombre. Vamos a File| Save As…

Save As …

Navegamos hasta el directorio de nuestros proyectos y creamos un nuevo directorio para este. Presionando [Create Forlder] le damos el nombre ‘wordpressreader’.

WordPressReader Save

Ya tenemos un proyecto guardado. Ahora debemos ponerle un menú a nuestro formulario. En la pestaña [Standard] de componentes hacemos click en  el primer ítem (TmainMenu).

TMainMenu

Para editar en Menú, le damos botón derecho y seleccionamos ‘MenuEditor’.

Menu Editor

Agregamos dos ‘MenuItem’. Para ello presionamos  dos veces el botón [Add Menu Item]. Luego con botón derecho sobre MenuItem1, seleccionamos [Edit Caption].

Rename Menu Item

Esto nos permite renombrar en ítem 1  del menú. Le ponemos ‘Configure’. Al siguiente le ponemos ‘Exit’.

Configure Exit Menu Items

No hay que olvidar de tanto en tanto presionar [Save] {Ctrl+S} o {Shift+Ctrl+S}. Agregamos un manejador de eventos. Botón derecho y [Add OnClick Handler]

Add Event Handler

Para el Menu Item Exit agregamos en el código:

Application.Terminate;

Nótese que si esperamos un poco la ayuda contextual busca en los atributos y métodos del objeto y nos brinda un dropdown con los posibles valores. Al seleccionar Terminate y dar [Enter] se completa el código incluyendo el punto y coma.

Application.Terminate;

También generamos un Event Handler para Item Configure. Por ahora no ponemos nada allí. Volvemos al Designer del Form1, y elegimos la pestaña SQLdb de la Barra de componentes, y agregamos los siguientes componentes al Form1:  TMySQL40Connection,  TMySQL41Connection,  TMySQL50Connection,  TMySQL51Connection,  TMySQL55Connection,  TMySQL56Connection y TMySQL57Connection.

TMySQLxyConnection

Agregamos de la pestaña también un TSQLTransaction y un TSQLQuery. En la pestaña ‘Data Access’ agregamos un TDataSource. Agregamos de la pestaña Additional un TPairSplitter.

Add Components

Seleccionamos el PairSplitter (que de lo contrario es invisible) y le cambiamos el atributo de orientación. En el atributo Splitter Type ponemos pstVertical.

PairSplitter horizontal

El Pair Splitter consiste en un contenedor que incluye otros dos contenedores de componentes gráficos con un TSplitter en medio, que nos permitirá agrandar a un componente mientras se achica el otro. Haciendo click en la parte de arriba y en la de abajo podemos identificar ambos contenedores.

Pair Splitter Side 2

Agregamos en el contenedor superior un TDBGrid y en el inferior un TDBMemo de la pestaña de ‘Data Controls’.

DBGrid Upper Container
DBGrid Lower Container

Agregamos un DBMemo (DBMemo2) en el contenedor inferior (lower container). Modificamos el atributo Align = alTop y Height=48. Esto permite alinear DBMemo2 a la parte superior del contenedor inferior (lower container). Modificamos todos los componentes para que llenen el espacio del contenedor, para cada uno de PairSplitter y para el DBGrid y el DBMemo. Les ponemos Align=alClient. También ponemos ScrollBars=ssAutoBoth.

Align to client

Y nos queda el aspecto correcto.

Form1

Ahora debemos configurar los atributos de los objetos relacionados para que todo funcione correctamente. Suponemos que nos conectaremos a una base de datos MySQL de nombre ‘MySQLDatabase’, con el usuario ‘database-user’, y la password ‘MyV3rYC0mp73xP45w0rd’, en el servidor ‘localhost’ y por el puerto ‘3306’ (default). Para los objetos MySQLxyConnection vamos a tener que modificar los siguientes parámetros en tiempo de ejecución.

DatabaseName:='MySQLDatabase';
KeepConnection:=true;
Password:='MyV3rYC0mp73xP45w0rd';
Transaction:=SQLTransaction1;
UserName:='database-user';
Connected:=true;

Pero vamos a tener que probar una a una para verificar qué versión de cliente MySQL tenemos en el sistema. Para SQLTransaction1 tenemos que configurar los siguientes:

DataBase:=MySQLxyConnection1; //La que esté activa
Active:=true

Para el SQLQuery1 debemos configurar lo siguiente:

DataBase:=MySQLxyConnection1; //La que esté activa
SQL:='SELECT * FROM MySQLDatabase.wp_posts ORDER BY wp_posts.post_modified ASC;';
Transaction:=SQLTransaction1;
Active:=true;

No se asigna el atributo DataSource en SQLQuery1 porque daría un error de dependencia circular. Para el componente DataSource1 se configura el atributo DataSet.

DataSet:=SQLQuery1;

Los siguientes elementos se configuran en tiempo de diseño, como se explica aquí. El DBGrid1 dentro del PairSplitter se le debe vincular el DataSource1. Al componente DBMemo1 se le agrega el DataSource y el DataField como se indica.

PairSplitter1

PairSplitterSide1

DBGrid1

DataSource:=DataSource1;

PairSplitterSide2

DBMemo1

DataSource:=DataSource1;

DataField:=’post_content’;

Agregamos un segundo formulario (Form2)

New Form

Y nos aparece el nuevo formulario.

Form2

Al nuevo formulario debemos agregarle los TLabeledEdit de la pestaña de ‘Additional’.

Labeled Edit

Debemos modificar el atributo LabelPosition a lpLeft, para que la etiqueta quede a la izquierda del cuadro de texto.

Labeled edit left

Se corrige el tamaño para que queden elegantes en el formulario. Tanto como se pueda. Debemos editar la Etiqueta para que quede algo significativo. EditLabel.Caption es el contenido de la etiqueta. Y Text es el contenido del Edit Box.

Edit SubLabel

Agregamos un Botón con Caption Activate o Login o Connect. También editamos el texto de las cajas de edición para dejarlo de esta manera:

Form2 Labeled Edits

Además renombramos las EditBoxes con los nombres:

LabeledEditUser; LabeledEditPassword; LabeledEditDatabase; LabeledEditServer; LabeledEditPort;

En la Unit2 debemos agregar en la sección ‘Implementation’, que usa a la Unit1.

Include Unit1 in Unit2.

Para incluir la Unit2 en la Unit1, se declara en la sentencia uses.

Insert Uses Unit2

Esta es la forma correcta para que no haya errores por dependencias circulares. En el Form2 seleccionamos el evento OnClick del Botón y agregamos el siguiente código.

procedure TForm2.Button1Click(Sender: TObject);
begin
 Form1.user:= LabeledEditUser.Text;
 Form1.password:= LabeledEditPassword.Text;
 Form1.database:= LabeledEditDatabase.Text;
 Form1.server:= LabeledEditServer.Text;
 Form1.port:= LabeledEditPort.Text;
 self.Close;
end;

Esto tomará los parámetros de la conexión al cliente MySQL y los pasará al Form1 en las variables correspondientes. En el Form1 debemos editar el evento del ítem de menú Configure. En la sección public debemos crear las variables de pasaje de parámetros.

 public
      user, password, database,server,port: string;
 end;

Entre {$R *.frm} y { TForm1 }  creamos un procedimiento auxiliar con el siguiente código

{$R *.frm}

procedure MyConnected;
var messagestring :string;
begin
 messagestring:= '';
 if Form1.MySQL40Connection1.Connected then messagestring:= messagestring + 'MySQL40 ';
 if Form1.MySQL41Connection1.Connected then messagestring:= messagestring + 'MySQL41 ';
 if Form1.MySQL50Connection1.Connected then messagestring:= messagestring + 'MySQL50 ';
 if Form1.MySQL51Connection1.Connected then messagestring:= messagestring + 'MySQL51 ';
 if Form1.MySQL55Connection1.Connected then messagestring:= messagestring + 'MySQL55 ';
 if Form1.MySQL56Connection1.Connected then messagestring:= messagestring + 'MySQL56 ';
 if Form1.MySQL57Connection1.Connected then messagestring:= messagestring + 'MySQL57 ';
 if (messagestring='')
 then messagestring:= 'Connected '+ messagestring
 else messagestring:='Not Conencted';
 ShowMessage(messagestring);
end;

{ TForm1 }

Esta función es solo de diagnóstico, en la versión final no se utiliza. Y luego agregamos el siguiente código en la función del evento del Menú Configure (MenuItem1):

{ TForm1 }

procedure TForm1.MenuItem1Click(Sender: TObject);
begin
 Form2.ShowModal; //Add Unit2 in uses...
 ShowMessage('This is a database' + database + ' password:'+ password + ' user:'+ user + ' server:'+ server + ' port:' + port );
 //use parameters
 try
 MySQL40Connection1.DatabaseName:=database;
 MySQL40Connection1.KeepConnection:=true;
 MySQL40Connection1.Password:=password;
 MySQL40Connection1.UserName:=user;
 MySQL40Connection1.HostName:=server;
 MySQL40Connection1.Port:=StrToInt(port);
 MySQL40Connection1.KeepConnection:=true; //<----
 MySQL40Connection1.Connected:=true;
 MySQL40Connection1.Open;
 finally
 if MySQL40Connection1.Connected then
 begin
 SQLTransaction1.DataBase:=MySQL40Connection1;
 SQLTransaction1.Active:=true;

SQLQuery1.DataBase:=MySQL40Connection1;
 SQLQuery1.Transaction:=SQLTransaction1;
 SQLQuery1.SQL.Text:='SELECT * FROM '+ database + '.wp_posts ORDER BY wp_posts.post_modified ASC;';
 SQLQuery1.Active:=true;
 end
 else
 begin
 try
 MySQL41Connection1.DatabaseName:=database;
 MySQL41Connection1.KeepConnection:=true;
 MySQL41Connection1.Password:=password;
 MySQL41Connection1.UserName:=user;
 MySQL41Connection1.HostName:=server;
 MySQL41Connection1.Port:=StrToInt(port);
 MySQL41Connection1.KeepConnection:=true; //<----
 MySQL41Connection1.Connected:=true;
 MySQL41Connection1.Open;
 finally
 if MySQL41Connection1.Connected then
 begin
 SQLTransaction1.DataBase:=MySQL41Connection1;
 SQLTransaction1.Active:=true;

SQLQuery1.DataBase:=MySQL41Connection1;
 SQLQuery1.Transaction:=SQLTransaction1;
 SQLQuery1.SQL.Text:='SELECT * FROM '+ database + '.wp_posts ORDER BY wp_posts.post_modified ASC;';
 SQLQuery1.Active:=true;
 end
 else
 begin
 try
 MySQL50Connection1.DatabaseName:=database;
 MySQL50Connection1.KeepConnection:=true;
 MySQL50Connection1.Password:=password;
 MySQL50Connection1.UserName:=user;
 MySQL50Connection1.HostName:=server;
 MySQL50Connection1.Port:=StrToInt(port);
 MySQL50Connection1.KeepConnection:=true; //<----
 MySQL50Connection1.Connected:=true;
 MySQL50Connection1.Open;
 finally
 if MySQL50Connection1.Connected then
 begin
 SQLTransaction1.DataBase:=MySQL50Connection1;
 SQLTransaction1.Active:=true;

SQLQuery1.DataBase:=MySQL50Connection1;
 SQLQuery1.Transaction:=SQLTransaction1;
 SQLQuery1.SQL.Text:='SELECT * FROM '+ database + '.wp_posts ORDER BY wp_posts.post_modified ASC;';
 SQLQuery1.Active:=true;
 end
 else
 begin
 try
 MySQL51Connection1.DatabaseName:=database;
 MySQL51Connection1.KeepConnection:=true;
 MySQL51Connection1.Password:=password;
 MySQL51Connection1.UserName:=user;
 MySQL51Connection1.HostName:=server;
 MySQL51Connection1.Port:=StrToInt(port);
 MySQL51Connection1.KeepConnection:=true; //<----
 //MySQL51Connection1.Connected:=true;
 MySQL51Connection1.Open;
 finally
 if MySQL51Connection1.Connected then
 begin
 SQLTransaction1.DataBase:=MySQL51Connection1;
 SQLTransaction1.Active:=true;

SQLQuery1.DataBase:=MySQL51Connection1;
 SQLQuery1.Transaction:=SQLTransaction1;
 SQLQuery1.SQL.Text:='SELECT * FROM '+ database + '.wp_posts ORDER BY wp_posts.post_modified ASC;';
 SQLQuery1.Active:=true;
 end
 else
 begin
 try
 MySQL55Connection1.DatabaseName:=database;
 MySQL55Connection1.KeepConnection:=true;
 MySQL55Connection1.Password:=password;
 MySQL55Connection1.UserName:=user;
 MySQL55Connection1.HostName:=server;
 MySQL55Connection1.Port:=StrToInt(port);
 MySQL55Connection1.KeepConnection:=true; //<----
 MySQL55Connection1.Connected:=true;
 MySQL55Connection1.Open;

finally
 if MySQL55Connection1.Connected then
 begin
 SQLTransaction1.DataBase:=MySQL55Connection1;
 SQLTransaction1.Active:=true;

SQLQuery1.DataBase:=MySQL55Connection1;
 SQLQuery1.Transaction:=SQLTransaction1;
 SQLQuery1.SQL.Text:='SELECT * FROM '+ database + '.wp_posts ORDER BY wp_posts.post_modified ASC;';
 SQLQuery1.Active:=true;
 end
 else
 begin
 try
 MySQL56Connection1.DatabaseName:=database;
 MySQL56Connection1.KeepConnection:=true;
 MySQL56Connection1.Password:=password;
 MySQL56Connection1.UserName:=user;
 MySQL56Connection1.HostName:=server;
 MySQL56Connection1.Port:=StrToInt(port);
 MySQL56Connection1.KeepConnection:=true; //<----
 MySQL56Connection1.Connected:=true;
 MySQL56Connection1.Open;

finally
 if MySQL56Connection1.Connected then
 begin
 SQLTransaction1.DataBase:=MySQL56Connection1;
 SQLTransaction1.Active:=true;

SQLQuery1.DataBase:=MySQL56Connection1;
 SQLQuery1.Transaction:=SQLTransaction1;
 SQLQuery1.SQL.Text:='SELECT * FROM '+ database + '.wp_posts ORDER BY wp_posts.post_modified ASC;';
 SQLQuery1.Active:=true;
 end
 else
 begin
 try
 MySQL57Connection1.DatabaseName:=database;
 MySQL57Connection1.KeepConnection:=true;
 MySQL57Connection1.Password:=password;
 MySQL57Connection1.UserName:=user;
 MySQL57Connection1.HostName:=server;
 MySQL57Connection1.Port:=StrToInt(port);
 MySQL57Connection1.KeepConnection:=true; //<----
 MySQL57Connection1.Connected:=true;
 MySQL57Connection1.Open;

finally
 if MySQL57Connection1.Connected then
 begin
 SQLTransaction1.DataBase:=MySQL57Connection1;
 SQLTransaction1.Active:=true;

SQLQuery1.DataBase:=MySQL57Connection1;
 SQLQuery1.Transaction:=SQLTransaction1;
 SQLQuery1.SQL.Text:='SELECT * FROM '+ database + '.wp_posts ORDER BY wp_posts.post_modified ASC;';
 SQLQuery1.Active:=true;
 end
 else
 begin
 ShowMessage(' Did not find a suitable version of MySQL Client.');
 end;
 end; //try
 end; //57
 end; //finally
 end; //56
 end; //finally
 end; //55
 end; //finally
 end; //51
 end; //finally
 end; //50
 end;//finally
 end; //41
 end;//finally

MyConnected; //tell which database is connected

{SQLTransaction1.DataBase:=MySQLConnection;
 SQLTransaction1.Active:=true;

SQLQuery1.DataBase:=MySQLConnection;
 SQLQuery1.Transaction:=SQLTransaction1;
 SQLQuery1.SQL.Text:='SELECT * FROM '+ database + '.wp_posts ORDER BY wp_posts.post_modified ASC;';
 SQLQuery1.Active:=true;}

DataSource1.DataSet:=SQLQuery1;

DBGrid1.DataSource:=DataSource1;

DBMemo1.DataSource:=DataSource1;
 DBMemo1.DataField:='post_content';

end; //MenuItem1Click

Salvamos todo y podemos compilarlo y correrlo. Haciendo click en Configure nos aparece el form2 y podemos ingresar los parámetros de conexión a la base de datos. Haciendo Click en Activate, se conecta. Aparecerá un Message que nos modtrará los parámetros de conexión a la base de datos. Le damos OK. En Typhon el componente 51 dá un error no capturable en un mensaje si no encuentra su cliente de MySQL instalado.

TMySQL51Connection can not work with the installed MySQL client version: Expected (5.1), got (5.5.57).

Press OK to ignore and risk data corruption.
Press Abort to kill the program.

Es un problema de ese componente, ya que los otros componentes son capturados por el try finally. Dándole OK continúa. Y podemos recorrer los registros de la base y buscar el texto de nuestros posts perdidos. Recorremos los registros en el DBGrid superior, y nos aparece la información del post en el DBMemo abajo.

WordPressReader

Este es el Proyecto Typhon. ¡Actualizado!

Este es el Proyecto Lazarus. ¡Actualizado! Probado en lazarus-1.8.0RC4-fpc-3.0.4rc1-win32.

Entradas relacionadas