Symfony
Crear archivos batch en symfony
por tryke en Dic.17, 2008, dentro Symfony
Crear archivos batch con symfony considero que es una de las tareas menos documentadas dentro del framework.
En este post veremos un ejemplo de como hacer un proceso batch para enviar un mailing a todos los usuarios con nuestro boletin.
En primer lugar ejecutaremos el comando init-batch de symfony para que cree el archivo batch.
-
symfony init-batch default [yourBatchName] [yourApplicationName]
El comando crea automaticamente un archivo en el directorio batch de nuestro proyecto.
-
<?php
-
-
/**
-
* yourBatchName batch script
-
*
-
* Here goes a brief description of the purpose of the batch script
-
*
-
* @package yourProject
-
* @subpackage batch
-
* @version $Id$
-
*/
-
-
define('SF_ROOT_DIR', realpath(dirname(__file__).'/..'));
-
define('SF_APP', 'yourApplicationName');
-
define('SF_ENVIRONMENT', 'dev');
-
define('SF_DEBUG', 1);
-
-
require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php');
-
-
// initialize database manager
-
//$databaseManager = new sfDatabaseManager();
-
//$databaseManager->initialize();
-
-
// batch process here
-
?>
Como podemos observar por defecto te crea un comentario con las llamadas necesarias para inicializar nuestro acceso a la base de datos.
En primer lugar deberemos crearnos un modulo para el envio de emails, a este modulo nosotros lo hemos llamado “email” y la acción “boletin” es la encargada de realizar el envio. En la acción de este modulo leeremos el parametro “usuario_id” que será el que identifica el usuario receptor del mensaje.
actions.class.php
-
<?php
-
class emailActions extends sfActions
-
{
-
public function executeBoletin()
-
{
-
$this->i18n = $this->getContext()->getI18N();
-
$this->usuario = UsuarioPeer::retrieveByPK($this->getRequestParameter('usuario_id'));
-
if (!$this->usuario) {
-
return sfView::NONE;
-
}
-
if (!$this->usuario->getMailavisos()) {
-
return sfView::NONE;
-
}
-
$this->i18n->setCulture($this->usuario->getCulture());
-
-
$this->mail = new sfMail();
-
$this->setMailer('sendmail');
-
$this->setCharset('utf-8');
-
$this->setContentType('text/html');
-
-
$this->mail->setSender('no-reply@miweb.com', 'miweb.com');
-
$this->mail->setFrom('no-reply@miweb.com', 'miweb.com');
-
$this->mail->addAddress($this->usuario->getEmail());
-
$this->mail->setSubject($this->i18n->__('Boletin semanal', null, 'email'));
-
}
-
}
-
?>
Por otro lado montamos el template que será el que contiene el cuerpo del mensaje con el boletin a enviar.
boletinSuccess.php
-
<?php echo sprintf('%s <b>%s</b>', __('Hola', null, 'email'), $usuario->getNombre() ); ?><br>
-
<?php echo __('Este es tu boletin semanal', null, 'email') ?>
Para finalizar solo tenemos que retocar el fichero batch que hemos creado anteriormente para que lea de la base de datos todos los usuarios y vaya enviando el boletin.
batch_boletin.php
-
<?php
-
/**
-
* yourBatchName batch script
-
*
-
* Here goes a brief description of the purpose of the batch script
-
*
-
* @package yourProject
-
* @subpackage batch
-
* @version $Id$
-
*/
-
set_time_limit(0);
-
-
define('SF_ROOT_DIR', realpath(dirname(__file__).'/..'));
-
define('SF_APP', 'yourApplicationName');
-
define('SF_ENVIRONMENT', 'dev');
-
define('SF_DEBUG', 1);
-
define('SF_LOG_DEBUG', 'crit');
-
-
require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php');
-
-
// initialize database manager
-
$databaseManager = new sfDatabaseManager();
-
$databaseManager->initialize();
-
-
// batch process here
-
sfLogger::getInstance()->log('Inicio envio boletin (' . date('Y-m-d H:m:i') . ')…', SF_LOG_DEBUG);
-
-
$c = new Criteria();
-
$usuarios = UsuarioPeer::doSelect($c);
-
-
foreach ($usuarios as $s) {
-
sfContext::getInstance()->getRequest()->setParameter('usuario_id', $s->getId()); //Pasa el usuario por parametro
-
sfContext::getInstance()->getController()->sendEmail('email', 'boletin'); //Envia el email al usuario
-
sfLogger::getInstance()->log('envio boletin: ' . $s->getId(), SF_LOG_DEBUG); //Añado una linea en el log
-
sleep(rand(0,4)); //Espera un máximo de 4s por envio para evitar ser catalogado como spam
-
}
-
-
sfLogger::getInstance()->log('Fin envio boletin (' . date('Y-m-d H:m:i') . ')…', SF_LOG_DEBUG);
-
?>
Si quisieramos podriamos poner nuestro archivo batch_boletin en el cron del servidor para que se ejecutará semanalmente.
Symfony Cache por Base de Datos en MySQL
por admin en Dic.15, 2008, dentro Symfony
El Framework de Symfony dispone de diversos metodos de almacenar la cache. Entre los cuales podemos elegir diferentes opciones:
- Guardar la cache en disco mediante el uso de ficheros.
- Utilizar memcache.
- Almacenar la cache en base de datos mediante SQLite.
- etc..
Cuando trabajamos con proyectos muy grandes que requieren balanceo de carga, el sistema de cache puede resultar un problema.
Una posible solución es manipular la cache mediante Base de Datos.
Para poder almacenar la cache en MySQL he creado esta pequeña clase.
sfMySQLCache.class.php
-
<?php
-
-
class sfMySQLCache extends sfCache
-
{
-
const DEFAULT_HOST = 'localhost';
-
const DEFAULT_BD = 'database';
-
const DEFAULT_USR = 'usuario';
-
const DEFAULT_PSR = 'password';
-
-
const DEFAULT_NAMESPACE = '';
-
-
protected $automaticCleaningFactor = 500;
-
protected $conn = null;
-
-
public function __construct($database = null)
-
{
-
}
-
-
public function __destruct()
-
{
-
}
-
-
public function initialize($options = array())
-
{
-
}
-
-
-
/*Terminada …*/
-
public function get($id, $namespace = self::DEFAULT_NAMESPACE, $doNotTestCacheValidity = false)
-
{
-
$this->conn = mysql_connect(self::DEFAULT_HOST, self::DEFAULT_USR, self::DEFAULT_PSR);
-
mysql_select_db(self::DEFAULT_BD, $this->conn);
-
mysql_query("SET NAMES 'utf8'", $this->conn);
-
-
$statement = sprintf("SELECT data FROM _cache WHERE id = '%s' AND namespace = '%s'", mysql_escape_string($id), mysql_escape_string($namespace));
-
if (!$doNotTestCacheValidity) {
-
$statement .= sprintf(" AND created_at > '%s'", mysql_escape_string(date('Y-m-d H:i:s', $this->refreshTime)));
-
}
-
$statement .= ' LIMIT 1';
-
-
$rs = mysql_query($statement, $this->conn);
-
$datos = mysql_fetch_array($rs);
-
$resultado = mysql_num_rows($rs) ? $datos['data'] : null;
-
-
return $resultado;
-
}
-
-
/*Terminada …*/
-
public function has($id, $namespace = self::DEFAULT_NAMESPACE, $doNotTestCacheValidity = false)
-
{
-
$this->conn = mysql_connect(self::DEFAULT_HOST, self::DEFAULT_USR, self::DEFAULT_PSR);
-
mysql_select_db(self::DEFAULT_BD, $this->conn);
-
mysql_query("SET NAMES 'utf8'", $this->conn);
-
-
$statement = sprintf("SELECT id FROM _cache WHERE id = '%s' AND namespace = '%s'", mysql_escape_string($id), mysql_escape_string($namespace));
-
if (!$doNotTestCacheValidity) {
-
$statement .= sprintf(" AND created_at > '%s'", mysql_escape_string(date('Y-m-d H:i:s', $this->refreshTime)));
-
}
-
$statement .= ' LIMIT 1';
-
-
$rs = mysql_query($statement, $this->conn);
-
$resultado = mysql_num_rows($rs) ? true : false;
-
-
return $resultado;
-
}
-
-
/*Terminada…*/
-
public function set($id, $namespace = self::DEFAULT_NAMESPACE, $data)
-
{
-
if ($this->automaticCleaningFactor > 0) {
-
$rand = rand(1, $this->automaticCleaningFactor);
-
if ($rand == 1) {
-
$this->clean(false, 'old');
-
}
-
}
-
-
if (!$this->has($id, $namespace, true)) {
-
$this->conn = mysql_connect(self::DEFAULT_HOST, self::DEFAULT_USR, self::DEFAULT_PSR);
-
mysql_select_db(self::DEFAULT_BD, $this->conn);
-
mysql_query("SET NAMES 'utf8'", $this->conn);
-
$statement = sprintf("INSERT INTO _cache (id, namespace, data, created_at) VALUES ('%s', '%s', '%s', '%s')", mysql_escape_string($id), mysql_escape_string($namespace), mysql_escape_string($data), date('Y-m-d H:i:s'));
-
} else {
-
$this->conn = mysql_connect(self::DEFAULT_HOST, self::DEFAULT_USR, self::DEFAULT_PSR);
-
mysql_select_db(self::DEFAULT_BD, $this->conn);
-
mysql_query("SET NAMES 'utf8'", $this->conn);
-
$statement = sprintf("UPDATE _cache SET data = '%s', created_at = '%s' WHERE id = '%s' AND namespace = '%s' LIMIT 1", mysql_escape_string($data), date('Y-m-d H:i:s'), mysql_escape_string($id), mysql_escape_string($namespace));
-
}
-
-
$resultado = mysql_query($statement, $this->conn) ? true : false;
-
return $resultado;
-
}
-
-
/*Terminada…*/
-
public function remove($id, $namespace = self::DEFAULT_NAMESPACE)
-
{
-
$this->conn = mysql_connect(self::DEFAULT_HOST, self::DEFAULT_USR, self::DEFAULT_PSR);
-
mysql_select_db(self::DEFAULT_BD, $this->conn);
-
mysql_query("SET NAMES 'utf8'", $this->conn);
-
-
$statement = sprintf("DELETE FROM _cache WHERE id = '%s' AND namespace = '%s' LIMIT 1", mysql_escape_string($id), mysql_escape_string($namespace));
-
$resultado = mysql_query($statement, $this->conn) ? true : false;
-
-
return $resultado;
-
}
-
-
/*Terminada… POR OBTIMIZAR*/
-
public function clean($namespace = null, $mode = 'all')
-
{
-
$this->conn = mysql_connect(self::DEFAULT_HOST, self::DEFAULT_USR, self::DEFAULT_PSR);
-
mysql_select_db(self::DEFAULT_BD, $this->conn);
-
mysql_query("SET NAMES 'utf8'", $this->conn);
-
-
if (!$namespace) {
-
$statement = "DELETE FROM _cache";
-
} else {
-
$statement = sprintf("DELETE FROM _cache WHERE namespace LIKE '%s%%'", $namespace);
-
}
-
-
if ('old' == $mode) {
-
$statement .= sprintf(" %s created_at < '%s'", $namespace ? 'AND' : 'WHERE', mysql_escape_string(date('Y-m-d H:i:s', $this->refreshTime)));
-
}
-
-
$resultado = mysql_num_rows(mysql_query($statement, $this->conn)) ? true : false;
-
-
return $resultado;
-
}
-
-
/*Terminada…*/
-
public function lastModified($id, $namespace = self::DEFAULT_NAMESPACE)
-
{
-
$this->conn = mysql_connect(self::DEFAULT_HOST, self::DEFAULT_USR, self::DEFAULT_PSR);
-
mysql_select_db(self::DEFAULT_BD, $this->conn);
-
mysql_query("SET NAMES 'utf8'", $this->conn);
-
-
$statement = sprintf("SELECT UNIX_TIMESTAMP(created_at) as created_at FROM _cache WHERE id = '%s' AND namespace = '%s' LIMIT 1", mysql_escape_string($id), mysql_escape_string($namespace));
-
$rs = mysql_query($statement, $this->conn);
-
$data = mysql_fetch_array($rs);
-
$resultado = mysql_num_rows($rs) ? intval($data['created_at']) : 0;
-
-
return $resultado;
-
}
-
-
}
-
?>
Trabajar con UTF-8 en Symfony
por admin en Dic.15, 2008, dentro Symfony
Durante mis primeros días trabajando con symfony me encontré con un problema que me hizo perder varios días de trabajo.
Por lo visto symfony tiene un archivo de configuración “config/settings.yml” donde le puedes indicar el charset con el que vas a trabajar dentro del proyecto.
El problema me lo encontré al intentar conectar una base de datos MySQL utilizando el charset utf-8. Por lo visto synfony 1.0.17 no ejecuta la sentencia set names para trabajar en unicode.
Esta sentencia es la encargada de decirle a nuestra base de datos que se va a trabajar en utf-8.
Finalmente, despues de mucho pelearme, conseguí hacerlo funcionar mediante un filtro.
Para conseguirlo, solo es necesario crear la clase Utf8ConnectionFilter dentro del directorio lib de nuestra aplicación.
Utf8ConnectionFilter.class.php
-
<?php
-
-
class Utf8ConnectionFilter extends sfFilter
-
{
-
public function execute($filterChain) {
-
$con = Propel::getConnection();
-
if ($con) {
-
$con->executeQuery("set names utf8");
-
} else {
-
throw new Exception($e);
-
}
-
$filterChain->execute();
-
}
-
}
-
-
?>
El filtro, obtiene la conexión de propel y ejecuta la sentencia set names utf8 como primera sentencia sql.
Posteriormente hace una llamada al método execute para que continue con la ejecucción de los otros filtros.
Debemos añadir nuestra clase en el archivo config/filters.yml, que es el encargado de determinar que filtros se ejecutarán y cual será su orden de ejecucción.
filters.yml
-
rendering: ~
-
web_debug: ~
-
security: ~
-
-
connection:
-
class: Utf8ConnectionFilter
-
-
cache: ~
-
common: ~
-
flash: ~
-
execution: ~
Como último paso solo será necesario borrar la cache.









