Estas en: Home > acciones

Entradas etiquetadas con acciones

Cron Job WordPress

WordPress 3.x para desarrolladores: Temas y plantillas, functions.php

0

Como ya llevamos varias plantillas creadas con algunas llamadas a funciones del archivo functions.php, vamos a crearlo y añadir esas funciones, después continuaremos añadiendo más plantillas.

 

FUNCTIONS.PHP

Creamos el archivo functions.php y añadimos el siguiente código:

[codesyntax lang=»php»]

<?php

/**
 * Set the content width based on the theme's design and stylesheet.
 */
if ( ! isset( $content_width ) )
	$content_width = 584;

[/codesyntax]

Este código creara una variable que nos indicará el ancho que tendrá el contenido.

[codesyntax lang=»php»]

<?php

/**
 * Tell WordPress to run newtheme_setup() when the 'after_setup_theme' hook is run.
 */
add_action( 'after_setup_theme', 'newtheme_setup' );

if ( ! function_exists( 'newtheme_setup' ) ):

function newtheme_setup() {

}

endif;

[/codesyntax]

 

Le decimos a WordPress que ejecute newtheme_setup cuando el hook after_setup_theme esté funcionando. Creamos un condicional para comprobar que la función newtheme_setup no ha sido aun creada, y creamos la función.

Dentro de newtheme_setup añadiremos las siguientes lineas de código:

[codesyntax lang=»php»]

<?php

	load_theme_textdomain( 'newtheme', get_template_directory() . '/languages' );

[/codesyntax]

Esta línea cargará el archivo de idioma correspondiente.

[codesyntax lang=»php»]

<?php

	add_editor_style();

[/codesyntax]

Le indicamos a WordPress que cargue el editor de estilos. Para ello WordPress buscará el archivo editor-style.css dentro de la carpeta del tema, por tanto copiaremos los archivos editor-style.css y editor-style-rtl.css del tema Twenty Eleven a nuestro tema.

[codesyntax lang=»php»]

<?php

	require( get_template_directory() . '/inc/theme-options.php' );
	require( get_template_directory() . '/inc/widgets.php' );

[/codesyntax]

Estas dos lineas cargan los archivos de las opciones del tema que se mostrarán en la administración y los widgets de los que disponga el tema.

[codesyntax lang=»php»]

<?php

	add_theme_support( 'automatic-feed-links' );

[/codesyntax]

Le indicamos a WordPress que los links de este tema se añadirán a un archivo rss que se creará automáticamente. Más sobre otros argumentos de esta función: http://codex.wordpress.org/Function_Reference/add_theme_support

[codesyntax lang=»php»]

<?php

	register_nav_menu( 'primary', __( 'Primary Menu', 'newtheme' ) );

[/codesyntax]

Registramos la barra de menú de la cabecera.

[codesyntax lang=»php»]

<?php
	add_theme_support( 'post-formats', array( 'aside', 'link', 'gallery', 'status', 'quote', 'image' ) );

[/codesyntax]

Añadimos soporte para varios tipos de formato de posts.

[codesyntax lang=»php»]

<?php

	$theme_options = newtheme_get_theme_options();
	if ( 'dark' == $theme_options['color_scheme'] )
		$default_background_color = '1d1d1d';
	else
		$default_background_color = 'f1f1f1';

	// Add support for custom backgrounds.
	add_theme_support( 'custom-background', array(
		// Let WordPress know what our default background color is.
		// This is dependent on our current color scheme.
		'default-color' => $default_background_color,
	) );

[/codesyntax]

Primero recuperamos las opciones del tema a través de la función newtheme_get_theme_options(), que se encuentra en el archivo inc/theme_options.php, el cual crearemos más delante.

Comprobamos que tipo de esquema de estilos se ha elegido y guardamos en la variable $default_background_color el valor correspondiente.

Le indicamos a WordPress el color de nuestro fondo de página.

[codesyntax lang=»php»]

<?php

	add_theme_support( 'post-thumbnails' );

[/codesyntax]

Le indicamos a WordPress que este tema utilizará imágenes destacadas o thumbnails.

[codesyntax lang=»php»]

<?php

	$custom_header_support = array(
		// The default header text color.
		'default-text-color' => '000',
		// The height and width of our custom header.
		'width' => apply_filters( 'newtheme_header_image_width', 1000 ),
		'height' => apply_filters( 'newtheme_header_image_height', 288 ),
		// Support flexible heights.
		'flex-height' => true,
		// Random image rotation by default.
		'random-default' => true,
		// Callback for styling the header.
		'wp-head-callback' => 'newtheme_header_style',
		// Callback for styling the header preview in the admin.
		'admin-head-callback' => 'newtheme_admin_header_style',
		// Callback used to display the header preview in the admin.
		'admin-preview-callback' => 'newtheme_admin_header_image',
	);

	add_theme_support( 'custom-header', $custom_header_support );

