Loading presentation...

Present Remotely

Send the link below via email or IM

Copy

Present to your audience

Start remote presentation

  • Invited audience members will follow you as you navigate and present
  • People invited to a presentation do not need a Prezi account
  • This link expires 10 minutes after you close the presentation
  • A maximum of 30 users can follow your presentation
  • Learn more about this feature in our knowledge base article

Do you really want to delete this prezi?

Neither you, nor the coeditors you shared it with will be able to recover it again.

DeleteCancel

Make your likes visible on Facebook?

Connect your Facebook account to Prezi and let your likes appear on your timeline.
You can change this under Settings & Account at any time.

No, thanks

Symfony2 Clase 4,5 y 6

Generando nuestra primera aplicacion
by

Tomas Cordoba

on 7 January 2013

Comments (0)

Please log in to add your comment.

Report abuse

Transcript of Symfony2 Clase 4,5 y 6

Lic. Tomás Córdoba cordoba.tomas@gmail.com 1. Todo el código se encuentra organizado en bundles. Por lo tanto debemos generar el bundle para nuestra aplicación. ¿Por donde empezamos? Creando nuestro primer controlador Introducción a Doctrine2 ¿Como se relaciona Symfony con nuestra Base de datos? Entidades Métodos de Mapeo Praparando las tablas en la DB Trabajando con datos persistidos A practicar!!
Grabar, recuperar y borrar de la DB Otros conceptos... Nuestra primera aplicación php app/console generate:boundle --namespace="Company/Namespace" --format=yml 2. Chequemos que se haya generado la estructura en el directorio /src AppKernel.php 1. Creamos la nueva ruta en el archivo routing.yml 2. Creamos el controlador que va a atender las peticiones 3. Creamos la función que atiende la petición especifica. Aprovechemos para mirar el directorio app/ Es el principal punto de entrada de la configuración de la aplicación Carga automatica de archivos La clase UniversalClassLoader se usa para cargar de forma automatica los archivos que respeten las normas estandar de espacios de nombres (namespaces) autoload.php config/routing.yml config/config.yml Se definen los patrones de las rutas que son aceptadas por la aplicación Archivo de configuración de parámetros de la aplicación Ejercicio: Debemos generar un arreglo con 10 valores y mostrarlos en pantalla cuando el usuario haga la peticion de "mostrararreglo". Utilizar estilos CSS y Bloques Twig Object Relational Mapper (ORM) para PHP que funciona sobre una poderoza capa de abstraccion (DBAL). Una de sus caracteristicas principales es la opcion de escribir consultas a la base de datos en un dialecto propietario orientado a objetos (DQL) inspirado por Hibernates (HQL). Esto provee a los desarrolladores de una poderoza alternativa a SQL que mantiene flexibilidad sin necesidad de duplicar codigo. Y con la posibilidad de migrar a otros motores de base de datos sin necesidad de reingenierias. Comencemos creando una base de datos vacia y asignandola a nuestro proyecto Symfony2:

Podemos utilizar la consola de MySQL o bien mediante PhpMyAdmin Escribimos los parametros de conexion con la base de datos en el archivo de configuracion

app/config/parameters.ini
[parameters]
database_driver = pdo_mysql
database_host = localhost
database_name = test_project
database_user = root
database_password = password


Luego podemos crear la base de datos en el servidor MySQL o bien ejecutar el siguiente commando:

php app/console doctrine:database:create Se debe crear una nueva carpeta en el bundle denominada "Entity", donde se almacenaran todas las clases que representan objetos de la base de datos. // src/Acme/StoreBundle/Entity/Product.php
namespace Acme\StoreBundle\Entity;

class Product
{
protected $name;

protected $price;

protected $description;
} Pero esta clase aún no puede ser almacenada porque es una simple clase PHP, Doctrine no sabe como persistirla en la base de datos. Agregando Mapeo para la entidad Creando nuestra primera entidad http://symfony.com/doc/current/book/doctrine.html Para que Doctrine tenga la capacidad de guardar en la base de datos los objetos, tenemos que crear "metadatos" o configuraciones que le digan a Doctrine exactamente como el objeto y sus propiedades deben mapearse en la base de datos.

