Kota Jembal :: Nota Symfony & PHP & Pembeda.com
Wednesday, August 21, 2013
Simple Form
? php app/console generate:bundle --namespace=ASF/TaskBundle
Welcome to the Symfony2 bundle generator
In your code, a bundle is often referenced by its name. It can be the
concatenation of all namespace parts but it's really up to you to come
up with a unique name (a good practice is to start with the vendor name).
Based on the namespace, we suggest ASFTaskBundle.
Bundle name [ASFTaskBundle]:
The bundle can be generated anywhere. The suggested default directory uses
the standard conventions.
Target directory [/home/fadabi/www/asf/asfnetwork/symfony2/src]:
Determine the format to use for the generated configuration.
Configuration format (yml, xml, php, or annotation): yml
To help you get started faster, the command can generate some
code snippets for you.
Do you want to generate the whole directory structure [no]? yes
Summary before generation
You are going to generate a "ASF\TaskBundle\ASFTaskBundle" bundle
in "/home/fadabi/www/asf/asfnetwork/symfony2/src/" using the "yml" format.
Do you confirm generation [yes]?
Bundle generation
Generating the bundle code: OK
Checking that the bundle is autoloaded: OK
Confirm automatic update of your Kernel [yes]?
Enabling the bundle inside the Kernel: OK
Confirm automatic update of the Routing [yes]?
Importing the bundle routing resource: OK
You can now start using the generated code!
==> Creating module / Entity
vi src/ASF/TaskBundle/Entity/Task.php
<?php
// src/ASF/TaskBundle/Entity/Task.php
namespace ASF\TaskBundle\Entity;
// para el mapping entre campos de la BD y Entity
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="task")
*/
class Task2
{
/**
* @ORM\Id
* @ORM\Column(type="integer", unique=true)
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* El nombre de la tarea, como máximo de 20 caracteres
* @ORM\Column(type="string", length=20)
*/
protected $task;
/**
* La fecha de finalización de la tarea
* @ORM\Column(type="date")
*/
protected $dueDate;
/**
* La descripción de la tarea
* @ORM\Column(type="text", length=300)
*/
protected $description;
/**
* La URL relacionada de algún modo con la tarea
* @ORM\Column(type="text", nullable=true)
*/
protected $url;
==> Generating Getters & Setters ? php app/console doctrine:generate:entities ASF/TaskBundle/Entity/Task
Generating entity "ASF\TaskBundle\Entity\Task"
> backing up Task.php to Task.php~
> generating ASF\TaskBundle\Entity\Task
==> Form validation :
#ASF/TaskBundle/Resource/config/validation.yml
ASF\TaskBundle\Entity\Task:
properties:
task:
- NotBlank: {message: "Tak Boleh Kosong"}
- MaxLength: {limit: 20, message: "Maksima {{ limit }} huruf" }
- MinLength: {limit: 1, message: "minima {{ limit }} huruf" }
dueDate:
- NotBlank: ~
- Type: \DateTime
- Date: {message: "Tarikh Kosong"}
description:
- MaxLength: { limit: 300, message: "Desc Maksima {{ limit }} huruf" }
url:
- Url:
- Regex:
pattern: "/.*\.es$/"
message: "La URL debe terminar en .es"
==> creating the table
php app/console doctrine:schema:update --force
==> the routing
# src/ASF/TaskBundle/Resources/config/routing.yml
ASFTaskBundle_task_new:
pattern: /new
defaults: { _controller: ASFTaskBundle:Default:new }
ASFTaskBundle_task_show:
pattern: /show
defaults: { _controller: ASFTaskBundle:Default:show }
ASFTaskBundle_task_edit:
pattern: /{id}/edit
defaults: { _controller: ASFTaskBundle:Default:edit, id: 0 }
requirements:
id: \d+
ASFTaskBundle_task_success:
pattern: /success/{nombreTarea}
defaults: { _controller: ASFTaskBundle:Default:success, nombreTarea: - }
==> The Controller
php app/console doctrine:schema:update --force
<?php
// src/ASF/TaskBundle/Controller/DefaultController.php
namespace ASF\TaskBundle\Controller;
use ASF\TaskBundle\Entity\Task;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class DefaultController extends Controller
{
/*
* new Task
*/
public function newAction(Request $request)
{
// Current year:
$thisyear = date('Y');
// create new task
$task = new Task();
$form = $this->createFormBuilder($task)
->add('task', 'text',array('label' => 'Tarea:'))
->add('dueDate', 'date', array('label' => 'Fetch limit', 'years' => range($thisyear, $thisyear+5)))
->add('description', 'textarea', array('label' => 'Descripcion', 'required' => 'false'))
->add('url', 'url', array('required' => false))
->getForm();
if ($request->getMethod() == 'POST') {
// second time you call NewAction, now we have the data
// task in the $request. So do the "bind" the form...
$form->bindRequest($request);
// and check whether it is valid (validation.yml!)
if ($form->isValid()){
// do things with form data.
// Keep them in BD, p eg.
$em = $this->getDoctrine()->getEntityManager();
$em->persist($task); // = tell Symfony to "control" this object!
$em->flush(); // can group multiple queries and then flush the launch of the BD at a time!
return $this->redirect($this->generateUrl('ASFTaskBundle_task_success', array('nombreTarea' => $task->getTask()) ));
}
}
return $this->render('ASFTaskBundle:Default:new2desplegado.html.twig', array( 'form' => $form->createView(), ));
}
/*
* Gets all tasks
*/ public function showAction() {
$tasks = $this->getDoctrine()
->getRepository('ASFTaskBundle:Task')
->findAll();
//->findByTask('Ejemplo tarea'); //with this line could find a job with that nombre exacto
return $this->render('ASFTaskBundle:Default:show.html.twig', array(
'tasks' => $tasks
));
}
/*
* Edit a task
*/
public function editAction($id, Request $request)
{
if (!$id) {
throw $this->createNotFoundException('Can not find the task id = '.$id);
}
// valid that there is a task associated with that ID...
$em = $this->getDoctrine()->getEntityManager();
$task = $em->getRepository('ASFTaskBundle:Task')->find($id);
if (!$task){
throw $this->createNotFoundException('No se encuentra la tarea con id = '.$id);
}
// I want to know the current year:
$thisyear = date('Y');
// I think the form (with fields) dynamically.
// As I will repeat the form that you created in NewAction, it might be interesting
// plantearme create a separate class and use $ this->createForm to create "statically"
$form = $this->createFormBuilder($task)
->add('task', 'text',array('label' => 'Tarea:'))
->add('dueDate', 'date', array('label' => 'Fetch limit', 'years' => range($thisyear, $thisyear+5)))
->add('description', 'textarea', array('label' => 'Descripcion', 'required' => 'false'))
->add('url', 'url', array('required' => false))
->getForm();
if ($request->getMethod() == 'POST') {
// I have received the result of the form...
// mappeo request values to the form...
$form->bindRequest($request);
// and check whether it is valid ...
if ($form->isValid()){
// is valid, so update the BD ...
$em->flush();
return $this->redirect($this->generateUrl('ASFTaskBundle_task_success', array('nombreTarea' => $task->getTask()) ));
}
}
// FIRST INVOCATION TO EDIT: you have to let the user change the info!
return $this->render('ASFTaskBundle:Default:edit2desplegado.html.twig', array(
'form' => $form->createView(),
'id' => $task->getId(),
));
}
/*
* Show splash screen "when performing operations success."
*/
public function successAction($nombreTarea){
if (!strcmp($nombreTarea,"-")){
$message = "What frames, Moreno?URL should not invoke this manually!";
} else {
// I will generate a message...
$message = "task '".$nombreTarea."' is saved.";
}
return $this->render('ASFTaskBundle:Default:success.html.twig', array(
'message' => $message ));
}
The Templates (view) + Assets (Css)
==> The Templates (view) + Assets (Css)vi src/ASF/TaskBundle/Resources/views/Default/template-base.html.twig
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
{% block head %}
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>
{% block title %}
{{ title|default("Template Base para TWIG") }}
{% endblock title %}
</title>
{% block description %}
<meta name="description" content="{{ description|default('Plantilla TWIG base por Miguel Martin') }}"/>
{% endblock description %}
{% block keywords %}
<meta name="keywords" content="twig, template, free, design, 960, grid" />
{% endblock keywords %}
{% block styles %}
{% stylesheets
'@ASFTaskBundle/Resources/public/css/layout/mainStyle.css'
'@ASFTaskBundle/Resources/public/css/layout/reset.css'
'@ASFTaskBundle/Resources/public/css/layout/colors.css'
output = 'css/compiled/styles.css'
filter = 'yui_css'
%}
<link href="{{ asset_url }}" type="text/css" rel="stylesheet" media="screen" />
{% endstylesheets %}
{% endblock styles %}
{% block script %}
{% javascripts
'@ASFTaskBundle/Resources/public/js/*'
%}
<script src="{{ asset_url }}" type="text/javascript"></script>
{% endjavascripts %}
<script type="text/javascript">
//<![CDATA[
//$(document).ready(function(){
//});
//]]>
</script>
{% endblock script %}
</head>
{% endblock head %}
<body>
<div id="wrapper">
<!-- ******************************************** HEADER ************************************ -->
{% block header %}
<div id="header">
<div id="titulo-centro">
<h1> {{ titulo|default("TEMPLATE BASE") }}</h1>
</div>
</div>
{% endblock header %}
<!-- ******************************************** /HEADER ************************************ -->
<div id="content">
<div id="breadcrumbs">
{% block breadcrumbs %}
<ul>
<li class"=first"><a href="{{ path('ASFTaskBundle_homepage') }}">HOME </a></li>
<li class="actual"><a href="="{{ path('ASFTaskBundle_test_template') }}">Template</a></li>
</ul>
{% endblock breadcrumbs %}
</div>
<br />
<!-- ******************************************** LEFT-COLUMN ************************************ -->
<div id="left-column">
{% block menusub %}
<div id="menu-sub">
<ul>
<li class"=first"><a href="{{ path('ASFTaskBundle_homepage') }}">HOME </a></li>
<li class="actual"><a href="{{ path('ASFTaskBundle_test_template') }}">Template</a></li>
<li><a href="{{ path('ASFTaskBundle_task_new2') }}">Insertar tarea</a></li>
<li><a href="{{ path('ASFTaskBundle_task_show') }}">Mostrar tareas</a></li>
<li class="last"><a href="#">link 4</a></li>
</ul>
</div>
{% endblock menusub %}
</div>
<!-- ******************************************** /LEFT-COLUMN ************************************ -->
<!--====MAIN COLUMN START====-->
<div id="main-column">
{% block maincolumn %}
<h2>Template base en TWIG</h2>
<br />
<p class="text-justify">We will be important, interesting, but because occasionally circumstances occur in which toil and pain can procure him some great. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it. We currently have in the train comes to find fault with that produces no resultant pleasure is to be online applications. These cases are perfectly account of the system, they are at fault quae workshop to leave softens recommend you: </ p> <br />
<p class="text-justify"> But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and, a complete account of the system, and the very fact that explorer from the truth, the master of a happy life that were said to you here. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because they do not know how to pursue pleasure rationally encounter consequences that are a pain. Nor again is there anyone who loves grief itself since it is grief liver, brain, so blinded by desire, but because occasionally occur at times of such a nature in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?
</p>
{% endblock maincolumn %}
</div>
<!--====MAIN COLUMN END====-->
<!--====RIGHT COLUMN START====-->
<div id="right-column">
{% block rightcolumn %}
<p class="text-justify xxsmall">But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it?</p>
{% endblock rightcolumn %}
</div>
<!--====RIGHT COLUMN END====-->
</div>
<!--=================CONTENT END==============-->
<!--=================FOOTER START==============-->
<div id="footer">
{% block footer %} ©2012 All Rights Reserved Miguel Martin | <a href="http://www.leccionespracticas.com" target="_blank" >Design by MiguelMartin</a> | <a href="http://validator.w3.org/check?uri=referer" target="_blank" rel="nofollow" >XHTML</a> | <a href="http://jigsaw.w3.org/css-validator/" target="_blank" rel="nofollow" >CSS</a>
</div>
{% endblock footer %}
<!--=================FOOTER END==============-->
</div>
</body>
</html>
vi src/ASF/TaskBundle/Resources/views/Default/new2desplegado.html.twig
{# src/ASF/TaskBundle/Resources/views/Default/new2desplegado.html.twig #}
{% extends "ASFTaskBundle:Default:template-base.html.twig" %}
{% block title %}
Insert New Task
{% endblock title %}
{% block header %}
<div id="header">
<div id="titulo-centro"> <h1>INSERT NEW TASK</h1>
</div>
</div>
{% endblock header %}
{% block breadcrumbs %}
<ul>
<li class"=first"><a href="/">HOME </a></li>
<li class="actual"><a href="/ASF/template">Template</a></li>
<li class="last"><a href="/ASF/new2">Nueva tarea</a></li>
</ul>
{% endblock breadcrumbs %}
{% block maincolumn %}
{% block message %}
{% endblock message %}
<div id="form-div" style="width: 800px; margin:auto; padding:10px;">
<form action="{{ path('ASFTaskBundle_task_new2') }}" method="post" {{ form_enctype(form) }}>
<div id="errores_form" class="error">
<!-- general errors of the form -->
{{ form_errors(form) }}
</div>
<div id="formcontent">
<table style="border-collapse:separate; border-spacing:1em;">
<tr>
<td>{{ form_label(form.task) }}</td>
<td>{{ form_widget(form.task) }}</td>
<td class="error">{{ form_errors(form.task) }}</td>
</tr>
<tr>
<td>{{ form_label(form.dueDate) }}</td>
<td>{{ form_widget(form.dueDate) }}</td>
<td class="error">{{ form_errors(form.dueDate) }}</td>
</tr>
<tr>
<td>{{ form_label(form.description) }}</td>
<td>{{ form_widget(form.description) }}</td>
<td class="error">{{ form_errors(form.description) }}</td>
</tr>
<tr>
<td>{{ form_label(form.url) }}</td>
<td>{{ form_widget(form.url) }}</td>
<td class="error">{{ form_errors(form.url) }}</td>
</tr>
<tr></tr>
<tr>{{ form_rest(form) }}</tr>
<tr>
<td></td>
<td><input type="submit" formnovalidate /></td>
</tr>
</table>
</div>
<br />
</form>
</div>
{% endblock maincolumn %}
{% block rightcolumn %}
<p>Use this form to enter a new task</p>
{% endblock rightcolumn %}
vi src/ASF/TaskBundle/Resources/views/Default/show.html.twig
{% extends "ASFTaskBundle:Default:new2desplegado.html.twig" %}
{% block title %}
List of tasks
{% endblock title %}
{% block header %}
<div id="header">
<div id="titulo-centro">
<h1>MOSTRAR TAREAS</h1>
</div>
</div>
{% endblock header %}
{% block breadcrumbs %}
<ul>
<li class"=first"><a href="/">HOME </a></li>
<li class="actual"><a href="/ASF/template">ASF</a></li>
<li class="last">Mostrar tareas</li>
</ul>
{% endblock breadcrumbs %}
{% block maincolumn %}
{% block message %}
{% if tasks is defined %}
<table style="border-spacing: 5px; margin-right: 5px; border-collapse: separate;">
<tr style="font-weight: bold;">
<td></td>
<!-- editar -->
<!--<td>ID</td>-->
<td>NOMBRE</td>
<td>FECHA</td>
<td>DESCRIPCIÓN</td>
<td>URL</td>
</tr>
{% for tarea in tasks %}
<tr style="font-size: 0.8em">
<td><a href=" {{ path('ASFTaskBundle_task_edit', { 'id' : tarea.id } ) }}" style="color:#A90641; font-size:0.9em; ">edit</a></td>
<!-- editar -->
<!--<td>{{ tarea.id }}</td>-->
<td>{{ tarea.task }}</td>
<td>{{ tarea.dueDate|date("m/d/Y") }}</td>
<td>{{ tarea.description }}</td>
<td>{{ tarea.url }}</td>
</tr>
{% endfor %}
</table>
{% else %}
<p>No tasks. you <a href="{{ path('ASFTaskBundle_task_new2') }}">Insert a new task</a></p>
{% endif %}
{% endblock message %}
{% endblock maincolumn %}
{% block rightcolumn %}
{% endblock rightcolumn %}
vi src/ASF/TaskBundle/Resources/views/Default/success.html.twig
{% extends "ASFTaskBundle:Default:new2desplegado.html.twig" %}
{% block title %}
job Stored
{% endblock title %}
{% block header %}
<div id="header">
<div id="titulo-centro">
<h1>Tarea guardada</h1>
</div>
</div>
{% endblock header %}
{% block breadcrumbs %}
<ul>
<li class"=first"><a href="/">HOME </a></li>
<li class="actual"><a href="/ASF/template">Template</a></li>
<li class="last">Tarea completada</li>
</ul>
{% endblock breadcrumbs %}
{% block maincolumn %}
{% block message %}
{{ message|raw }}
<br /><br />
<p>Use the links in the menu to perform a new task or view existing tasks</p>
{% endblock message %}
{% endblock maincolumn %}
vi src/ASF/TaskBundle/Resources/views/Default/edit2desplegado.html.twig
{# src/ASF/TaskBundle/Resources/views/Default/new2desplegado.html.twig #}
{% extends "ASFTaskBundle:Default:template-base.html.twig" %}
{% block title %}
modify Task
{% endblock title %}
{% block header %}
<div id="header">
<div id="titulo-centro">
<h1>MODIFY TASK</h1>
</div>
</div>
{% endblock header %}
{% block breadcrumbs %}
<ul>
<li class"=first"><a href="/">HOME </a></li>
<li class="actual"><a href="/ASF/template">Template</a></li>
<li class="last">Editar tarea</li>
</ul>
{% endblock breadcrumbs %}
{% block maincolumn %}
{% block message %}
{% endblock message %}
<div id="form-div" style="width: 800px; margin:auto; padding:10px;">
<form action="{{ path('ASFTaskBundle_task_edit', { 'id' : id } ) }}" method="post" {{ form_enctype(form) }}>
<div id="errores_form" class="error">
<!-- general errors of the form -->
{{ form_errors(form) }}
</div>
<div id="formcontent">
<table style="border-collapse:separate; border-spacing:1em;">
<tr>
<td>{{ form_label(form.task) }}</td>
<td>{{ form_widget(form.task) }}</td>
<td class="error">{{ form_errors(form.task) }}</td>
</tr>
<tr>
<td>{{ form_label(form.dueDate) }}</td>
<td>{{ form_widget(form.dueDate) }}</td>
<td class="error">{{ form_errors(form.dueDate) }}</td>
</tr>
<tr>
<td>{{ form_label(form.description) }}</td>
<td>{{ form_widget(form.description) }}</td>
<td class="error">{{ form_errors(form.description) }}</td>
</tr>
<tr>
<td>{{ form_label(form.url) }}</td>
<td>{{ form_widget(form.url) }}</td>
<td class="error">{{ form_errors(form.url) }}</td>
</tr>
<tr></tr>
<tr>{{ form_rest(form) }}</tr>
<tr>
<td></td>
<td><input type="submit" formnovalidate /></td>
<tr> </table> </div>
<br />
</form>
</div>
{% endblock maincolumn %}
{% block rightcolumn %}
<p>Use the form to edit the new task</p>
{% endblock rightcolumn %}
vi src/ASF/TaskBundle/Resources/public/css/layout/reset.css
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;vertical-align:baseline;background:transparent}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:'';content:none}:focus{outline:0}ins{text-decoration:none}del{text-decoration:line-through}table{border-collapse:collapse;border-spacing:0}
vi src/ASF/TaskBundle/Resources/public/css/layout/colors.css
a{color:#A90641}a:hover{color:#A90641}a:visited{color:#A90641}a:active{color:#A90641} body{ background:#464646; color:#333;} #content{ color:#EEE; font-size: 0.8em;background-color: #343333;} #header{color:#FCFAD0;border-bottom:thick double #A90641;background:#111;}#footer{font-size:0.7em;border-top:thick double #A90641;background: #111;color:#5B605F;font-weight:bold;}#menu-sub a{font-size:0.8em; color:#A90641;}#menu-sub {padding-left:5px;}#menu-sub a:hover{font-size:0.8em; color:#CB2863;}#menu-sub a:visited{font-size:0.8em; color:#A90641;}#titulo-centro{margin:auto; width: 920px;padding:20px;text-align:center;}#breadcrumbs a{color:#A90641}.actual a{font-weight:bold;}
vi src/ASF/TaskBundle/Resources/public/css/layout/mainStyle.css
.tt1 {background:#FF0000;}
.tt2 {background:#FF00FF;}
.tt3 {background:#FFFF00;}
html { }
body {font: 13px/1.5 Verdana, Arial, sans-serif; background:url(../_images/bck2.jpg) 50% 0 repeat-x;}
a:focus {outline: 1px dotted invert;}
a:link {color:#000; text-decoration:none;}
a:visited {color:#000; text-decoration:none;}
a:hover {color:#000; text-decoration:none;}
a:active {color:#000; text-decoration:none;}
#footer a:link {color:#666; text-decoration:none;}
#footer a:visited {color:#666; text-decoration:none;}
#footer a:hover {color:#666; text-decoration:none;}
#footer a:active {color:#666; text-decoration:none;}
hr {border-color: #ccc; border-style: solid; border-width: 1px 0 0; clear: both; height: 0;}
p { }
sup {position: relative;top: -3px;vertical-align: top;font-size: 80%;}
sub {position: relative;bottom: -5px;vertical-align: top;font-size: 80%;}
h1 {font-size: 25px;}
h2 {font-size: 23px;}
h3 {font-size: 21px;}
h4 {font-size: 19px;}
h5 {font-size: 17px;}
h6 {font-size: 15px;}
.xxsmall {font-size: 10px;}
.xsmall {font-size: 12px;}
.small {font-size: 14px;}
.medium {font-size: 16px;}
.large {font-size: 22px;}
.xlarge {font-size: 26px;}
.xxlarge {font-size: 32px;}
ol {list-style: decimal;}
ul {list-style: square;}
li {margin-left: 30px;}
p, dl, hr, h1, h2, h3, h4, h5, h6, ol, ul, pre, table, address, fieldset {margin-bottom: 20px;}
#wrapper {overflow:hidden; width:960px; margin:20px auto;}
html body * span.clear,html body * div.clear,html body * li.clear,html body * dd.clear{background:none;border:0;clear:both;display:block;float:none;font-size:0;list-style:none;margin:0;padding:0;overflow:hidden;visibility:hidden;width:0;height:0}
.margin-left {margin-left:20px;}
.margin-right {margin-right:20px;}
.margin-top {margin-top:20px;}
.margin-bottom {margin-bottom:20px;}
.margin-left-half {margin-left:10px;}
.margin-right-half {margin-right:10px;}
.margin-top-half {margin-top:10px;}
.margin-bottom-half {margin-bottom:10px;}
.margin-bottom-none {margin-bottom:0;}
img.centered {display:block;margin-left:auto;margin-right:auto;}
img.alignright {display: inline;}
img.alignleft {display: inline;}
.alignright {float:right;}
.alignleft {float:left;}
.bold {font-weight:bold;}
.italic {font-style:italic;}
.text-left {text-align:left;}
.text-right {text-align:right;}
.uppercase {text-transform:uppercase;}
.text-justify{text-align:justify;}
/*=================MAIN END==============*/
/* BREADCRUMBS! */
#breadcrumbs {margin-left:160px;}
#breadcrumbs ul li{display: inline; }
#breadcrumbs ul li:before{ content:"\00BB \0020";}
/*=================HEADER START==============*/
#header {width:960px;float:left; min-height: 80px;}
/*=================HEADER END==============*/
/*=================CONTENT START==============*/
#content {width:960px;float:left; padding-top:10px; padding-bottom: 10px;}
/*======LEFT COLUMN START======*/
#left-column {width:160px;float:left;}
#menu-sub {float:left;}
#menu-sub ul {list-style:none;}
#menu-sub ul li {font-size:16px;}
/*======LEFT COLUMN END======*/
/*======MAIN COLUMN START======*/
#main-column {width:630px;float:left;padding-right:10px;}
/*======MAIN COLUMN END======*/
/*======RIGHT COLUMN START======*/
#right-column {width:140px;float:left;padding-left:10px; padding-right:10px;}
/*======RIGHT COLUMN END======*/
/*=================CONTENT END==============*/
/*=================FOOTER START==============*/
#footer {width:960px;float:left;text-align:center;color:#666; min-height:30px; padding: 15px;}
/*=================FOOTER END==============*/
? app/console cache:clear --env=dev
? php app/console assets:install web
http://symfony2/web/app_dev.php/show
http://symfony2/web/app_dev.php/new
php app/console doctrine:schema:update --force
The Templates (view) + Assets (Css)
php
app/console doctrine:generate:entities curso/TaskBundle/Entity/Task -
See more at:
http://www.leccionespracticas.com/informatica-web/symfony-create-and-update-an-entity-using-doctrine-full-example/#sthash.xitlSIsZ.dpuf
php
app/console doctrine:generate:entities curso/TaskBundle/Entity/Task -
See more at:
http://www.leccionespracticas.com/informatica-web/symfony-create-and-update-an-entity-using-doctrine-full-example/#sthash.xitlSIsZ.dpuf
Tuesday, August 20, 2013
File System Fuction
use Symfony\Component\Finder\Finder;
$finder = new Finder();
$iterator = $finder
->files()
->name('*.php')
->depth(0)
->size('>= 1K')
->in(__DIR__);
foreach ($iterator as $file) {
print $file->getRealpath()."\n";
}
$finder = new Finder();
$iterator = $finder
->files()
->name('*.php')
->depth(0)
->size('>= 1K')
->in(__DIR__);
foreach ($iterator as $file) {
print $file->getRealpath()."\n";
}
Friday, August 16, 2013
Creating Bundle Basic With Database - super fast
For Symfony2.3
1. Download Symfony2 Standard Edition
2. extract :
php app/console generate:bundle --namespace=
1. Download Symfony2 Standard Edition
2. extract :
tar
-zxvf Symfony_Standard_Vendors_2.0.0BETA2.tgz
3. set permission :
chmod
777 app
/cache
app
/logs
4.
Point your server to “web/” as root directory and you already would have to see symfony2 welcome page at http://127.0.0.1/app_dev.php/
5. setup database config:
vi
app/config/parameter.yml
6.
Creating our first bundleASF
/Bundle/StoreBundle --no-interaction
7. add
to app/AppKernel.php :
$bundles
=
array
(
// ...
new
ASF
\StoreBundle\ASFStoreBundle(),
);
8. add to app/config/routing.yml
asf_store:
resource: "@ASFStoreBundle/Resources/config/routing.yml"
prefix: /store
9. Creating a controller :
vi src/ASF/StoreBundle/Controller/StoreController.php
//ASF/StoreBundle/Controller/StoreController.php
<?php
namespace
ASF
\StoreBundle\Controller;
use
Symfony\Bundle\FrameworkBundle\Controller\Controller;
use
Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
class
StoreController
extends
Controller
{
/**
* @Template()
*/
public
function
indexAction(
$store
)
{
return
array
(
'store'
=>
$store
);
}
}
10. add to src/ASF/StoreBundle/Resources/config/routing.yml
asf_mystore:
pattern: /store/{store}
defaults: { _controller: ASFStoreBundle:Store:index }
11. add a view
vi src/ASF/StoreBundle/Resources/views/Store/index.html.twig
So you want store "{{ store }}"?
12. Done
going to http://127.0.0.1/app_dev.php/store/my-store
13. Model
- define a model store/category
- Store model
- vi
ASF/StoreBundle/Entity/Store.php
<?php
// ASF/storeBundle/Entity/Store.php
namespace
ASF
\StoreBundle\Entity;
use
Doctrine\ORM\Mapping
as
ORM;
/**
* @ORM\Entity
*/
class
Store
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected
$id
;
/**
* @ORM\ManyToMany(targetEntity="Category")
* @ORM\JoinTable(name="stores_categories",
* joinColumns={@ORM\JoinColumn(name="store_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="category_id", referencedColumnName="id")})
*/
protected
$categories
;
/**
* @ORM\Column(type="string", length=255)
*/
protected
$url
;
/**
* @ORM\Column(type="string", length=255)
*/
protected
$name
;
/**
* @ORM\Column(type="integer")
*/
protected
$clicks
= 0;
/**
* @ORM\Column(type="boolean")
*/
protected
$validated
= false;
/**
* @ORM\Column(type="integer")
*/
protected
$pcomments
= 0;
/**
* @ORM\Column(type="integer")
*/
protected
$ncomments
= 0;
/**
* @ORM\Column(type="boolean")
*/
protected
$active
= false;
/**
* @ORM\Column(type="datetime", name="updated_at")
*/
protected
$updatedAt
;
/**
* @ORM\Column(type="datetime", name="created_at")
*/
protected
$createdAt
;
public
function
__construct()
{
$this
->categories =
new
\Doctrine\Common\Collections\ArrayCollection();
$this
->createdAt =
new
\DateTime();
$this
->updatedAt =
new
\DateTime();
}
}
- Store model
- vi
ASF/StoreBundle/Entity/Category.php
<?php
// ASF/StoreBundle/Entity/Category.php
namespace
ASF
\StoreBundle\Entity;
use
Doctrine\ORM\Mapping
as
ORM;
/**
* @ORM\Entity
*/
class
Category
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected
$id
;
/**
* @ORM\OneToMany(targetEntity="Category", mappedBy="parent")
*/
protected
$children
;
/**
* @ORM\ManyToOne(targetEntity="Category", inversedBy="children")
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
* @ORM\Column(nullable=true)
*/
protected
$parent
;
/**
* @ORM\ManyToMany(targetEntity="Store", mappedBy="categories")
*/
protected
$stores
;
/**
* @ORM\Column(type="string", length=255)
*/
protected
$name
;
/**
* @ORM\Column(type="string", length=255, name="url_string", unique=true)
*/
protected
$urlString
;
public
function
__construct()
{
$this
->stores =
new
\Doctrine\Commmon\Collections\ArrayCollection();
}
}
Creating Tables :
php app
/console
doctrine:schema:create
Creating Getters & Setters
php app
/console
doctrine:generate:entities ASFStoreBundle
14. Test the module
add to the routing the storeAction:
vi src/ASF/StoreBundle/Resources/config/routing.yml
asf_mystore:
pattern: /store/{store}
defaults: { _controller: ASFStoreBundle:Store:store }
asf_mystore_index:
pattern: /store/
defaults: { _controller: ASFStoreBundle:Store:index }
vi src/ASF/StoreBundle/Controller/StoreController.php
<?php
//ASF/StoreBundle/Controller/StoreController.php
namespace ASF\StoreBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
class StoreController extends Controller
{
/**
* @Template()
*/
public function indexAction()
{
$em = $this->get('doctrine.orm.entity_manager');
$stores = $em->createQuery('SELECT count(s.id) AS total FROM ASF\StoreBundle\Entity\Store s')->getSingleScalarResult();
return array('stores' => $stores);
}
/**
* @Template()
*/
public function storeAction($store)
{
return array('store' => $store);
}
}
vi src/ASF/StoreBundle/Resources/views/Store/index.html.twig
vi src/ASF/StoreBundle/Resources/views/Store/store.html.twig
add to the routing the storeAction:
vi src/ASF/StoreBundle/Resources/config/routing.yml
asf_mystore:
pattern: /store/{store}
defaults: { _controller: ASFStoreBundle:Store:store }
asf_mystore_index:
pattern: /store/
defaults: { _controller: ASFStoreBundle:Store:index }
vi src/ASF/StoreBundle/Controller/StoreController.php
<?php
//ASF/StoreBundle/Controller/StoreController.php
namespace ASF\StoreBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
class StoreController extends Controller
{
/**
* @Template()
*/
public function indexAction()
{
$em = $this->get('doctrine.orm.entity_manager');
$stores = $em->createQuery('SELECT count(s.id) AS total FROM ASF\StoreBundle\Entity\Store s')->getSingleScalarResult();
return array('stores' => $stores);
}
/**
* @Template()
*/
public function storeAction($store)
{
return array('store' => $store);
}
}
vi src/ASF/StoreBundle/Resources/views/Store/index.html.twig
<!-- Montes/AdictosBundle/Resources/views/Store/index.html.twig -->
We have a total of {{ stores }} stores.
vi src/ASF/StoreBundle/Resources/views/Store/store.html.twig
<!-- Montes/AdictosBundle/Resources/views/Store/store.html.twig -->
So you want store "{{ store }}"?
Thursday, August 15, 2013
Making a framework on top of symfony2
Summary from http://fabien.potencier.org/article/51/create-your-own-framework-on-top-of-the-symfony2-components-part-1 -12
$ mkdir framework
$ cd
framework
$ vi composer.json
{
"require": {
"symfony/class-loader": "2.1.*"
}
}
:wq
$ wget http://getcomposer.org/composer.phar
$
# or
$ curl -O http://getcomposer.org/composer.phar
$ php composer.phar install
$ vi autoload.php
<?php // framework/autoload.php require_once __DIR__.'/vendor/symfony/class-loader/Symfony/Component/ClassLoader/UniversalClassLoader.php'; use Symfony\Component\ClassLoader\UniversalClassLoader; $loader = new UniversalClassLoader(); $loader->register();
:wq
$ php autoload.php
$ vi index.php (error version if no get parameter supply)
<?php // framework/index.php $input = $_GET['name']; printf('Hello %s', $input);
:wq
=> go to http://localhost and it will show hello
$ vi index.php (unsecure version : Internet security issue, XSS (Cross-Site Scripting))
<?php // framework/index.php $input = isset($_GET['name']) ? $_GET['name'] : 'World'; printf('Hello %s', $input);
:wq
$vi index.php (secure versinon)
<?php $input = isset($_GET['name']) ? $_GET['name'] : 'World'; header('Content-Type: text/html; charset=utf-8'); printf('Hello %s', htmlspecialchars($input, ENT_QUOTES, 'UTF-8'));
:wq
==>test unit
vi test.php
<?php // framework/test.php class IndexTest extends \PHPUnit_Framework_TestCase { public function testHello() { $_GET['name'] = 'Fabien'; ob_start(); include 'index.php'; $content = ob_get_clean(); $this->assertEquals('Hello Fabien', $content); } }
:wq
=> At this point, if you are not convinced that security and testing are indeed two very good reasons to stop writing code the old way and adopt a framework instead
In PHP, the request is represented by global variables ($_GET
,$_POST
,$_FILE
,$_COOKIE
,$_SESSION
...) and the response is generated by functions (echo
,header
,setcookie
, ...).
=>better code : Object-Oriented approach, Symfony2 HttpFoundation component
$ vi framework/composer.json { "require": { "symfony/class-loader": "2.1.*", "symfony/http-foundation": "2.1.*" } }
:wq
php composer.phar update
vi autoload.php add at bootom :
<?php // framework/autoload.php $loader->registerNamespace('Symfony\\Component\\HttpFoundation', __DIR__.'/vendor/symfony/http-foundation');
wq:
$ vi index.php
<?php // framework/index.php require_once __DIR__.'/autoload.php'; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; $request = Request::createFromGlobals(); $input = $request->get('name', 'World'); $response = new Response(sprintf('Hello %s', htmlspecialchars($input, ENT_QUOTES, 'UTF-8'))); $response->send();
:wq
$ vi bye.php
<?php // framework/bye.php require_once __DIR__.'/autoload.php'; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; $request = Request::createFromGlobals(); $response = new Response('Goodbye!'); $response->send();
:wq
$ vi init.php
<?php // framework/init.php require_once __DIR__.'/autoload.php'; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; $request = Request::createFromGlobals(); $response = new Response();
:wq
$ vi index.php<?php // framework/index.php require_once __DIR__.'/init.php'; $input = $request->get('name', 'World'); $response->setContent(sprintf('Hello %s', htmlspecialchars($input, ENT_QUOTES, 'UTF-8'))); $response->send();
wq
$ vi bye.php
<?php // framework/bye.php require_once __DIR__.'/init.php'; $response->setContent('Goodbye!'); $response->send();
:wq
$ vi front.php
<?php // framework/front.php require_once __DIR__.'/autoload.php'; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; $request = Request::createFromGlobals(); $response = new Response(); $map = array( '/hello' => __DIR__.'/hello.php', '/bye' => __DIR__.'/bye.php', ); $path = $request->getPathInfo(); if (isset($map[$path])) { require $map[$path]; } else { $response->setStatusCode(404); $response->setContent('Not Found'); } $response->send();
:wq
$ vi hello.php
<?php // framework/hello.php $input = $request->get('name', 'World'); $response->setContent(sprintf('Hello %s', htmlspecialchars($input, ENT_QUOTES, 'UTF-8')));
:wq
==> http://example.com/front.php/hello?name=Fabien
==>
http://example.com/front.php/bye
Now that the web server always access the same script (front.php
) for all
our pages, we can secure our code further by moving all other PHP files
outside the web root directory:example.com
??? composer.json
? src
? ??? autoload.php
? ??? pages
? ??? hello.php
? ??? bye.php
??? vendor
??? web
??? front.php
Now, configure your web server root directory to point to
web/
and all
other files won't be accessible from the client anymore.vi src/pages/hello.php
<!-- example.com/src/pages/hello.php --> <?php $name = $request->get('name', 'World') ?> Hello <?php echo htmlspecialchars($name, ENT_QUOTES, 'UTF-8') ?>
:wq
$ vi web/front.php
<?php // example.com/web/front.php require_once __DIR__.'/../src/autoload.php'; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; $request = Request::createFromGlobals(); $response = new Response(); $map = array( '/hello' => __DIR__.'/../src/pages/hello.php', '/bye' => __DIR__.'/../src/pages/bye.php', ); $path = $request->getPathInfo(); if (isset($map[$path])) { ob_start(); include $map[$path]; $response->setContent(ob_get_clean()); } else { $response->setStatusCode(404); $response->setContent('Not Found'); } $response->send();
:wq
..
.
.
.
.
.
.
.
That's it! Our application has now four different layers and each of them has a well defined goal:
web/front.php
: The front controller; the only exposed PHP code that makes the interface with the client (it gets the Request and sends the Response) and provides the boiler-plate code to initialize the framework and our application;src/Simplex
: The reusable framework code that abstracts the handling of incoming Requests (by the way, it makes your controllers/templates easily testable -- more about that later on);src/Calendar
: Our application specific code (the controllers and the model);src/app.php
: The application configuration/framework customization.
Subscribe to:
Posts (Atom)