[/codesyntax]

Creamos un array con los encabezados personalizados y se lo indicamos a WordPress.

[codesyntax lang=»php»]

<?php

	if ( ! function_exists( 'get_custom_header' ) ) {
		// This is all for compatibility with versions of WordPress prior to 3.4.
		define( 'HEADER_TEXTCOLOR', $custom_header_support['default-text-color'] );
		define( 'HEADER_IMAGE', '' );
		define( 'HEADER_IMAGE_WIDTH', $custom_header_support['width'] );
		define( 'HEADER_IMAGE_HEIGHT', $custom_header_support['height'] );
		add_custom_image_header( $custom_header_support['wp-head-callback'], $custom_header_support['admin-head-callback'], $custom_header_support['admin-preview-callback'] );
		add_custom_background();
	}

[/codesyntax]

En el caso de que se utilizase este tema con una versión de WordPress inferior a la 3.4 creamos varias constantes, y añadimos las cabeceras personalizadas y el fondo a WordPress.

[codesyntax lang=»php»]

<?php

	set_post_thumbnail_size( $custom_header_support['width'], $custom_header_support['height'], true );

[/codesyntax]

Configuramos la imagen destacada definiendo un ancho y alto.

[codesyntax lang=»php»]

<?php

	add_image_size( 'large-feature', $custom_header_support['width'], $custom_header_support['height'], true );
	// Used for featured posts if a large-feature doesn't exist.
	add_image_size( 'small-feature', 500, 300 );

[/codesyntax]

Añadimos la imagen a la cabecera definiendo su ancho y alto, además añadimos una imagen más pequeña para los post en el caso de que no existe imagen para la cabecera.

[codesyntax lang=»php»]

<?php

	register_default_headers( array(
		'wheel' => array(
			'url' => '%s/images/headers/wheel.jpg',
			'thumbnail_url' => '%s/images/headers/wheel-thumbnail.jpg',
			/* translators: header image description */
			'description' => __( 'Wheel', 'newtheme' )
		),
		'shore' => array(
			'url' => '%s/images/headers/shore.jpg',
			'thumbnail_url' => '%s/images/headers/shore-thumbnail.jpg',
			/* translators: header image description */
			'description' => __( 'Shore', 'newtheme' )
		),
		'trolley' => array(
			'url' => '%s/images/headers/trolley.jpg',
			'thumbnail_url' => '%s/images/headers/trolley-thumbnail.jpg',
			/* translators: header image description */
			'description' => __( 'Trolley', 'newtheme' )
		),
		'pine-cone' => array(
			'url' => '%s/images/headers/pine-cone.jpg',
			'thumbnail_url' => '%s/images/headers/pine-cone-thumbnail.jpg',
			/* translators: header image description */
			'description' => __( 'Pine Cone', 'newtheme' )
		),
		'chessboard' => array(
			'url' => '%s/images/headers/chessboard.jpg',
			'thumbnail_url' => '%s/images/headers/chessboard-thumbnail.jpg',
			/* translators: header image description */
			'description' => __( 'Chessboard', 'newtheme' )
		),
		'lanterns' => array(
			'url' => '%s/images/headers/lanterns.jpg',
			'thumbnail_url' => '%s/images/headers/lanterns-thumbnail.jpg',
			/* translators: header image description */
			'description' => __( 'Lanterns', 'newtheme' )
		),
		'willow' => array(
			'url' => '%s/images/headers/willow.jpg',
			'thumbnail_url' => '%s/images/headers/willow-thumbnail.jpg',
			/* translators: header image description */
			'description' => __( 'Willow', 'newtheme' )
		),
		'hanoi' => array(
			'url' => '%s/images/headers/hanoi.jpg',
			'thumbnail_url' => '%s/images/headers/hanoi-thumbnail.jpg',
			/* translators: header image description */
			'description' => __( 'Hanoi Plant', 'newtheme' )
		)
	) );

[/codesyntax]

Este es el paquete de imágenes que el tema Twenty Eleven trae por defecto, nosotros haremos lo mismo. Si no lo habéis hecho ya, copiad la carpeta images del tema Twenty Eleven a nuestro tema.

El marcador %s indica que se debe sustituir por la uri del tema.

Como esta función tiene llamadas a otras funciones dentro del mismo archivo functions.php, vamos a crearlas.

En primer lugar crearemos la función newtheme_header_style():

[codesyntax lang=»php»]

<?php

if ( ! function_exists( 'newtheme_header_style' ) ) :
/**
 * Styles the header image and text displayed on the blog
 */