Estos metadatos pueden ser especificados de diferentes formas, incluyendo YAML, XML, o con anotaciones directamente en la clase. # src/Acme/StoreBundle/Resources/config/doctrine/Product.orm.yml
Acme\StoreBundle\Entity\Product:
type: entity
table: product
id:
id:
type: integer
generator: { strategy: AUTO }
fields:
name:
type: string
length: 100
price:
type: decimal
scale: 2
description:
type: text En YAML Anotaciones // src/Acme/StoreBundle/Entity/Product.php
namespace Acme\StoreBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
* @ORM\Entity
* @ORM\Table(name="product")
*/
class Product
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;

/**
* @ORM\Column(type="string", length=100)
*/
protected $name;

/**
* @ORM\Column(type="decimal", scale=2)
*/
protected $price;

/**
* @ORM\Column(type="text")
*/
protected $description;
} XML <!-- src/Acme/StoreBundle/Resources/config/doctrine/Product.orm.xml -->
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">

<entity name="Acme\StoreBundle\Entity\Product" table="product">
<id name="id" type="integer" column="id">
<generator strategy="AUTO" />
</id>
<field name="name" column="name" type="string" length="100" />
<field name="price" column="price" type="decimal" scale="2" />
<field name="description" column="description" type="text" />
</entity>
</doctrine-mapping> Mas información en:
Tipos de datos aceptados por doctrine: http://symfony.com/doc/current/book/doctrine.html#book-doctrine-field-types php app/console doctrine:generate:entities Acme/StoreBundle/Entity/Product Luego de haber creado la configuracion para el mapeo es necesario generar los setters & getters para poder acceder a los datos, dado que son protegidos.
Por suerte, existe un commando que los genera automaticamente: De forma complementaria podemos generar todas las entidades de un bundle o namespace, que tengan mapeo realizado:

$ php app/console doctrine:generate:entities AcmeStoreBundle
$ php app/console doctrine:generate:entities Acme Ahora doctrine "sabe" como guardar los datos en la base de datos, pero aun no existen las tablas, para ello utilizamos el siguiente comando:

$ php app/console doctrine:schema:update --force

Este comando es muy importante, y compara que lo que se encuentra en la información de mapping sea lo mismo que lo que se encuentra en la base de datos. // src/Acme/StoreBundle/Controller/DefaultController.php

// ...
use Acme\StoreBundle\Entity\Product;
use Symfony\Component\HttpFoundation\Response;

public function createAction()
{
$product = new Product();
$product->setName('A Foo Bar');
$product->setPrice('19.99');
$product->setDescription('Lorem ipsum dolor');

$em = $this->getDoctrine()->getEntityManager();
$em->persist($product);
$em->flush();

return new Response('Created product id '.$product->getId());
} public function showAction($id)
{
$product = $this->getDoctrine()
->getRepository('AcmeStoreBundle:Product')
->find($id);

if (!$product) {
throw $this->createNotFoundException('No product found for id '.$id);
}

// ... do something, like pass the $product object into a template
} Grabar Recuperar Primero hay que obtener el repositorio del objeto que estamos trabajando mediante el siguiente metodo:

$repository = $this->getDoctrine()->getRepository('AcmeStoreBundle:Product');

// query by the primary key (usually "id")
$product = $repository->find($id);

// dynamic method names to find based on a column value
$product = $repository->findOneById($id);
$product = $repository->findOneByName('foo');

// find *all* products
$products = $repository->findAll();

// find a group of products based on an arbitrary column value
$products = $repository->findByPrice(19.99); Actualizando un objeto

public function updateAction($id)
{
$em = $this->getDoctrine()->getEntityManager();
$product = $em->getRepository('AcmeStoreBundle:Product')->find($id);

if (!$product) {
throw $this->createNotFoundException('No product found for id '.$id);
}

$product->setName('New product name!');
$em->flush();

return $this->redirect($this->generateUrl('homepage'));
} El siguiente comando se utiliza para publicar el contenido de la carpeta "Resources/public" de nuestros bundles en el directorio web. De modo que quede accesible para los usuarios:

php app/console assets:install web Para limpiar la cache, en caso de que hagamos modificaciones en archivos del entorno de produccion, podemos usar el siguiente comando:

php app/console cache:clear ¿Consultas? Gracias! Consultas Complejas con DQL $em = $this->getDoctrine()->getEntityManager();
$query = $em->createQuery(
'SELECT p FROM AcmeStoreBundle:Product p WHERE p.price > :price ORDER BY p.price ASC'
)->setParameter('price', '19.99');