function newtheme_header_style() {
	$text_color = get_header_textcolor();

	// If no custom options for text are set, let's bail.
	if ( $text_color == HEADER_TEXTCOLOR )
		return;

	// If we get this far, we have custom styles. Let's do this.
	?>
	<style type="text/css">
	<?php
		// Has the text been hidden?
		if ( 'blank' == $text_color ) :
	?>
		#site-title,
		#site-description {
			position: absolute !important;
			clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
			clip: rect(1px, 1px, 1px, 1px);
		}
	<?php
		// If the user has set a custom color for the text use that
		else :
	?>
		#site-title a,
		#site-description {
			color: #<?php echo $text_color; ?> !important;
		}
	<?php endif; ?>
	</style>
	<?php
}
endif; // newtheme_header_style

[/codesyntax]

Simplemente en esta función se generan los estilos para el título y la descripción que se ubican en la cabecera de la página.

Creamos el método newtheme_admin_header_style():

[codesyntax lang=»php»]

<?php

if ( ! function_exists( 'newtheme_admin_header_style' ) ) :
/**
 * Styles the header image displayed on the Appearance > Header admin panel.
 *
 * Referenced via add_theme_support('custom-header') in newtheme_setup().
 */
function newtheme_admin_header_style() {
?>
	<style type="text/css">
	.appearance_page_custom-header #headimg {
		border: none;
	}
	#headimg h1,
	#desc {
		font-family: "Helvetica Neue", Arial, Helvetica, "Nimbus Sans L", sans-serif;
	}
	#headimg h1 {
		margin: 0;
	}
	#headimg h1 a {
		font-size: 32px;
		line-height: 36px;
		text-decoration: none;
	}
	#desc {
		font-size: 14px;
		line-height: 23px;
		padding: 0 0 3em;
	}
	<?php
		// If the user has set a custom color for the text use that
		if ( get_header_textcolor() != HEADER_TEXTCOLOR ) :
	?>
		#site-title a,
		#site-description {
			color: #<?php echo get_header_textcolor(); ?>;
		}
	<?php endif; ?>
	#headimg img {
		max-width: 1000px;
		height: auto;
		width: 100%;
	}
	</style>
<?php
}
endif; // newhtme_admin_header_style

[/codesyntax]

Esta función permite dar estilos a la imagen de la cabecera dentro de su apartado de opciones en la administración de WordPress, donde se podrá configurar cómo se ve la imagen.

Creamos la función newtheme_admin_header_image():

[codesyntax lang=»php»]

<?php

if ( ! function_exists( 'newtheme_admin_header_image' ) ) :
/**
 * Custom header image markup displayed on the Appearance > Header admin panel.
 *
 * Referenced via add_theme_support('custom-header') in newtheme_setup().
 */
function newtheme_admin_header_image() { ?>
	<div id="headimg">
		<?php
		$color = get_header_textcolor();
		$image = get_header_image();
		if ( $color && $color != 'blank' )
			$style = ' style="color:#' . $color . '"';
		else
			$style = ' style="display:none"';
		?>
		<h1><a id="name"<?php echo $style; ?> onclick="return false;" href="<?php echo esc_url( home_url( '/' ) ); ?>"><?php bloginfo( 'name' ); ?></a></h1>
		<div id="desc"<?php echo $style; ?>><?php bloginfo( 'description' ); ?></div>
		<?php if ( $image ) : ?>
			<img src="<?php echo esc_url( $image ); ?>" alt="" />
		<?php endif; ?>
	</div>
<?php }
endif; // newtheme_admin_header_image

[/codesyntax]

Esta función crea el código html que mostrará la imagen, el título y la descripción en su respectiva zona de opciones de la administración de WordPress, para que el usuario pueda ver como quedaría.

[codesyntax lang=»php»]

<?php

/**
 * Sets the post excerpt length to 40 words.
 *
 * To override this length in a child theme, remove the filter and add your own
 * function tied to the excerpt_length filter hook.
 */
function newtheme_excerpt_length( $length ) {
	return 40;
}
add_filter( 'excerpt_length', 'newtheme_excerpt_length' );

[/codesyntax]

Esta función establece la longitud del extracto de un post a 40 palabras.

[codesyntax lang=»php»]

<?php

/**
 * Returns a "Continue Reading" link for excerpts
 */
function newtheme_continue_reading_link() {
	return ' <a href="'. esc_url( get_permalink() ) . '">' . __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'newtheme' ) . '</a>';
}

[/codesyntax]

Esta función devuelve el link con el texto «Seguir leyendo…» en los extractos de los posts.

[codesyntax lang=»php»]

<?php

/**
 * Replaces "[...]" (appended to automatically generated excerpts) with an ellipsis and newtheme_continue_reading_link().
 *
 * To override this in a child theme, remove the filter and add your own
 * function tied to the excerpt_more filter hook.
 */
function newtheme_auto_excerpt_more( $more ) {
	return ' &hellip;' . newtheme_continue_reading_link();
}
add_filter( 'excerpt_more', 'newtheme_auto_excerpt_more' );

[/codesyntax]

Esta función remplaza el texto «[…]» por «…» utilizando «&hellip;» para ello, y el link de newtheme_continue_reading_link()

[codesyntax lang=»php»]

<?php

/**
 * Adds a pretty "Continue Reading" link to custom post excerpts.
 *
 * To override this link in a child theme, remove the filter and add your own
 * function tied to the get_the_excerpt filter hook.
 */
function newtheme_custom_excerpt_more( $output ) {
	if ( has_excerpt() && ! is_attachment() ) {
		$output .= newtheme_continue_reading_link();
	}
	return $output;
}
add_filter( 'get_the_excerpt', 'newtheme_custom_excerpt_more' );

[/codesyntax]

Añade la salida de newtheme_continue_reading_link() a los extractos personalizados de los posts.

[codesyntax lang=»php»]

<?php

/**
 * Get our wp_nav_menu() fallback, wp_page_menu(), to show a home link.
 */
function newtheme_page_menu_args( $args ) {
	$args['show_home'] = true;
	return $args;
}
add_filter( 'wp_page_menu_args', 'newtheme_page_menu_args' );

[/codesyntax]

Esta función hace que en nuestro menú de navegación aparezca un link hacía la página principal.

[codesyntax lang=»php»]

<?php

/**
 * Register our sidebars and widgetized areas. Also register the default Epherma widget.
 */
function newtheme_widgets_init() {

	register_widget( 'New_Theme_Ephemera_Widget' );

	register_sidebar( array(
		'name' => __( 'Main Sidebar', 'newtheme' ),
		'id' => 'sidebar-1',
		'before_widget' => '<aside id="%1$s" class="widget %2$s">',
		'after_widget' => "</aside>",
		'before_title' => '<h3 class="widget-title">',
		'after_title' => '</h3>',
	) );

	register_sidebar( array(
		'name' => __( 'Showcase Sidebar', 'newtheme' ),
		'id' => 'sidebar-2',
		'description' => __( 'The sidebar for the optional Showcase Template', 'newtheme' ),
		'before_widget' => '<aside id="%1$s" class="widget %2$s">',
		'after_widget' => "</aside>",
		'before_title' => '<h3 class="widget-title">',
		'after_title' => '</h3>',
	) );

	register_sidebar( array(
		'name' => __( 'Footer Area One', 'newtheme' ),
		'id' => 'sidebar-3',
		'description' => __( 'An optional widget area for your site footer', 'newtheme' ),
		'before_widget' => '<aside id="%1$s" class="widget %2$s">',
		'after_widget' => "</aside>",
		'before_title' => '<h3 class="widget-title">',
		'after_title' => '</h3>',
	) );

	register_sidebar( array(
		'name' => __( 'Footer Area Two', 'newtheme' ),
		'id' => 'sidebar-4',
		'description' => __( 'An optional widget area for your site footer', 'newtheme' ),
		'before_widget' => '<aside id="%1$s" class="widget %2$s">',
		'after_widget' => "</aside>",
		'before_title' => '<h3 class="widget-title">',
		'after_title' => '</h3>',
	) );

	register_sidebar( array(
		'name' => __( 'Footer Area Three', 'newtheme' ),
		'id' => 'sidebar-5',
		'description' => __( 'An optional widget area for your site footer', 'newtheme' ),
		'before_widget' => '<aside id="%1$s" class="widget %2$s">',
		'after_widget' => "</aside>",
		'before_title' => '<h3 class="widget-title">',
		'after_title' => '</h3>',
	) );
}
add_action( 'widgets_init', 'newtheme_widgets_init' );

[/codesyntax]

Esta función registra nuestro widget que crearemos en el archivo inc/widgets.php, y las cinco sidebars que añade el tema a diferentes partes de la página.

[codesyntax lang=»php»]

<?php

if ( ! function_exists( 'newtheme_content_nav' ) ) :
/**
 * Display navigation to next/previous pages when applicable
 */
function newtheme_content_nav( $nav_id ) {
	global $wp_query;

	if ( $wp_query->max_num_pages > 1 ) : ?>
		<nav id="<?php echo $nav_id; ?>">
			<h3 class="assistive-text"><?php _e( 'Post navigation', 'newtheme' ); ?></h3>
			<div class="nav-previous"><?php next_posts_link( __( '<span class="meta-nav">&larr;</span> Older posts', 'newtheme' ) ); ?></div>
			<div class="nav-next"><?php previous_posts_link( __( 'Newer posts <span class="meta-nav">&rarr;</span>', 'newtheme' ) ); ?></div>
		</nav><!-- #nav-above -->
	<?php endif;
}
endif; // newtheme_content_nav

[/codesyntax]