$products = $query->getResult(); El metodo getResult() devuelve un arreglo de resultados.
El metodo getSingleResult() devuelve un solo objeto como resultado (el primero, pero arroja una exception en caso contrario). $query = $em->createQuery('SELECT ...')->setMaxResults(1);

try {
$product = $query->getSingleResult();
} catch (\Doctrine\Orm\NoResultException $e) {
$product = null;
} Doctrine's QueryBuilder $repository = $this->getDoctrine()
->getRepository('AcmeStoreBundle:Product');

$query = $repository->createQueryBuilder('p')
->where('p.price > :price')
->setParameter('price', '19.99')
->orderBy('p.price', 'ASC')
->getQuery();

$products = $query->getResult();
Con el fin de mantener la lógica del negocio separada, las consultas que se realizan sobre una tabla especifica como producto deben estar dentro de una clase repositorio especifica. // src/Acme/StoreBundle/Entity/Product.php
namespace Acme\StoreBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
* @ORM\Entity(repositoryClass="Acme\StoreBundle\Repository\ProductRepository")
*/
class Product
{
//...
}

--------------------------------------------------------------------------------------------------------------------------------------------

// src/Acme/StoreBundle/Repository/ProductRepository.php
namespace Acme\StoreBundle\Repository;

use Doctrine\ORM\EntityRepository;

class ProductRepository extends EntityRepository
{
public function findAllOrderedByName()
{
return $this->getEntityManager()
->createQuery('SELECT p FROM AcmeStoreBundle:Product p ORDER BY p.name ASC')
->getResult();
}
} Relaciones entre objetos (uno a muchos) // src/Acme/StoreBundle/Entity/Category.php

// ...
use Doctrine\Common\Collections\ArrayCollection;

class Category
{
// ...

/**
* @ORM\OneToMany(targetEntity="Product", mappedBy="category")
*/
protected $products;

public function __construct()
{
$this->products = new ArrayCollection();
}
} // src/Acme/StoreBundle/Entity/Product.php

// ...

class Product
{
// ...

/**
* @ORM\ManyToOne(targetEntity="Category", inversedBy="products")
* @ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
protected $category;
} ¿Como se guarda la relacion? // ...

use Acme\StoreBundle\Entity\Category;
use Acme\StoreBundle\Entity\Product;
use Symfony\Component\HttpFoundation\Response;

class DefaultController extends Controller
{
public function createProductAction()
{
$category = new Category();
$category->setName('Main Products');

$product = new Product();
$product->setName('Foo');
$product->setPrice(19.99);
// relate this product to the category
$product->setCategory($category);

$em = $this->getDoctrine()->getEntityManager();
$em->persist($category);
$em->persist($product);
$em->flush();

return new Response(
'Created product id: '.$product->getId().' and category id: '.$category->getId()
);
}
} Join categoria // src/Acme/StoreBundle/Repository/ProductRepository.php
public function findOneByIdJoinedToCategory($id)
{
$query = $this->getEntityManager()
->createQuery('
SELECT p, c FROM AcmeStoreBundle:Product p
JOIN p.category c
WHERE p.id = :id'
)->setParameter('id', $id);

try {
return $query->getSingleResult();
} catch (\Doctrine\ORM\NoResultException $e) {
return null;
}
} ó Life Cicles /**
* @ORM\Entity()
* @ORM\HasLifecycleCallbacks()
*/
class Product
{
// ...
}

------------------------------------------------------------------------------------------------------------------------------
/**
* @ORM\PrePersist
*/
public function setCreatedValue()
{
$this->created = new \DateTime();
}

Esto es util para setar valores cuando una entidad se crea o se edita. Los eventos disponibles son:
preRemove
postRemove
prePersist
postPersist
preUpdate
postUpdate
postLoad
loadClassMetadata type: (optional, defaults to ‘string’)
The mapping type to use for the column.

name: (optional, defaults to field name)
The name of the column in the database.

length: (optional, default 255)
The length of the column in the database. (Applies only if a string-valued column is used).

unique: (optional, default FALSE)
Whether the column is a unique key.

nullable: (optional, default FALSE)
Whether the database column is nullable.

precision: (optional, default 0)
The precision for a decimal (exact numeric) column. (Applies only if a decimal column is used.)

scale: (optional, default 0)
The scale for a decimal (exact numeric) column. (Applies only if a decimal column is used.) Opciones para las columnas del mapeo TExto agregado
Full transcript