Muestra los links para mostrar la siguiente o anterior página de posts cuando sea aplicable.

[codesyntax lang=»php»]

<?php

/**
 * Return the URL for the first link found in the post content.
 *
 * @return string|bool URL or false when no link is present.
 */
function newtheme_url_grabber() {
	if ( ! preg_match( '/<a\s[^>]*?href=[\'"](.+?)[\'"]/is', get_the_content(), $matches ) )
		return false;

	return esc_url_raw( $matches[1] );
}

[/codesyntax]

Devuelve la url del primer link encontrado en el contenido del post.

[codesyntax lang=»php»]

<?php

/**
 * Count the number of footer sidebars to enable dynamic classes for the footer
 */
function newtheme_footer_sidebar_class() {
	$count = 0;

	if ( is_active_sidebar( 'sidebar-3' ) )
		$count++;

	if ( is_active_sidebar( 'sidebar-4' ) )
		$count++;

	if ( is_active_sidebar( 'sidebar-5' ) )
		$count++;

	$class = '';

	switch ( $count ) {
		case '1':
			$class = 'one';
			break;
		case '2':
			$class = 'two';
			break;
		case '3':
			$class = 'three';
			break;
	}

	if ( $class )
		echo 'class="' . $class . '"';
}

[/codesyntax]

Cuenta el número de sidebars habilitados para el pie de página y devuelve la clase que corresponda.

[codesyntax lang=»php»]

<?php

if ( ! function_exists( 'newtheme_comment' ) ) :
/**
 * Template for comments and pingbacks.
 *
 * To override this walker in a child theme without modifying the comments template
 * simply create your own newtheme_comment(), and that function will be used instead.
 *
 * Used as a callback by wp_list_comments() for displaying the comments.
 *
 */
function newtheme_comment( $comment, $args, $depth ) {
	$GLOBALS['comment'] = $comment;
	switch ( $comment->comment_type ) :
		case 'pingback' :
		case 'trackback' :
	?>
	<li class="post pingback">
		<p><?php _e( 'Pingback:', 'newtheme' ); ?> <?php comment_author_link(); ?><?php edit_comment_link( __( 'Edit', 'newtheme' ), '<span class="edit-link">', '</span>' ); ?></p>
	<?php
			break;
		default :
	?>
	<li <?php comment_class(); ?> id="li-comment-<?php comment_ID(); ?>">
		<article id="comment-<?php comment_ID(); ?>" class="comment">
			<footer class="comment-meta">
				<div class="comment-author vcard">
					<?php
						$avatar_size = 68;
						if ( '0' != $comment->comment_parent )
							$avatar_size = 39;

						echo get_avatar( $comment, $avatar_size );

						/* translators: 1: comment author, 2: date and time */
						printf( __( '%1$s on %2$s <span class="says">said:</span>', 'newtheme' ),
							sprintf( '<span class="fn">%s</span>', get_comment_author_link() ),
							sprintf( '<a href="%1$s"><time pubdate datetime="%2$s">%3$s</time></a>',
								esc_url( get_comment_link( $comment->comment_ID ) ),
								get_comment_time( 'c' ),
								/* translators: 1: date, 2: time */
								sprintf( __( '%1$s at %2$s', 'newtheme' ), get_comment_date(), get_comment_time() )
							)
						);
					?>

					<?php edit_comment_link( __( 'Edit', 'newtheme' ), '<span class="edit-link">', '</span>' ); ?>
				</div><!-- .comment-author .vcard -->

				<?php if ( $comment->comment_approved == '0' ) : ?>
					<em class="comment-awaiting-moderation"><?php _e( 'Your comment is awaiting moderation.', 'newtheme' ); ?></em>
					<br />
				<?php endif; ?>

			</footer>

			<div class="comment-content"><?php comment_text(); ?></div>

			<div class="reply">
				<?php comment_reply_link( array_merge( $args, array( 'reply_text' => __( 'Reply <span>&darr;</span>', 'newtheme' ), 'depth' => $depth, 'max_depth' => $args['max_depth'] ) ) ); ?>
			</div><!-- .reply -->
		</article><!-- #comment-## -->

	<?php
			break;
	endswitch;
}
endif; // ends check for newtheme_comment()

[/codesyntax]

Esta función genera el código html necesario para mostrar cada comentario de un post.

[codesyntax lang=»php»]

<?php

if ( ! function_exists( 'newtheme_posted_on' ) ) :
/**
 * Prints HTML with meta information for the current post-date/time and author.
 * Create your own newtheme_posted_on to override in a child theme
 */
function newtheme_posted_on() {
	printf( __( '<span class="sep">Posted on </span><a href="%1$s" title="%2$s" rel="bookmark"><time class="entry-date" datetime="%3$s" pubdate>%4$s</time></a><span class="by-author"> <span class="sep"> by </span> <span class="author vcard"><a class="url fn n" href="%5$s" title="%6$s" rel="author">%7$s</a></span></span>', 'newtheme' ),
		esc_url( get_permalink() ),
		esc_attr( get_the_time() ),
		esc_attr( get_the_date( 'c' ) ),
		esc_html( get_the_date() ),
		esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ),
		esc_attr( sprintf( __( 'View all posts by %s', 'newtheme' ), get_the_author() ) ),
		get_the_author()
	);
}
endif;

[/codesyntax]

Esta función devuelve los metadatos de un post.

[codesyntax lang=»php»]

<?php

/**
 * Adds two classes to the array of body classes.
 * The first is if the site has only had one author with published posts.
 * The second is if a singular post being displayed
 */
function newtheme_body_classes( $classes ) {

	if ( function_exists( 'is_multi_author' ) && ! is_multi_author() )
		$classes[] = 'single-author';

	if ( is_singular() && ! is_home() && ! is_page_template( 'showcase.php' ) && ! is_page_template( 'sidebar-page.php' ) )
		$classes[] = 'singular';

	return $classes;
}
add_filter( 'body_class', 'newtheme_body_classes' );

[/codesyntax]

Esta función devuelve las clases de estilos que corresponden para la etiqueta body dependiendo del tipo de página que se muestre al usuario.

Symfony: El controlador (I)

0

Continuo dándole caña a Symfony. Ahora toca el controlador.

¿Qué hace el controlador? Pues lo siguiente:

  • El controlador frontal es el único punto de entrada a la aplicación. Carga la configuración y determina la acción a ejecutarse.
  • Las acciones contienen la lógica de la aplicación. Verifican la integridad de las peticiones y preparan los datos requeridos por la capa de presentación.
  • Los objetos request, response y session dan acceso a los parámetros de la petición, las cabeceras de las respuestas y a los datos persistentes del usuario. Se utilizan muy a menudo en la capa del controlador.
  • Los filtros son trozos de código ejecutados para cada petición, antes o después de una acción. Por ejemplo, los filtros de seguridad y validación son comúnmente utilizados en aplicaciones web. Puedes extender el framework creando tus propios filtros.

EL CONTROLADOR FRONTAL

http://localhost/index.php/mimodulo/miAccion

La URL de arriba es un ejemplo de que tarea realiza el controlador frontal. En este caso nuestro controlador frontal es el archivo index.php que se encargará de ejecutar miAccion de mimodulo y generar la página que mostrará al usuario.

EL TRABAJO DEL CONTROLADOR EN DETALLE

Estas son las tareas que ejecuta el controlador antes de que se muestre la página al usuario:

  1. Carga la clase de configuración del proyecto y las librerías de Symfony.
  2. Crea la configuración de la aplicación y el contexto de Symfony.
  3. Carga e inicializa las clases del núcleo del framework.
  4. Carga la configuración.
  5. Decodifica la URL de la petición para determinar la acción a ejecutar y los parámetros de la petición.
  6. Si la acción no existe, redireccionará a la acción del error 404.
  7. Activa los filtros (por ejemplo, si la petición necesita autenticación).
  8. Ejecuta los filtros, primera pasada.
  9. Ejecuta la acción y produce la vista.
  10. Ejecuta los filtros, segunda pasada.
  11. Muestra la respuesta.

index.php, EL CONTROLADOR FRONTAL POR DEFECTO

Este archivo se encuentra en la carpeta /web del proyecto y contiene el siguiente código:

[codesyntax lang=»php»]

<?php    

  require_once(dirname(__FILE__).'/../config/ProjectConfiguration.class.php');

  $configuration = ProjectConfiguration::getApplicationConfiguration('frontend', 'prod', false);
  sfContext::createInstance($configuration)-&gt;dispatch();

[/codesyntax]

Lo que hace es simple, carga el archivo de la clase de configuración, llama a la clase y despacha la petición usando el método dispatch() de la clase sfContext.

Podemos crear otros controladores frontales simplemente copiando el archivo y modificando el segundo parámetro del método getApplicationConfiguration().

Para ello copiaremos el código del archivo index.php a frontend_staging.php y sustituiremos el segundo parámetro del método getApplicationConfiguration() que en vez de ser prod (de producción), será staging. Utilizaremos este controlador para que el cliente pueda probar la aplicación antes de ponerla en producción.

Una vez hecho esto modificaremos el archivo app.yml en la carpeta /config de la aplicación (en este caso sería /frontend/config) como sigue:

[codesyntax lang=»php»]

staging:
  mail:
    webmaster: falso@misitio.com
    contacto: falso@misitio.com
all:
  mail:
    webmaster: webmaster@misitio.com
    contacto: contacto@mysite.com

[/codesyntax]

Ahora solo tienes que escribir la siguiente URL para ver como se comporta el nuevo controlador frontal:

http://localhost/frontend_staging.php/mimodulo/index

LAS ACCIONES

[codesyntax lang=»php»]

<?php

class mimoduloActions extends sfActions
 {
   public function executeIndex()
   {
     // ...
   }
 }

[/codesyntax]

Las acciones son métodos de una clase que hereda de sfActions y se encuentran agrupadas por módulos. Esta clase se encuentra en el archivo actions.class.php en la carpeta /actions del módulo.

Para añadir más acciones sólo es necesario añadir más métodos execute al objeto sfActions:

[codesyntax lang=»php»]

<?php

class mimoduloActions extends sfActions
{
  public function executeIndex()
  {
    // ...
  }

  public function executeListar()
  {
    // ...
  }
}

[/codesyntax]

Y para ver en el navegador estas acciones sólo habría que escribir:

Para executeIndex() -> http://localhost/frontend_dev.php/mimodulo/index
Para executeListar() -> http://localhost/frontend_dev.php/mimodulo/listar

 

SEPARANDO LAS ACCIONES EN ARCHIVOS DIFERENTES

Para crear acciones de un mismo módulo en archivos diferentes se debe crear una clase que extienda sfAction (en vez de sfActions que utilizabamos anteriormente), en un archivo llamado nombreAccionAction.class.php y el nombre del método en cada archivo será, simplemente, execute.

[codesyntax lang=»php» title=»Archivo de una sola acción, en frontend/modules/mimodulo/actions/indexAction.class.php»]

<?php

class indexAction extends sfAction
{
  public function execute($peticion)
  {
    // ...
  }
}

[/codesyntax]

[codesyntax lang=»php» title=»Archivo de una sola acción, en frontend/modules/mimodulo/actions/listAction.class.php»]

<?php

class listarAction extends sfAction
{
  public function execute($peticion)
  {
    // ...
  }
}

[/codesyntax]

 

OBTENIENDO INFORMACIÓN DE LAS ACCIONES

sfActions proporciona acceso a sfContext::createInstance() a través de getContext() que devuelve un objeto que guarda una referencia de todos los objetos del núcleo de symfony relacionados con la petición dada:

[codesyntax lang=»php» title=»Métodos comunes de sfActions»]

<?php

class mimoduloActions extends sfActions
{
  public function executeIndex($peticion)
  {
    // Obteniendo parametros de la petición
    $password      = $peticion->getParameter('password');

    // Obteniendo información del controlador
    $nombreModulo  = $this->getModuleName();
    $nombreAccion  = $this->getActionName();

    // Obteniendo objetos del núcleo del framework
    $sesionUsuario = $this->getUser();
    $respuesta     = $this->getResponse();
    $controlador   = $this->getController();
    $contexto      = $this->getContext();

    // Creando variables de la acción para pasar información a la plantilla
    $this->setVar('parametro', 'valor');
    $this->parametro = 'valor';           // Versión corta.
  }
}

[/codesyntax]

  • sfController: El objeto controlador (->getController())
  • sfRequest: El objeto de la petición (->getRequest())
  • sfResponse: El objeto de la respuesta (->getResponse())
  • sfUser: El objeto de la sesión del usuario (->getUser())
  • sfDatabaseConnection: La conexión a la base de datos (->getDatabaseConnection())
  • sfLogger: El objeto para los logs (->getLogger())
  • sfI18N: El objeto de internacionalización (->getI18N())

Se puede llamar al método sfContext::getInstance() desde cualquier parte del código.

 

TERMINACIÓN DE LAS ACCIONES

Normalmente cuando finalizamos un método o función y queremos devolver algún dato utilizamos la palabra return seguida de alguna variable u objeto. En Symfony es más o menos igual, me explico:

Symfony, una vez a procesado la acción, enviará los datos a la plantilla para que el usuario pueda visualizarlo. Por defecto, Symfony siempre utiliza return sfView::SUCCESS para buscar la plantilla que debe mostrar los datos:

[codesyntax lang=»php» title=»Acciones que llaman a las plantillas indexSuccess.php y listarSuccess.php»]

<?php

public function executeIndex()
{
  return sfView::SUCCESS;
}

public function executeListar()
{
}

[/codesyntax]

Al ser sfView::SUCCESS la vista por defecto, si no se indica en la acción, Symfony buscará una plantilla llamada nombreacciónSuccess.php.

En el caso de que quisieramos mostrar al usuario otra plantilla en caso de error haríamos lo siguiente:

[codesyntax lang=»php»]

<?php

return sfView::ERROR;

[/codesyntax]

Esto buscará una plantilla llamada nombreacciónError.php. Si queremos mostrar una vista personalizada:

[codesyntax lang=»php»]

<?php

return 'MiResultado';

[/codesyntax]

En ete caso, Symfony buscará una plantilla llamada nombreacciónMiResultado.php (ojo a las mayusculas ya que Symfony es case sensitive)

Si no se quiere utilizar ninguna vista:

[codesyntax lang=»php»]

<?php

return sfView::NONE;

[/codesyntax]

En el caso de que la acción vaya a ser utilizada por Ajax, podemos devolver los datos sin necesidad de pasar por la vista con el método renderText():

[codesyntax lang=»php»]

<?php

public function executeIndex()
{
  $this->getResponse()->setContent("<html><body>¡Hola Mundo!</body></html>");

  return sfView::NONE;
}

// Es equivalente a
public function executeIndex()
{
  return $this->renderText("<html><body>¡Hola Mundo!</body></html>");
}

[/codesyntax]

En algunos casos se necesita enviar sólo las cabeceras de la petición, como en el caso de J-SON:

[codesyntax lang=»php»]

<?php

public function executeActualizar()
{
  $salida = '<"titulo","Mi carta sencilla"],["nombre","Sr. Pérez">';
  $this->getResponse()->setHttpHeader("X-JSON", '('.$salida.')');

  return sfView::HEADER_ONLY;
}

[/codesyntax]

Si se quiere utilizar una plantilla específica, se debe prescindir de la sentencia return y utilizar el método setTemplate():

[codesyntax lang=»php»]

<?php

$this->setTemplate('miPlantillaPersonalizada');

[/codesyntax]

 

SALTANDO A OTRA ACCIÓN

Hay dos formas de saltar a otra acción:

[codesyntax lang=»php»]

<?php

//Si la acción debe continuar en otro módulo
$this->forward('otroModulo', 'index');

//Si la acción debe redireccionar a otro módulo o una web externa
$this->redirect('otroModulo/index');
$this->redirect('http://www.google.com/');

[/codesyntax]

En el caso de que quisieramos redireccionar para mostrar un error 404:

[codesyntax lang=»php»]

<?php

public function executeVer($peticion)
{
  $articulo = ArticuloPeer::retrieveByPK($peticion->getParameter('id'));
  if (!$articulo)
  {
    $this->forward404();
  }
}

[/codesyntax]

Si estás buscando la acción y la plantilla del error 404, las puedes encontrar en el directorio $sf_symfony_lib_dir/controller/default/. Se puede personalizar esta página agregado un módulo default a la aplicación, sobrescribiendo el del framework, y definiendo una acción error404 y una plantilla error404Success dentro del nuevo módulo. Otro método alternativo es el de establecer las constantes error_404_module y error_404_action en el archivo settings.yml para utilizar una acción existente.

La clase sfActions tiene algunos métodos más, llamados forwardIf(), forwardUnless(), forward404If(), forward404Unless(), redirectIf() y redirectUnless(). Estos métodos simplemente requieren un parámetro que representa la condición cuyo resultado se emplea para ejecutar el método. El método se ejecuta si el resultado de la condición es true y el método es de tipo xxxIf() o si el resultado de la condición es false y el método es de tipo xxxUnless():

[codesyntax lang=»php»]

<?php

// Esta acción es equivalente a la mostrada en el Listado 6-11
public function executeVer($peticion)
{
  $articulo = ArticuloPeer::retrieveByPK($peticion->getParameter('id'));
  $this->forward404If(!$articulo);
}

// Esta acción también es equivalente
public function executeVer()
{
  $articulo = ArticuloPeer::retrieveByPK($peticion->getParameter('id'));
  $this->forward404Unless($articulo);
}

[/codesyntax]

 

REPITIENDO CÓDIGO PARA VARIAS ACCIONES DE UN MÓDULO

Si por alguna razón nuestras acciones siempre van a ejecutar el mismo código al inicio o al final del método, podemos evitar duplicar código creando los métodos postExecute() y preExecute(), pero además podemos añadir al archivo de la acción (con sfAction) o acciones (con sfActions) nuestros propios métodos siempre que no empiecen con execute y no sean métodos públicos (utilizando para ello las sentencias protected o private).

[codesyntax lang=»php»]

<?php

class mimoduloActions extends sfActions
{
  public function preExecute()
  {
    // El código insertado aquí se ejecuta al principio de cada llamada a una acción
    // ...
  }

  public function executeIndex($peticion)
  {
    // ...
  }

  public function executeListar($peticion)
  {
    // ...
    $this->miPropioMetodo();  // Se puede acceder a cualquier método de la clase acción
  }

  public function postExecute()
  {
    // El código insertado aquí se ejecuta al final de cada llamada a la acción
    ...
  }

  protected function miPropioMetodo()
  {
    // Se pueden crear métodos propios, siempre que su nombre no comience por "execute"
    // En ese case, es mejor declarar los métodos como protected o private
    // ...
  }
}

[/codesyntax]

Ir arriba