SlideShare una empresa de Scribd logo
1 de 127
Workshop: Symfony2
introduction
Antonio Perić-Mažar, CEO
Luka Vidoš, Frontend Dev
04.09.2013, eZ Publish Summer Camp
Who we are?
• locastic – since 2010
• Web and mobile development
• UI/UX design
• Located in Split, Croatia
• 9 team members
• www.locastic.com
• studio@locastic.com
Our works?
Speakers?
• Antonio Perić-Mažar,
mag. ing. comp.
• CEO and partner @ locastic
• Last 6 years developing
custom web apps
• Last 3 years developing
custom apps with Symfony
• www.locastic.com
• antonio@locastic.com
• twitter: @antonioperic
Speakers?
• Luka Vidoš, mag. Diz.
• Frontend Dev @ locastic
●
Last 13 years designing, slicing
and implementing beautiful
web design into various web
apps
●
In love with Symfony for
last 3 years
• www.locastic.com
• luka@locastic.com
• twitter: @lukavidos
Symfony is project
●
PHP framework
●
Philosophy
●
Community
• Fabien Potencier,
SensioLabs (France)
• 2005. first version was relased
• 2007. symfony 1.0
• 2011. Symfony2
• ATM Symfony 2.3.4 (LTS)
10 criteria for choosing the correct
framework
1. Popularity and community size
2. Philosophy
3. Sustainability
4. Support
5. Technique
6. Security
7. Documentation ( always can be better )
8. License (free)
9. Availability of resources on the market
10. Try it out!
6 good reasons to use Symfony
1. Reputation
2. Permanence
3. References (Yahoo!, Dailymotion, Opensky.com, Exercise.com, phpBB, Drupal,
eZPublish,Youporn :) )
4. Innovation
5. Resources
6. Interoperability
The technological benefits of
Symfony in 6 easy lessons
1. Faster and less greedy
2. Unlimited flexibility
3. Expandable
4. Stable and sustainable
5. The joy of developing
6. Ease of use
Symfony2 community
• Github – 10 000+ commits, 5 branches, 50
releases, 746 contributors
●
1898 open source Bundles
(http://knpbundles.com/)
• Symfony2 CMF (Content Management
Framework), eZpublish, Drupal, Sylius
What are we going to do today?
What are we going to do today?
What are we going to do today?
To do list app
●
Creating unlimited number of task lists
●
Creating, deleting and updating lists
●
Creating, deleting and updating tasks inside of
lists
Let's go... How to install Sf2?
Instalation: Option A
http://getcomposer.org/
> php -r "eval('?>'.file_get_contents('
https://getcomposer.org/installer'));"
> php composer.phar
> php composer.phar create-project
symfony/framework-standard-edition
/path/to/webroot/Symfony 2.3.0
Instalation: Option B
Download, Extract, Start
Done!
What is inside?
What is inside?
> php app/console
Standalone Tools: The Symfony2
Components
HttpFoundation - Contains the Request and Response classes, as well as other classes for handling
sessions and file uploads;
Routing - Powerful and fast routing system that allows you to map a specific URI (e.g. /contact) to some
information about how that request should be handled (e.g. execute the contactAction() method);
Form - A full-featured and flexible framework for creating forms and handling form submissions;
Validator A system for creating rules about data and then validating whether or not user-submitted
data follows those rules;
ClassLoader An autoloading library that allows PHP classes to be used without needing to manually
require the files containing those classes;
Templating A toolkit for rendering templates, handling template inheritance (i.e. a template is
decorated with a layout) and performing other common template tasks;
Security - A powerful library for handling all types of security inside an application;
Translation A framework for translating strings in your application.
Coding standard
Structure
●
Add a single space after each comma delimiter;
●
Add a single space around operators (==, &&, ...);
●
Add a comma after each array item in a multi-line array, even after the last one;
●
Add a blank line before return statements, unless the return is alone inside a statement-group (like an if
statement);
●
Use braces to indicate control structure body regardless of the number of statements it contains;
●
Define one class per file - this does not apply to private helper classes that are not intended to be instantiated
from the outside and thus are not concerned by the PSR-0 standard;
●
Declare class properties before methods;
●
Declare public methods first, then protected ones and finally private ones;
●
Use parentheses when instantiating classes regardless of the number of arguments the constructor has;
●
Exception message strings should be concatenated using sprintf.
Coding standard
Naming Conventions
●
Use camelCase, not underscores, for variable, function and method names, arguments;
●
Use underscores for option names and parameter names;
●
Use namespaces for all classes;
●
Prefix abstract classes with Abstract. Please note some early Symfony2 classes do not follow this convention and
have not been renamed for backward compatibility reasons. However all new abstract classes must follow this
naming convention;
●
Suffix interfaces with Interface;
●
Suffix traits with Trait;
●
Suffix exceptions with Exception;
●
Use alphanumeric characters and underscores for file names;
●
Don't forget to look at the more verbose Conventions document for more subjective naming considerations.
Coding standard
Service Naming Conventions
●
A service name contains groups, separated by dots;
●
The DI alias of the bundle is the first group (e.g. fos_user);
●
Use lowercase letters for service and parameter names;
●
A group name uses the underscore notation;
●
Each service has a corresponding parameter containing the class name, following the SERVICE
NAME.class convention.
Documentation
●
Add PHPDoc blocks for all classes, methods, and functions;
●
Omit the @return tag if the method does not return anything;
●
The @package and @subpackage annotations are not used.
Coding standard
namespace Acme;
/**
* Coding standards demonstration.
*/
class FooBar
{
const SOME_CONST = 42;
private $fooBar;
...
Coding standard
/**
* @param string $dummy Some argument description
*/
public function __construct($dummy)
{
$this->fooBar = $this->transformText($dummy);
}
Coding standard
/**
* @param string $dummy Some argument
description
* @param array $options
*
* @return string|null Transformed input
*/
private function transformText($dummy,
array $options = array())
Coding standard
if (true === $dummy) {
return;
}
if ('string' === $dummy) {
if ('values' === $mergedOptions['some_default']) {
return substr($dummy, 0, 5);
}
return ucwords($dummy);
}
throw new RuntimeException(sprintf('Unrecognized dummy option "%s"', $dummy));
}
}
Creating Pages in Symfony2
Creating a new page in Symfony2 is a simple two-
step process:
●
Create a route: A route defines the URL (e.g. /about) to your page and
specifies a controller (which is a PHP function) that Symfony2 should
execute when the URL of an incoming request matches the route path;
●
Create a controller: A controller is a PHP function that takes the
incoming request and transforms it into the Symfony2 Response object
that's returned to the user.
●
Environment:
●
Prod, dev, test
But before... bundles :)
●
Bundle is everything in Symfony2 :) - first-
class citizens
●
Directory that houses everything related to a
specific feature ( configuration, PHP, JS, CSS...)
●
We can compare it with modul or plugin
●
Flexible, independent, powerful
> php app/console generate:bundle
Creating Pages in Symfony2
Step1: Create route
# app/config/routing.yml
acme_hello:
resource: "@AcmeHelloBundle/Resources/config/routing.yml"
prefix: /
# src/Acme/HelloBundle/Resources/config/routing.yml
hello:
path: /hello/{name}
defaults: { _controller: AcmeHelloBundle:Hello:index }
Creating Pages in Symfony2
Step2: Create controller
// src/Acme/HelloBundle/Controller/HelloController.php
namespace AcmeHelloBundleController;
use SymfonyComponentHttpFoundationResponse;
class HelloController
{
public function indexAction($name)
{
return new Response('<html><body>Hello '.$name.'!</body></html>');
}
}
Creating Pages in Symfony2
Step3: Create template
// src/Acme/HelloBundle/Controller/HelloController.php
namespace AcmeHelloBundleController;
use SymfonyBundleFrameworkBundleControllerController;
class HelloController extends Controller
{
public function indexAction($name)
{
return $this->render(
'AcmeHelloBundle:Hello:index.html.twig',
array('name' => $name)
);
}
}
Creating Pages in Symfony2
Practice #1:
- create controller that receives some integer as
parameter from route and returns template
with that number squared.
Time: 5 minutes
Controller
• Request -> Response
●
The response could be an HTML page, an XML document,
a serialized JSON array, an image, a redirect, a 404 error
or anything else you can dream up.
●
The controller contains whatever arbitrary logic your
application needs to render the content of a page.
use SymfonyComponentHttpFoundationResponse;
public function helloAction()
{
return new Response('Hello world!');
}
Requests, Controller, Response
Lifecycle
Simple Controller
// src/Acme/HelloBundle/Controller/HelloController.php
namespace AcmeHelloBundleController;
use SymfonyComponentHttpFoundationResponse;
class HelloController
{
public function indexAction($name)
{
return new Response('<html><body>Hello '.$name.'!</body></html>');
}
}
Mapping url to a Controller
# app/config/routing.yml
hello:
path: /hello/{first_name}/{last_name}
defaults: { _controller: AcmeHelloBundle:Hello:index, color: green }
// order of arguments does not metter
public function indexAction($first_name, $color, $last_name)
{
// ... do whatever logic and return Response
}
The Request as Controller
Argument
use SymfonyComponentHttpFoundationRequest;
public function updateAction(Request $request)
{
$form = $this->createForm(...);
$form->handleRequest($request);
// ...
}
The Base Controller Class
// src/Acme/HelloBundle/Controller/HelloController.php
namespace AcmeHelloBundleController;
use SymfonyBundleFrameworkBundleControllerController;
use SymfonyComponentHttpFoundationResponse;
class HelloController extends Controller
{
// ... do whatever logic and return Response
}
By extending this Controller class, you can take advantage of several helper
methods.
Common Controller Tasks
// redirecting
public function indexAction()
{
return $this->redirect($this->generateUrl('homepage'));
}
public function indexAction()
{
return $this->redirect($this->generateUrl('homepage'), 301);
}
Shortcut for:
use SymfonyComponentHttpFoundationRedirectResponse;
return new RedirectResponse($this->generateUrl('homepage'));
Common Controller Tasks
// forwarding
public function indexAction($name)
{
$response = $this->forward('AcmeHelloBundle:Hello:fancy', array(
'name' => $name,
'color' => 'green',
));
// ... further modify the response or return it directly
return $response;
}
public function fancyAction($name, $color)
{
// ... create and return a Response object
}
Common Controller Tasks
Shortcut for:
$httpKernel = $this->container->get('http_kernel');
$response = $httpKernel->forward(
'AcmeHelloBundle:Hello:fancy',
array(
'name' => $name,
'color' => 'green',
)
);
Common Controller Tasks
// rendering templates
use SymfonyComponentHttpFoundationResponse;
$content = $this->renderView(
'AcmeHelloBundle:Hello:index.html.twig',
array('name' => $name)
);
return new Response($content);
return $this->render(
'AcmeHelloBundle:Hello:index.html.twig',
array('name' => $name)
);
Common Controller Tasks
Shortcut for:
$templating = $this->get('templating');
$content = $templating->render(
'AcmeHelloBundle:Hello:index.html.twig',
array('name' => $name)
);
$templating->render(
'AcmeHelloBundle:Hello/Greetings:index.html.twig',
array('name' => $name)
);
404 error
public function indexAction()
{
// retrieve the object from database
$product = ...;
if (!$product) {
throw $this->createNotFoundException('The product does not exist');
}
return $this->render(...);
}
Error 500
throw new Exception('Something went wrong!');
Accessing other Services
$request = $this->getRequest();
$templating = $this->get('templating');
$router = $this->get('router');
$mailer = $this->get('mailer');
Accessing other Services
$request = $this->getRequest();
$templating = $this->get('templating');
$router = $this->get('router');
$mailer = $this->get('mailer');
> php app/console container:debug
Managing the Session
$session = $this->getRequest()->getSession();
// store an attribute for reuse during a later user request
$session->set('foo', 'bar');
// in another controller for another request
$foo = $session->get('foo');
// use a default value if the key doesn't exist
$filters = $session->get('filters', array());
Flash Messages
public function updateAction()
{
$form = $this->createForm(...);
$form->bind($this->getRequest());
if ($form->isValid()) {
// do some sort of processing
$this->get('session')->getFlashBag()->add('notice', 'Your changes were saved!');
return $this->redirect($this->generateUrl(...));
}
return $this->render(...);
}
Flash Messages
{% for flashMessage in app.session.flashbag.get('notice') %}
<div class="flash-notice">
{{ flashMessage }}
</div>
{% endfor %}
The Response Object
The only requirement for a controller is to return a Response object. The Response
class is a PHP abstraction around the HTTP response - the text-based message filled
with HTTP headers and content that's sent back to the client:
use SymfonyComponentHttpFoundationResponse;
// create a simple Response with a 200 status code (the default)
$response = new Response('Hello '.$name, 200);
// create a JSON-response with a 200 status code
$response = new Response(json_encode(array('name' => $name)));
$response->headers->set('Content-Type', 'application/json');
The Response Object - JSON
use SymfonyComponentHttpFoundationResponse;
$response = new Response();
$response->setContent(json_encode(array(
'data' => 123,
)));
$response->headers->set('Content-Type', 'application/json');
---
use SymfonyComponentHttpFoundationJsonResponse;
$response = new JsonResponse();
$response->setData(array(
'data' => 123
));
The Response Object - FILE
use SymfonyComponentHttpFoundationResponseHeaderBag;
$d = $response->headers-
>makeDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, 'foo.pdf');
$response->headers->set('Content-Disposition', $d);
---
use SymfonyComponentHttpFoundationBinaryFileResponse
$file = 'path/to/file.txt';
$response = new BinaryFileResponse($file);
The Request Object
$request = $this->getRequest();
$request->isXmlHttpRequest(); // is it an Ajax request?
$request->getPreferredLanguage(array('en', 'fr'));
$request->query->get('page'); // get a $_GET parameter
$request->request->get('page'); // get a $_POST parameter
Render static page
No need for controller!!!
acme_privacy:
path: /privacy
defaults:
_controller: FrameworkBundle:Template:template
template: 'AcmeBundle:Static:privacy.html.twig'
Controller
Practice #2:
●
send numbers via $_GET parameter (numA and numB). Get these two
numbers in controller from Request Object (using $_GET[] is forbidden).
Send Request object as action's parameter.
If numA*numB > 100 redirect to some custom controller's action;
If numA < 0 and numB < 0 throw 404 error;
If numA+numB > 10 return JSON Response with result;
else return template with result numA-numB;
Time: 10 minutes
Routing <3
index.php?article_id=57 -> don't like this
/i-like/symfony-routing
One of the most powerfull Symfony2 component. Very flexible!!!
Route = map form url to controller
Position of route is important!!!
Routing <3
// example (sylius):
locastic_product_review_list:
pattern: /review-for-product/{productId}
defaults:
_controller: locastic.controller.frontend.product_review:listReviewsForProductAction
locastic_product_review_add:
pattern: /add-review-for-product/{productId}
defaults:
_controller: locastic.controller.frontend.product_review:addReviewAction
_format: json
sylius_product_show:
pattern: /p/{slug}
defaults:
_controller: sylius.controller.product:showAction
_sylius:
template: SyliusWebBundle:Frontend/Product:show.html.twig
Routing <3
// 4 ways of defining routes
1.YAML
2.XML
3.PHP
4.Annotations
Routing - YAML
# app/config/routing.yml
blog_show:
path: /blog/{slug}
defaults: { _controller: AcmeBlogBundle:Blog:show }
Routing - XML
<!-- app/config/routing.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/routing
http://symfony.com/schema/routing/routing-1.0.xsd">
<route id="blog_show" path="/blog/{slug}">
<default key="_controller">AcmeBlogBundle:Blog:show</default>
</route>
</routes>
Routing - PHP
// app/config/routing.php
use SymfonyComponentRoutingRouteCollection;
use SymfonyComponentRoutingRoute;
$collection = new RouteCollection();
$collection->add('blog_show', new Route('/blog/{slug}', array(
'_controller' => 'AcmeBlogBundle:Blog:show',
)));
return $collection;
Routing - Annotations
/**
* @Route("/blog/{slug}", name=”blog_show”)
*/
public function showAction($slug)
{
// do whatever logic and return Response
}
Routing :)
Basic Route Configuration
_welcome:
path: /
defaults: { _controller: AcmeDemoBundle:Main:homepage }
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/routing
http://symfony.com/schema/routing/routing-1.0.xsd">
<route id="_welcome" path="/">
<default key="_controller">AcmeDemoBundle:Main:homepage</default>
</route>
</routes>
Routing with placeholder
blog_show:
path: /blog/{slug}
defaults: { _controller: AcmeBlogBundle:Blog:show }
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/routing
http://symfony.com/schema/routing/routing-1.0.xsd">
<route id="blog_show" path="/blog/{slug}">
<default key="_controller">AcmeBlogBundle:Blog:show</default>
</route>
</routes>
Required and Optional
Placeholder
blog:
path: /blog
defaults: { _controller: AcmeBlogBundle:Blog:index }
blog:
path: /blog/{page}
defaults: { _controller: AcmeBlogBundle:Blog:index }
blog:
path: /blog/{page}
defaults: { _controller: AcmeBlogBundle:Blog:index, page: 1 }
Required and Optional
Placeholder
blog:
path: /blog/{page}
defaults: { _controller: AcmeBlogBundle:Blog:index, page: 1 }
/blog {page} = 1
/blog/1 {page} = 1
/blog/2 {page} = 2
Adding Requirements
blog:
path: /blog/{page}
defaults: { _controller: AcmeBlogBundle:Blog:index, page: 1 }
blog_show:
path: /blog/{slug}
defaults: { _controller: AcmeBlogBundle:Blog:show }
URL route parameters
/blog/2 blog {page} = 2
/blog/my-blog-post blog {page} = my-blog-post
Adding Requirements
blog:
path: /blog/{page}
defaults: { _controller: AcmeBlogBundle:Blog:index, page: 1 }
requirements:
page: d+
URL route parameters
/blog/2 blog {page} = 2
/blog/my-blog-post blog_show {slug} = my-blog-post
Earlier Routes always Win!!!
What this all means is that the order of the
routes is very important. If the blog_show
route were placed above the blog route, the
URL /blog/2 would match blog_show instead
of blog since the {slug} parameter of
blog_show has no requirements. By using
proper ordering and clever requirements, you
can accomplish just about anything.
Adding Requirements
homepage:
path: /{culture}
defaults: { _controller: AcmeDemoBundle:Main:homepage, culture: en }
requirements:
culture: en|fr
/ {culture} = en
/en {culture} = en
/fr {culture} = fr
/es won't match this route
Adding HTTP Method
Requirements
contact:
path: /contact
defaults: { _controller: AcmeDemoBundle:Main:contact }
methods: [GET]
contact_process:
path: /contact
defaults: { _controller: AcmeDemoBundle:Main:contactProcess }
methods: [POST]
Advanced Routing Example
article_show:
path: /articles/{culture}/{year}/{title}.{_format}
defaults: { _controller: AcmeDemoBundle:Article:show, _format: html }
requirements:
culture: en|fr
_format: html|rss
year: d+
/articles/en/2010/my-post
/articles/fr/2010/my-post.rss
/articles/en/2013/my-latest-post.html
Including External Routing
Resources
# app/config/routing.yml
acme_hello:
resource: "@AcmeHelloBundle/Resources/config/routing.yml"
# src/Acme/HelloBundle/Resources/config/routing.yml
acme_hello:
path: /hello/{name}
defaults: { _controller: AcmeHelloBundle:Hello:index }
Prefixing Imported Routes
# app/config/routing.yml
acme_hello:
resource: "@AcmeHelloBundle/Resources/config/routing.yml"
prefix: /admin
Visualizing & Debugging Routes
While adding and customizing routes, it's helpful to be able to visualize and get
detailed information about your routes. A great way to see every route in your
application is via the router:debug console command. Execute the command by
running the following from the root of your project.
> php app/console router:debug
Generating URLs
class MainController extends Controller
{
public function showAction($slug)
{
// ...
$url = $this->generateUrl( // helper method
'blog_show',
array('slug' => 'my-blog-post')
);
}
}
Generating URLs
$params = $this->get('router')->match('/blog/my-blog-post');
// array(
// 'slug' => 'my-blog-post',
// '_controller' => 'AcmeBlogBundle:Blog:show',
// )
$uri = $this->get('router')->generate('blog_show', array('slug' => 'my-blog-post'));
// /blog/my-blog-post
$this->get('router')->generate('blog_show', array('slug' => 'my-blog-post'), true);
// http://www.example.com/blog/my-blog-post
Generating URLs
// with query string
$this->get('router')->generate('blog', array('page' => 2, 'category' => 'Symfony'));
// /blog/2?category=Symfony
// from template
<a href="{{ path('blog_show', {'slug': 'my-blog-post'}) }}">
Read this blog post.
</a>
<a href="{{ url('blog_show', {'slug': 'my-blog-post'}) }}">
Read this blog post.
</a>
Routing :)
Practice #3:
- create route for AcmeDemoBundle:Hello:list, that accepts parameters:
- category (string with no numbers)
- page number (integer)
- only GET method
In template list: category, slug and page number like this:
If url is: /ez-publish-summer-camp/3
Category slug: ez-publish-summer-camp
Page number: 3
Use YAML format for routing!
Time: 5 minutes
MODEL
ORM
Doctrine 2
parameters.yml → Config.yml
> php app/console doctrine:database:create
MODEL - metadata
// src/Acme/StoreBundle/Entity/Product.php
namespace AcmeStoreBundleEntity;
use DoctrineORMMapping as ORM;
/**
* @ORMEntity
* @ORMTable(name="product")
*/
class Product
{
/**
* @ORMId
* @ORMColumn(type="integer")
* @ORMGeneratedValue(strategy="AUTO")
*/
protected $id;
...
MODEL - metadata
..
/**
* @ORMColumn(type="string", length=100)
*/
protected $name;
/**
* @ORMColumn(type="decimal", scale=2)
*/
protected $price;
/**
* @ORMColumn(type="text")
*/
protected $description;
}
MODEL – metadata - YAML
# src/Acme/StoreBundle/Resources/config/doctrine/Product.orm.yml
AcmeStoreBundleEntityProduct:
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
MODEL – metadata - XML
<!-- src/Acme/StoreBundle/Resources/config/doctrine/Product.orm.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<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="AcmeStoreBundleEntityProduct" 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>
MODEL
A bundle can accept only one metadata definition format. For
example, it's not possible to mix YAML metadata definitions with
annotated PHP entity class definitions.
Be careful that your class name and properties aren't mapped to a
protected SQL keyword (such as group or user).
Create getters and setters
> php app/console doctrine:generate:entities
Acme/StoreBundle/Entity/Product
> php app/console doctrine:schema:update –force
Persist object to database
// src/Acme/StoreBundle/Controller/DefaultController.php
// ...
use AcmeStoreBundleEntityProduct;
use SymfonyComponentHttpFoundationResponse;
public function createAction()
{
$product = new Product();
$product->setName('A Foo Bar');
$product->setPrice('19.99');
$product->setDescription('Lorem ipsum dolor');
$em = $this->getDoctrine()->getManager();
$em->persist($product);
$em->flush();
return new Response('Created product id '.$product->getId());
}
Fetching Objects from the
Database
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
}
Repository Basic
// 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);
Repository Basic
// query for one product matching be name and price
$product = $repository->findOneBy(array('name' => 'foo', 'price' => 19.99));
// query for all products matching the name, ordered by price
$products = $repository->findBy(
array('name' => 'foo'),
array('price' => 'ASC')
);
How many queries?
Updating an Object
public function updateAction($id)
{
$em = $this->getDoctrine()->getManager();
$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'));
}
Deleting on object
$em->remove($product);
$em->flush();
Querying for Object with DQL
$em = $this->getDoctrine()->getManager();
$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();
Using Doctrine's Query Builder
$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();
Custom Repository Classes
// using annotations
// src/Acme/StoreBundle/Entity/Product.php
namespace AcmeStoreBundleEntity;
use DoctrineORMMapping as ORM;
/**
* @ORMEntity(repositoryClass="AcmeStoreBundleEntityProductRepository")
*/
class Product
{
//...
}
Custom Repository Classes
// using YAML
#src/Acme/StoreBundle/Resources/config/doctrine/Product.orm.yml
AcmeStoreBundleEntityProduct:
type: entity
repositoryClass: AcmeStoreBundleEntityProductRepository
# ...
Custom Repository Classes
// using XML
<!-- src/Acme/StoreBundle/Resources/config/doctrine/Product.orm.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<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="AcmeStoreBundleEntityProduct"
repository-class="AcmeStoreBundleEntityProductRepository">
<!-- ... -->
</entity>
</doctrine-mapping>
Custom Repository Classes
// src/Acme/StoreBundle/Entity/ProductRepository.php
namespace AcmeStoreBundleEntity;
use DoctrineORMEntityRepository;
class ProductRepository extends EntityRepository
{
public function findAllOrderedByName()
{
return $this->getEntityManager()
->createQuery(
'SELECT p FROM AcmeStoreBundle:Product p ORDER BY p.name ASC'
)
->getResult();
}
}
Custom Repository Classes
$em = $this->getDoctrine()->getManager();
$products = $em->getRepository('AcmeStoreBundle:Product')
->findAllOrderedByName();
MODEL – custom repository
public function updateGallery($photoId, $galleryId)
{
$qb = $this->createQueryBuilder('p');
$query = $qb
->update()
->set('p.gallery', $galleryId)
->where('p.id = :id')
->setParameter('id', $photoId);
return $query->getQuery()->execute();
}
Relationship Mapping Metadata
// src/Acme/StoreBundle/Entity/Category.php
// ...
use DoctrineCommonCollectionsArrayCollection;
class Category
{
// ...
/**
* @ORMOneToMany(targetEntity="Product", mappedBy="category")
*/
protected $products;
public function __construct()
{
$this->products = new ArrayCollection();
}
}
Product (n) <- (1) Category
Relationship Mapping Metadata
<!-- src/Acme/StoreBundle/Resources/config/doctrine/Category.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="AcmeStoreBundleEntityCategory">
<!-- ... -->
<one-to-many field="products"
target-entity="Product"
mapped-by="category"
/>
<!--
don't forget to init the collection in
the __construct() method of the entity
-->
</entity>
Product (n) <- (1) Category
Relationship Mapping Metadata
#src/Acme/StoreBundle/Resources/config/doctrine/Category.orm.yml
AcmeStoreBundleEntityCategory:
type: entity
# ...
oneToMany:
products:
targetEntity: Product
mappedBy: category
# don't forget to init the collection in the __construct() method of the
entity
Product (n) <- (1) Category
Relationship Mapping Metadata
// src/Acme/StoreBundle/Entity/Product.php
// ...
class Product
{
// ...
/**
* @ORMManyToOne(targetEntity="Category", inversedBy="products")
* @ORMJoinColumn(name="category_id", referencedColumnName="id")
*/
protected $category;
}
Product (n) <- (1) Category
Relationship Mapping Metadata
# src/Acme/StoreBundle/Resources/config/doctrine/Product.orm.yml
AcmeStoreBundleEntityProduct:
type: entity
# ...
manyToOne:
category:
targetEntity: Category
inversedBy: products
joinColumn:
name: category_id
referencedColumnName: id
Product (n) <- (1) Category
Relationship Mapping Metadata
<!-- 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="AcmeStoreBundleEntityProduct">
<!-- ... -->
<many-to-one field="category"
target-entity="Category"
inversed-by="products"
join-column="category"
>
<join-column
name="category_id"
referenced-column-name="id"
/>
</many-to-one>
Product (n) <- (1) Category
Relationship Mapping Metadata
Saving related entities
// ...
use AcmeStoreBundleEntityCategory;
use AcmeStoreBundleEntityProduct;
use SymfonyComponentHttpFoundationResponse;
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()->getManager();
$em->persist($category);
$em->persist($product);
Fetching related Objects
public function showAction($id)
{
$product = $this->getDoctrine()
->getRepository('AcmeStoreBundle:Product')
->find($id);
$categoryName = $product->getCategory()->getName();
// ...
}
Fetching related Objects
Fetching related Objects
public function showProductAction($id)
{
$category = $this->getDoctrine()
->getRepository('AcmeStoreBundle:Category')
->find($id);
$products = $category->getProducts();
// ...
}
Doctrine Field Types Reference
Strings
string (used for shorter strings)
text (used for larger strings)
Numbers
integer
smallint
bigint
decimal
float
Dates and Times (use a DateTime object for these fields in PHP)
date
time
datetime
Other Types
boolean
object (serialized and stored in a CLOB field)
array (serialized and stored in a CLOB field)
Some advanced stuff
Events and lifecycle callbacks
preRemove
postRemove
prePersist
postPersist
preUpdate
postUpdate
postLoad
LoadClassMetadata
Doctrine Extensions: Timestampable, Sluggable, etc.
MODEL
Practice #3:
- Create entities for schema bellow and create empty custom repository for
each, use XML
Time: 15 minutes
Download
PPT:
Www.locastic.com/ez2013/index.html
Or bitly.com/ez2013
Views And templates
Www.locastic.com/ez2013/view.zip
CRUD
→ create bundle
CRUD
→ create bundle
→ create entity
CRUD
→ create bundle
→ create entity
→ create full CRUD* with routes, controllers and templates
CRUD
→ create bundle
→ create entity
→ create full CRUD with routes, controllers and templates
→ use console :)
FORMS AND VALIDATION
Workshop: Symfony2 Forms – tomorrow 09:00am
Bernhard Schussek
The Symfony2 Form component helps you to build powerful forms with little code. This workshop shows you
how to use the component in your daily life.
Template
Twig!!! FTW!!!
Skipper: Luka Vidoš
Questions?
Thank you

Más contenido relacionado

La actualidad más candente

Ruby On Rails Seminar Basis Softexpo Feb2010
Ruby On Rails Seminar Basis Softexpo Feb2010Ruby On Rails Seminar Basis Softexpo Feb2010
Ruby On Rails Seminar Basis Softexpo Feb2010
arif44
 
Java Server Faces (JSF) - advanced
Java Server Faces (JSF) - advancedJava Server Faces (JSF) - advanced
Java Server Faces (JSF) - advanced
BG Java EE Course
 

La actualidad más candente (20)

Spring MVC
Spring MVCSpring MVC
Spring MVC
 
Component Framework Primer for JSF Users
Component Framework Primer for JSF UsersComponent Framework Primer for JSF Users
Component Framework Primer for JSF Users
 
JSF 2 and beyond: Keeping progress coming
JSF 2 and beyond: Keeping progress comingJSF 2 and beyond: Keeping progress coming
JSF 2 and beyond: Keeping progress coming
 
REST APIs in Laravel 101
REST APIs in Laravel 101REST APIs in Laravel 101
REST APIs in Laravel 101
 
Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5
 
Workshop 16: EmberJS Parte I
Workshop 16: EmberJS Parte IWorkshop 16: EmberJS Parte I
Workshop 16: EmberJS Parte I
 
Ruby On Rails Seminar Basis Softexpo Feb2010
Ruby On Rails Seminar Basis Softexpo Feb2010Ruby On Rails Seminar Basis Softexpo Feb2010
Ruby On Rails Seminar Basis Softexpo Feb2010
 
Rapid application development with FOF
Rapid application development with FOFRapid application development with FOF
Rapid application development with FOF
 
Java Server Faces (JSF) - advanced
Java Server Faces (JSF) - advancedJava Server Faces (JSF) - advanced
Java Server Faces (JSF) - advanced
 
Boston 2011 OTN Developer Days - Java EE 6
Boston 2011 OTN Developer Days - Java EE 6Boston 2011 OTN Developer Days - Java EE 6
Boston 2011 OTN Developer Days - Java EE 6
 
Unified Expression Language
Unified Expression LanguageUnified Expression Language
Unified Expression Language
 
Jsf2.0 -4
Jsf2.0 -4Jsf2.0 -4
Jsf2.0 -4
 
CakePHP
CakePHPCakePHP
CakePHP
 
Wykorzystanie form request przy implementacji API w Laravelu
Wykorzystanie form request przy implementacji API w LaraveluWykorzystanie form request przy implementacji API w Laravelu
Wykorzystanie form request przy implementacji API w Laravelu
 
Xke - Introduction to Apache Camel
Xke - Introduction to Apache CamelXke - Introduction to Apache Camel
Xke - Introduction to Apache Camel
 
Jsf presentation
Jsf presentationJsf presentation
Jsf presentation
 
Starting with PHP and Web devepolment
Starting with PHP and Web devepolmentStarting with PHP and Web devepolment
Starting with PHP and Web devepolment
 
Java Server Faces (JSF) - Basics
Java Server Faces (JSF) - BasicsJava Server Faces (JSF) - Basics
Java Server Faces (JSF) - Basics
 
Dexterity in the Wild
Dexterity in the WildDexterity in the Wild
Dexterity in the Wild
 
Servlet and jsp interview questions
Servlet and jsp interview questionsServlet and jsp interview questions
Servlet and jsp interview questions
 

Destacado (9)

Curso de Liferay 6.2: Unidad didáctica 04 Gestión de un Sitio Web
Curso de Liferay 6.2: Unidad didáctica 04 Gestión de un Sitio WebCurso de Liferay 6.2: Unidad didáctica 04 Gestión de un Sitio Web
Curso de Liferay 6.2: Unidad didáctica 04 Gestión de un Sitio Web
 
Curso Liferay 6.2: Unidad Didáctica 07 Colaboración
Curso Liferay 6.2: Unidad Didáctica 07 ColaboraciónCurso Liferay 6.2: Unidad Didáctica 07 Colaboración
Curso Liferay 6.2: Unidad Didáctica 07 Colaboración
 
Curso de Liferay 6.2: Unidad Didáctica 00 Introducción
Curso de Liferay 6.2: Unidad Didáctica 00 IntroducciónCurso de Liferay 6.2: Unidad Didáctica 00 Introducción
Curso de Liferay 6.2: Unidad Didáctica 00 Introducción
 
Curso Liferay 6.2: Unidad Didáctica 05 Workflow
Curso Liferay 6.2: Unidad Didáctica 05 WorkflowCurso Liferay 6.2: Unidad Didáctica 05 Workflow
Curso Liferay 6.2: Unidad Didáctica 05 Workflow
 
Curso Liferay 6.2: Unidad Didáctica 06 Gestion de Documentos
Curso Liferay 6.2: Unidad Didáctica 06 Gestion de DocumentosCurso Liferay 6.2: Unidad Didáctica 06 Gestion de Documentos
Curso Liferay 6.2: Unidad Didáctica 06 Gestion de Documentos
 
Curso de liferay 6.2: Unidad didáctica 02 Funcionalidades Principales
Curso de liferay 6.2: Unidad didáctica 02 Funcionalidades PrincipalesCurso de liferay 6.2: Unidad didáctica 02 Funcionalidades Principales
Curso de liferay 6.2: Unidad didáctica 02 Funcionalidades Principales
 
Curso de Liferay 6.2: Unidad didáctica 01 Instalación
Curso de Liferay 6.2: Unidad didáctica 01 InstalaciónCurso de Liferay 6.2: Unidad didáctica 01 Instalación
Curso de Liferay 6.2: Unidad didáctica 01 Instalación
 
Curso de Magento 1.9: Unidad Didáctica 08 Estructura de un Tema
Curso de Magento 1.9: Unidad Didáctica 08 Estructura de un TemaCurso de Magento 1.9: Unidad Didáctica 08 Estructura de un Tema
Curso de Magento 1.9: Unidad Didáctica 08 Estructura de un Tema
 
Liferay 6.2: Unidad Didáctica 03 Administración básica
Liferay 6.2: Unidad Didáctica 03 Administración básicaLiferay 6.2: Unidad Didáctica 03 Administración básica
Liferay 6.2: Unidad Didáctica 03 Administración básica
 

Similar a Workshop: Symfony2 Intruduction: (Controller, Routing, Model)

Decoupled Libraries for PHP
Decoupled Libraries for PHPDecoupled Libraries for PHP
Decoupled Libraries for PHP
Paul Jones
 
Symfony2 Introduction Presentation
Symfony2 Introduction PresentationSymfony2 Introduction Presentation
Symfony2 Introduction Presentation
Nerd Tzanetopoulos
 
The PHP mysqlnd plugin talk - plugins an alternative to MySQL Proxy
The PHP mysqlnd plugin talk - plugins an alternative to MySQL ProxyThe PHP mysqlnd plugin talk - plugins an alternative to MySQL Proxy
The PHP mysqlnd plugin talk - plugins an alternative to MySQL Proxy
Ulf Wendel
 

Similar a Workshop: Symfony2 Intruduction: (Controller, Routing, Model) (20)

Simplify your professional web development with symfony
Simplify your professional web development with symfonySimplify your professional web development with symfony
Simplify your professional web development with symfony
 
PHP Development Tools
PHP  Development ToolsPHP  Development Tools
PHP Development Tools
 
[HKDUG] #20161210 - BarCamp Hong Kong 2016 - What's News in PHP?
[HKDUG] #20161210 - BarCamp Hong Kong 2016 - What's News in PHP?[HKDUG] #20161210 - BarCamp Hong Kong 2016 - What's News in PHP?
[HKDUG] #20161210 - BarCamp Hong Kong 2016 - What's News in PHP?
 
Patterns in Python
Patterns in PythonPatterns in Python
Patterns in Python
 
Why Drupal is Rockstar?
Why Drupal is Rockstar?Why Drupal is Rockstar?
Why Drupal is Rockstar?
 
MobileConf 2021 Slides: Let's build macOS CLI Utilities using Swift
MobileConf 2021 Slides:  Let's build macOS CLI Utilities using SwiftMobileConf 2021 Slides:  Let's build macOS CLI Utilities using Swift
MobileConf 2021 Slides: Let's build macOS CLI Utilities using Swift
 
Aspect-oriented programming in Perl
Aspect-oriented programming in PerlAspect-oriented programming in Perl
Aspect-oriented programming in Perl
 
Decoupled Libraries for PHP
Decoupled Libraries for PHPDecoupled Libraries for PHP
Decoupled Libraries for PHP
 
Srgoc dotnet
Srgoc dotnetSrgoc dotnet
Srgoc dotnet
 
Composer Helpdesk
Composer HelpdeskComposer Helpdesk
Composer Helpdesk
 
The Naked Bundle - Symfony Usergroup Belgium
The Naked Bundle - Symfony Usergroup BelgiumThe Naked Bundle - Symfony Usergroup Belgium
The Naked Bundle - Symfony Usergroup Belgium
 
Symfony2 Introduction Presentation
Symfony2 Introduction PresentationSymfony2 Introduction Presentation
Symfony2 Introduction Presentation
 
Creating a modern web application using Symfony API Platform, ReactJS and Red...
Creating a modern web application using Symfony API Platform, ReactJS and Red...Creating a modern web application using Symfony API Platform, ReactJS and Red...
Creating a modern web application using Symfony API Platform, ReactJS and Red...
 
The Naked Bundle - Symfony Live London 2014
The Naked Bundle - Symfony Live London 2014The Naked Bundle - Symfony Live London 2014
The Naked Bundle - Symfony Live London 2014
 
C++ basics
C++ basicsC++ basics
C++ basics
 
The Beauty And The Beast Php N W09
The Beauty And The Beast Php N W09The Beauty And The Beast Php N W09
The Beauty And The Beast Php N W09
 
Strategies and Tips for Building Enterprise Drupal Applications - PNWDS 2013
Strategies and Tips for Building Enterprise Drupal Applications - PNWDS 2013Strategies and Tips for Building Enterprise Drupal Applications - PNWDS 2013
Strategies and Tips for Building Enterprise Drupal Applications - PNWDS 2013
 
The PHP mysqlnd plugin talk - plugins an alternative to MySQL Proxy
The PHP mysqlnd plugin talk - plugins an alternative to MySQL ProxyThe PHP mysqlnd plugin talk - plugins an alternative to MySQL Proxy
The PHP mysqlnd plugin talk - plugins an alternative to MySQL Proxy
 
Essential Tools for Modern PHP
Essential Tools for Modern PHPEssential Tools for Modern PHP
Essential Tools for Modern PHP
 
iOS Application Development
iOS Application DevelopmentiOS Application Development
iOS Application Development
 

Más de Antonio Peric-Mazar

Más de Antonio Peric-Mazar (20)

You call yourself a Senior Developer?
You call yourself a Senior Developer?You call yourself a Senior Developer?
You call yourself a Senior Developer?
 
Using API Platform to build ticketing system #symfonycon
Using API Platform to build ticketing system #symfonyconUsing API Platform to build ticketing system #symfonycon
Using API Platform to build ticketing system #symfonycon
 
Using API platform to build ticketing system (translations, time zones, ...) ...
Using API platform to build ticketing system (translations, time zones, ...) ...Using API platform to build ticketing system (translations, time zones, ...) ...
Using API platform to build ticketing system (translations, time zones, ...) ...
 
Are you failing at being agile? #digitallabin
Are you failing at being agile? #digitallabinAre you failing at being agile? #digitallabin
Are you failing at being agile? #digitallabin
 
Symfony 4: A new way to develop applications #ipc19
Symfony 4: A new way to develop applications #ipc19Symfony 4: A new way to develop applications #ipc19
Symfony 4: A new way to develop applications #ipc19
 
A year with progressive web apps! #webinale
A year with progressive web apps! #webinaleA year with progressive web apps! #webinale
A year with progressive web apps! #webinale
 
The UI is the THE application #dpc19
The UI is the THE application #dpc19The UI is the THE application #dpc19
The UI is the THE application #dpc19
 
Symfony 4: A new way to develop applications #phpsrb
 Symfony 4: A new way to develop applications #phpsrb Symfony 4: A new way to develop applications #phpsrb
Symfony 4: A new way to develop applications #phpsrb
 
REST easy with API Platform
REST easy with API PlatformREST easy with API Platform
REST easy with API Platform
 
A year with progressive web apps! #DevConMU
A year with progressive web apps! #DevConMUA year with progressive web apps! #DevConMU
A year with progressive web apps! #DevConMU
 
Service workers are your best friends
Service workers are your best friendsService workers are your best friends
Service workers are your best friends
 
Progressive Web Apps are here!
Progressive Web Apps are here!Progressive Web Apps are here!
Progressive Web Apps are here!
 
Building APIs in an easy way using API Platform
Building APIs in an easy way using API PlatformBuilding APIs in an easy way using API Platform
Building APIs in an easy way using API Platform
 
Symfony4 - A new way of developing web applications
Symfony4 - A new way of developing web applicationsSymfony4 - A new way of developing web applications
Symfony4 - A new way of developing web applications
 
Build your business on top of Open Source
Build your business on top of Open SourceBuild your business on top of Open Source
Build your business on top of Open Source
 
Building APIs in an easy way using API Platform
Building APIs in an easy way using API PlatformBuilding APIs in an easy way using API Platform
Building APIs in an easy way using API Platform
 
Lessons learned while developing with Sylius
Lessons learned while developing with SyliusLessons learned while developing with Sylius
Lessons learned while developing with Sylius
 
Drupal8 for Symfony developers - Dutch PHP
Drupal8 for Symfony developers - Dutch PHPDrupal8 for Symfony developers - Dutch PHP
Drupal8 for Symfony developers - Dutch PHP
 
Drupal8 for Symfony Developers (PHP Day Verona 2017)
Drupal8 for Symfony Developers (PHP Day Verona 2017)Drupal8 for Symfony Developers (PHP Day Verona 2017)
Drupal8 for Symfony Developers (PHP Day Verona 2017)
 
Drupal8 for Symfony Developers
Drupal8 for Symfony DevelopersDrupal8 for Symfony Developers
Drupal8 for Symfony Developers
 

Último

Gardella_Mateo_IntellectualProperty.pdf.
Gardella_Mateo_IntellectualProperty.pdf.Gardella_Mateo_IntellectualProperty.pdf.
Gardella_Mateo_IntellectualProperty.pdf.
MateoGardella
 
An Overview of Mutual Funds Bcom Project.pdf
An Overview of Mutual Funds Bcom Project.pdfAn Overview of Mutual Funds Bcom Project.pdf
An Overview of Mutual Funds Bcom Project.pdf
SanaAli374401
 
Activity 01 - Artificial Culture (1).pdf
Activity 01 - Artificial Culture (1).pdfActivity 01 - Artificial Culture (1).pdf
Activity 01 - Artificial Culture (1).pdf
ciinovamais
 

Último (20)

Gardella_Mateo_IntellectualProperty.pdf.
Gardella_Mateo_IntellectualProperty.pdf.Gardella_Mateo_IntellectualProperty.pdf.
Gardella_Mateo_IntellectualProperty.pdf.
 
Measures of Central Tendency: Mean, Median and Mode
Measures of Central Tendency: Mean, Median and ModeMeasures of Central Tendency: Mean, Median and Mode
Measures of Central Tendency: Mean, Median and Mode
 
Web & Social Media Analytics Previous Year Question Paper.pdf
Web & Social Media Analytics Previous Year Question Paper.pdfWeb & Social Media Analytics Previous Year Question Paper.pdf
Web & Social Media Analytics Previous Year Question Paper.pdf
 
Application orientated numerical on hev.ppt
Application orientated numerical on hev.pptApplication orientated numerical on hev.ppt
Application orientated numerical on hev.ppt
 
This PowerPoint helps students to consider the concept of infinity.
This PowerPoint helps students to consider the concept of infinity.This PowerPoint helps students to consider the concept of infinity.
This PowerPoint helps students to consider the concept of infinity.
 
Unit-V; Pricing (Pharma Marketing Management).pptx
Unit-V; Pricing (Pharma Marketing Management).pptxUnit-V; Pricing (Pharma Marketing Management).pptx
Unit-V; Pricing (Pharma Marketing Management).pptx
 
Advanced Views - Calendar View in Odoo 17
Advanced Views - Calendar View in Odoo 17Advanced Views - Calendar View in Odoo 17
Advanced Views - Calendar View in Odoo 17
 
PROCESS RECORDING FORMAT.docx
PROCESS      RECORDING        FORMAT.docxPROCESS      RECORDING        FORMAT.docx
PROCESS RECORDING FORMAT.docx
 
SOCIAL AND HISTORICAL CONTEXT - LFTVD.pptx
SOCIAL AND HISTORICAL CONTEXT - LFTVD.pptxSOCIAL AND HISTORICAL CONTEXT - LFTVD.pptx
SOCIAL AND HISTORICAL CONTEXT - LFTVD.pptx
 
Mehran University Newsletter Vol-X, Issue-I, 2024
Mehran University Newsletter Vol-X, Issue-I, 2024Mehran University Newsletter Vol-X, Issue-I, 2024
Mehran University Newsletter Vol-X, Issue-I, 2024
 
SECOND SEMESTER TOPIC COVERAGE SY 2023-2024 Trends, Networks, and Critical Th...
SECOND SEMESTER TOPIC COVERAGE SY 2023-2024 Trends, Networks, and Critical Th...SECOND SEMESTER TOPIC COVERAGE SY 2023-2024 Trends, Networks, and Critical Th...
SECOND SEMESTER TOPIC COVERAGE SY 2023-2024 Trends, Networks, and Critical Th...
 
Paris 2024 Olympic Geographies - an activity
Paris 2024 Olympic Geographies - an activityParis 2024 Olympic Geographies - an activity
Paris 2024 Olympic Geographies - an activity
 
Sports & Fitness Value Added Course FY..
Sports & Fitness Value Added Course FY..Sports & Fitness Value Added Course FY..
Sports & Fitness Value Added Course FY..
 
An Overview of Mutual Funds Bcom Project.pdf
An Overview of Mutual Funds Bcom Project.pdfAn Overview of Mutual Funds Bcom Project.pdf
An Overview of Mutual Funds Bcom Project.pdf
 
Mattingly "AI & Prompt Design: Structured Data, Assistants, & RAG"
Mattingly "AI & Prompt Design: Structured Data, Assistants, & RAG"Mattingly "AI & Prompt Design: Structured Data, Assistants, & RAG"
Mattingly "AI & Prompt Design: Structured Data, Assistants, & RAG"
 
Measures of Dispersion and Variability: Range, QD, AD and SD
Measures of Dispersion and Variability: Range, QD, AD and SDMeasures of Dispersion and Variability: Range, QD, AD and SD
Measures of Dispersion and Variability: Range, QD, AD and SD
 
Explore beautiful and ugly buildings. Mathematics helps us create beautiful d...
Explore beautiful and ugly buildings. Mathematics helps us create beautiful d...Explore beautiful and ugly buildings. Mathematics helps us create beautiful d...
Explore beautiful and ugly buildings. Mathematics helps us create beautiful d...
 
ICT Role in 21st Century Education & its Challenges.pptx
ICT Role in 21st Century Education & its Challenges.pptxICT Role in 21st Century Education & its Challenges.pptx
ICT Role in 21st Century Education & its Challenges.pptx
 
Activity 01 - Artificial Culture (1).pdf
Activity 01 - Artificial Culture (1).pdfActivity 01 - Artificial Culture (1).pdf
Activity 01 - Artificial Culture (1).pdf
 
Holdier Curriculum Vitae (April 2024).pdf
Holdier Curriculum Vitae (April 2024).pdfHoldier Curriculum Vitae (April 2024).pdf
Holdier Curriculum Vitae (April 2024).pdf
 

Workshop: Symfony2 Intruduction: (Controller, Routing, Model)

  • 1. Workshop: Symfony2 introduction Antonio Perić-Mažar, CEO Luka Vidoš, Frontend Dev 04.09.2013, eZ Publish Summer Camp
  • 2. Who we are? • locastic – since 2010 • Web and mobile development • UI/UX design • Located in Split, Croatia • 9 team members • www.locastic.com • studio@locastic.com
  • 4. Speakers? • Antonio Perić-Mažar, mag. ing. comp. • CEO and partner @ locastic • Last 6 years developing custom web apps • Last 3 years developing custom apps with Symfony • www.locastic.com • antonio@locastic.com • twitter: @antonioperic
  • 5. Speakers? • Luka Vidoš, mag. Diz. • Frontend Dev @ locastic ● Last 13 years designing, slicing and implementing beautiful web design into various web apps ● In love with Symfony for last 3 years • www.locastic.com • luka@locastic.com • twitter: @lukavidos
  • 6. Symfony is project ● PHP framework ● Philosophy ● Community • Fabien Potencier, SensioLabs (France) • 2005. first version was relased • 2007. symfony 1.0 • 2011. Symfony2 • ATM Symfony 2.3.4 (LTS)
  • 7. 10 criteria for choosing the correct framework 1. Popularity and community size 2. Philosophy 3. Sustainability 4. Support 5. Technique 6. Security 7. Documentation ( always can be better ) 8. License (free) 9. Availability of resources on the market 10. Try it out!
  • 8. 6 good reasons to use Symfony 1. Reputation 2. Permanence 3. References (Yahoo!, Dailymotion, Opensky.com, Exercise.com, phpBB, Drupal, eZPublish,Youporn :) ) 4. Innovation 5. Resources 6. Interoperability
  • 9. The technological benefits of Symfony in 6 easy lessons 1. Faster and less greedy 2. Unlimited flexibility 3. Expandable 4. Stable and sustainable 5. The joy of developing 6. Ease of use
  • 10. Symfony2 community • Github – 10 000+ commits, 5 branches, 50 releases, 746 contributors ● 1898 open source Bundles (http://knpbundles.com/) • Symfony2 CMF (Content Management Framework), eZpublish, Drupal, Sylius
  • 11. What are we going to do today?
  • 12. What are we going to do today?
  • 13. What are we going to do today?
  • 14. To do list app ● Creating unlimited number of task lists ● Creating, deleting and updating lists ● Creating, deleting and updating tasks inside of lists
  • 15. Let's go... How to install Sf2?
  • 16. Instalation: Option A http://getcomposer.org/ > php -r "eval('?>'.file_get_contents(' https://getcomposer.org/installer'));" > php composer.phar > php composer.phar create-project symfony/framework-standard-edition /path/to/webroot/Symfony 2.3.0
  • 18. Done!
  • 20. What is inside? > php app/console
  • 21. Standalone Tools: The Symfony2 Components HttpFoundation - Contains the Request and Response classes, as well as other classes for handling sessions and file uploads; Routing - Powerful and fast routing system that allows you to map a specific URI (e.g. /contact) to some information about how that request should be handled (e.g. execute the contactAction() method); Form - A full-featured and flexible framework for creating forms and handling form submissions; Validator A system for creating rules about data and then validating whether or not user-submitted data follows those rules; ClassLoader An autoloading library that allows PHP classes to be used without needing to manually require the files containing those classes; Templating A toolkit for rendering templates, handling template inheritance (i.e. a template is decorated with a layout) and performing other common template tasks; Security - A powerful library for handling all types of security inside an application; Translation A framework for translating strings in your application.
  • 22. Coding standard Structure ● Add a single space after each comma delimiter; ● Add a single space around operators (==, &&, ...); ● Add a comma after each array item in a multi-line array, even after the last one; ● Add a blank line before return statements, unless the return is alone inside a statement-group (like an if statement); ● Use braces to indicate control structure body regardless of the number of statements it contains; ● Define one class per file - this does not apply to private helper classes that are not intended to be instantiated from the outside and thus are not concerned by the PSR-0 standard; ● Declare class properties before methods; ● Declare public methods first, then protected ones and finally private ones; ● Use parentheses when instantiating classes regardless of the number of arguments the constructor has; ● Exception message strings should be concatenated using sprintf.
  • 23. Coding standard Naming Conventions ● Use camelCase, not underscores, for variable, function and method names, arguments; ● Use underscores for option names and parameter names; ● Use namespaces for all classes; ● Prefix abstract classes with Abstract. Please note some early Symfony2 classes do not follow this convention and have not been renamed for backward compatibility reasons. However all new abstract classes must follow this naming convention; ● Suffix interfaces with Interface; ● Suffix traits with Trait; ● Suffix exceptions with Exception; ● Use alphanumeric characters and underscores for file names; ● Don't forget to look at the more verbose Conventions document for more subjective naming considerations.
  • 24. Coding standard Service Naming Conventions ● A service name contains groups, separated by dots; ● The DI alias of the bundle is the first group (e.g. fos_user); ● Use lowercase letters for service and parameter names; ● A group name uses the underscore notation; ● Each service has a corresponding parameter containing the class name, following the SERVICE NAME.class convention. Documentation ● Add PHPDoc blocks for all classes, methods, and functions; ● Omit the @return tag if the method does not return anything; ● The @package and @subpackage annotations are not used.
  • 25. Coding standard namespace Acme; /** * Coding standards demonstration. */ class FooBar { const SOME_CONST = 42; private $fooBar; ...
  • 26. Coding standard /** * @param string $dummy Some argument description */ public function __construct($dummy) { $this->fooBar = $this->transformText($dummy); }
  • 27. Coding standard /** * @param string $dummy Some argument description * @param array $options * * @return string|null Transformed input */ private function transformText($dummy, array $options = array())
  • 28. Coding standard if (true === $dummy) { return; } if ('string' === $dummy) { if ('values' === $mergedOptions['some_default']) { return substr($dummy, 0, 5); } return ucwords($dummy); } throw new RuntimeException(sprintf('Unrecognized dummy option "%s"', $dummy)); } }
  • 29. Creating Pages in Symfony2 Creating a new page in Symfony2 is a simple two- step process: ● Create a route: A route defines the URL (e.g. /about) to your page and specifies a controller (which is a PHP function) that Symfony2 should execute when the URL of an incoming request matches the route path; ● Create a controller: A controller is a PHP function that takes the incoming request and transforms it into the Symfony2 Response object that's returned to the user. ● Environment: ● Prod, dev, test
  • 30. But before... bundles :) ● Bundle is everything in Symfony2 :) - first- class citizens ● Directory that houses everything related to a specific feature ( configuration, PHP, JS, CSS...) ● We can compare it with modul or plugin ● Flexible, independent, powerful > php app/console generate:bundle
  • 31. Creating Pages in Symfony2 Step1: Create route # app/config/routing.yml acme_hello: resource: "@AcmeHelloBundle/Resources/config/routing.yml" prefix: / # src/Acme/HelloBundle/Resources/config/routing.yml hello: path: /hello/{name} defaults: { _controller: AcmeHelloBundle:Hello:index }
  • 32. Creating Pages in Symfony2 Step2: Create controller // src/Acme/HelloBundle/Controller/HelloController.php namespace AcmeHelloBundleController; use SymfonyComponentHttpFoundationResponse; class HelloController { public function indexAction($name) { return new Response('<html><body>Hello '.$name.'!</body></html>'); } }
  • 33. Creating Pages in Symfony2 Step3: Create template // src/Acme/HelloBundle/Controller/HelloController.php namespace AcmeHelloBundleController; use SymfonyBundleFrameworkBundleControllerController; class HelloController extends Controller { public function indexAction($name) { return $this->render( 'AcmeHelloBundle:Hello:index.html.twig', array('name' => $name) ); } }
  • 34. Creating Pages in Symfony2 Practice #1: - create controller that receives some integer as parameter from route and returns template with that number squared. Time: 5 minutes
  • 35. Controller • Request -> Response ● The response could be an HTML page, an XML document, a serialized JSON array, an image, a redirect, a 404 error or anything else you can dream up. ● The controller contains whatever arbitrary logic your application needs to render the content of a page. use SymfonyComponentHttpFoundationResponse; public function helloAction() { return new Response('Hello world!'); }
  • 37. Simple Controller // src/Acme/HelloBundle/Controller/HelloController.php namespace AcmeHelloBundleController; use SymfonyComponentHttpFoundationResponse; class HelloController { public function indexAction($name) { return new Response('<html><body>Hello '.$name.'!</body></html>'); } }
  • 38. Mapping url to a Controller # app/config/routing.yml hello: path: /hello/{first_name}/{last_name} defaults: { _controller: AcmeHelloBundle:Hello:index, color: green } // order of arguments does not metter public function indexAction($first_name, $color, $last_name) { // ... do whatever logic and return Response }
  • 39. The Request as Controller Argument use SymfonyComponentHttpFoundationRequest; public function updateAction(Request $request) { $form = $this->createForm(...); $form->handleRequest($request); // ... }
  • 40. The Base Controller Class // src/Acme/HelloBundle/Controller/HelloController.php namespace AcmeHelloBundleController; use SymfonyBundleFrameworkBundleControllerController; use SymfonyComponentHttpFoundationResponse; class HelloController extends Controller { // ... do whatever logic and return Response } By extending this Controller class, you can take advantage of several helper methods.
  • 41. Common Controller Tasks // redirecting public function indexAction() { return $this->redirect($this->generateUrl('homepage')); } public function indexAction() { return $this->redirect($this->generateUrl('homepage'), 301); } Shortcut for: use SymfonyComponentHttpFoundationRedirectResponse; return new RedirectResponse($this->generateUrl('homepage'));
  • 42. Common Controller Tasks // forwarding public function indexAction($name) { $response = $this->forward('AcmeHelloBundle:Hello:fancy', array( 'name' => $name, 'color' => 'green', )); // ... further modify the response or return it directly return $response; } public function fancyAction($name, $color) { // ... create and return a Response object }
  • 43. Common Controller Tasks Shortcut for: $httpKernel = $this->container->get('http_kernel'); $response = $httpKernel->forward( 'AcmeHelloBundle:Hello:fancy', array( 'name' => $name, 'color' => 'green', ) );
  • 44. Common Controller Tasks // rendering templates use SymfonyComponentHttpFoundationResponse; $content = $this->renderView( 'AcmeHelloBundle:Hello:index.html.twig', array('name' => $name) ); return new Response($content); return $this->render( 'AcmeHelloBundle:Hello:index.html.twig', array('name' => $name) );
  • 45. Common Controller Tasks Shortcut for: $templating = $this->get('templating'); $content = $templating->render( 'AcmeHelloBundle:Hello:index.html.twig', array('name' => $name) ); $templating->render( 'AcmeHelloBundle:Hello/Greetings:index.html.twig', array('name' => $name) );
  • 46. 404 error public function indexAction() { // retrieve the object from database $product = ...; if (!$product) { throw $this->createNotFoundException('The product does not exist'); } return $this->render(...); } Error 500 throw new Exception('Something went wrong!');
  • 47. Accessing other Services $request = $this->getRequest(); $templating = $this->get('templating'); $router = $this->get('router'); $mailer = $this->get('mailer');
  • 48. Accessing other Services $request = $this->getRequest(); $templating = $this->get('templating'); $router = $this->get('router'); $mailer = $this->get('mailer'); > php app/console container:debug
  • 49. Managing the Session $session = $this->getRequest()->getSession(); // store an attribute for reuse during a later user request $session->set('foo', 'bar'); // in another controller for another request $foo = $session->get('foo'); // use a default value if the key doesn't exist $filters = $session->get('filters', array());
  • 50. Flash Messages public function updateAction() { $form = $this->createForm(...); $form->bind($this->getRequest()); if ($form->isValid()) { // do some sort of processing $this->get('session')->getFlashBag()->add('notice', 'Your changes were saved!'); return $this->redirect($this->generateUrl(...)); } return $this->render(...); }
  • 51. Flash Messages {% for flashMessage in app.session.flashbag.get('notice') %} <div class="flash-notice"> {{ flashMessage }} </div> {% endfor %}
  • 52. The Response Object The only requirement for a controller is to return a Response object. The Response class is a PHP abstraction around the HTTP response - the text-based message filled with HTTP headers and content that's sent back to the client: use SymfonyComponentHttpFoundationResponse; // create a simple Response with a 200 status code (the default) $response = new Response('Hello '.$name, 200); // create a JSON-response with a 200 status code $response = new Response(json_encode(array('name' => $name))); $response->headers->set('Content-Type', 'application/json');
  • 53. The Response Object - JSON use SymfonyComponentHttpFoundationResponse; $response = new Response(); $response->setContent(json_encode(array( 'data' => 123, ))); $response->headers->set('Content-Type', 'application/json'); --- use SymfonyComponentHttpFoundationJsonResponse; $response = new JsonResponse(); $response->setData(array( 'data' => 123 ));
  • 54. The Response Object - FILE use SymfonyComponentHttpFoundationResponseHeaderBag; $d = $response->headers- >makeDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, 'foo.pdf'); $response->headers->set('Content-Disposition', $d); --- use SymfonyComponentHttpFoundationBinaryFileResponse $file = 'path/to/file.txt'; $response = new BinaryFileResponse($file);
  • 55. The Request Object $request = $this->getRequest(); $request->isXmlHttpRequest(); // is it an Ajax request? $request->getPreferredLanguage(array('en', 'fr')); $request->query->get('page'); // get a $_GET parameter $request->request->get('page'); // get a $_POST parameter
  • 56. Render static page No need for controller!!! acme_privacy: path: /privacy defaults: _controller: FrameworkBundle:Template:template template: 'AcmeBundle:Static:privacy.html.twig'
  • 57. Controller Practice #2: ● send numbers via $_GET parameter (numA and numB). Get these two numbers in controller from Request Object (using $_GET[] is forbidden). Send Request object as action's parameter. If numA*numB > 100 redirect to some custom controller's action; If numA < 0 and numB < 0 throw 404 error; If numA+numB > 10 return JSON Response with result; else return template with result numA-numB; Time: 10 minutes
  • 58. Routing <3 index.php?article_id=57 -> don't like this /i-like/symfony-routing One of the most powerfull Symfony2 component. Very flexible!!! Route = map form url to controller Position of route is important!!!
  • 59. Routing <3 // example (sylius): locastic_product_review_list: pattern: /review-for-product/{productId} defaults: _controller: locastic.controller.frontend.product_review:listReviewsForProductAction locastic_product_review_add: pattern: /add-review-for-product/{productId} defaults: _controller: locastic.controller.frontend.product_review:addReviewAction _format: json sylius_product_show: pattern: /p/{slug} defaults: _controller: sylius.controller.product:showAction _sylius: template: SyliusWebBundle:Frontend/Product:show.html.twig
  • 60. Routing <3 // 4 ways of defining routes 1.YAML 2.XML 3.PHP 4.Annotations
  • 61. Routing - YAML # app/config/routing.yml blog_show: path: /blog/{slug} defaults: { _controller: AcmeBlogBundle:Blog:show }
  • 62. Routing - XML <!-- app/config/routing.xml --> <?xml version="1.0" encoding="UTF-8" ?> <routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd"> <route id="blog_show" path="/blog/{slug}"> <default key="_controller">AcmeBlogBundle:Blog:show</default> </route> </routes>
  • 63. Routing - PHP // app/config/routing.php use SymfonyComponentRoutingRouteCollection; use SymfonyComponentRoutingRoute; $collection = new RouteCollection(); $collection->add('blog_show', new Route('/blog/{slug}', array( '_controller' => 'AcmeBlogBundle:Blog:show', ))); return $collection;
  • 64. Routing - Annotations /** * @Route("/blog/{slug}", name=”blog_show”) */ public function showAction($slug) { // do whatever logic and return Response }
  • 66. Basic Route Configuration _welcome: path: / defaults: { _controller: AcmeDemoBundle:Main:homepage } <?xml version="1.0" encoding="UTF-8" ?> <routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd"> <route id="_welcome" path="/"> <default key="_controller">AcmeDemoBundle:Main:homepage</default> </route> </routes>
  • 67. Routing with placeholder blog_show: path: /blog/{slug} defaults: { _controller: AcmeBlogBundle:Blog:show } <?xml version="1.0" encoding="UTF-8" ?> <routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd"> <route id="blog_show" path="/blog/{slug}"> <default key="_controller">AcmeBlogBundle:Blog:show</default> </route> </routes>
  • 68. Required and Optional Placeholder blog: path: /blog defaults: { _controller: AcmeBlogBundle:Blog:index } blog: path: /blog/{page} defaults: { _controller: AcmeBlogBundle:Blog:index } blog: path: /blog/{page} defaults: { _controller: AcmeBlogBundle:Blog:index, page: 1 }
  • 69. Required and Optional Placeholder blog: path: /blog/{page} defaults: { _controller: AcmeBlogBundle:Blog:index, page: 1 } /blog {page} = 1 /blog/1 {page} = 1 /blog/2 {page} = 2
  • 70. Adding Requirements blog: path: /blog/{page} defaults: { _controller: AcmeBlogBundle:Blog:index, page: 1 } blog_show: path: /blog/{slug} defaults: { _controller: AcmeBlogBundle:Blog:show } URL route parameters /blog/2 blog {page} = 2 /blog/my-blog-post blog {page} = my-blog-post
  • 71. Adding Requirements blog: path: /blog/{page} defaults: { _controller: AcmeBlogBundle:Blog:index, page: 1 } requirements: page: d+ URL route parameters /blog/2 blog {page} = 2 /blog/my-blog-post blog_show {slug} = my-blog-post
  • 72. Earlier Routes always Win!!! What this all means is that the order of the routes is very important. If the blog_show route were placed above the blog route, the URL /blog/2 would match blog_show instead of blog since the {slug} parameter of blog_show has no requirements. By using proper ordering and clever requirements, you can accomplish just about anything.
  • 73. Adding Requirements homepage: path: /{culture} defaults: { _controller: AcmeDemoBundle:Main:homepage, culture: en } requirements: culture: en|fr / {culture} = en /en {culture} = en /fr {culture} = fr /es won't match this route
  • 74. Adding HTTP Method Requirements contact: path: /contact defaults: { _controller: AcmeDemoBundle:Main:contact } methods: [GET] contact_process: path: /contact defaults: { _controller: AcmeDemoBundle:Main:contactProcess } methods: [POST]
  • 75. Advanced Routing Example article_show: path: /articles/{culture}/{year}/{title}.{_format} defaults: { _controller: AcmeDemoBundle:Article:show, _format: html } requirements: culture: en|fr _format: html|rss year: d+ /articles/en/2010/my-post /articles/fr/2010/my-post.rss /articles/en/2013/my-latest-post.html
  • 76. Including External Routing Resources # app/config/routing.yml acme_hello: resource: "@AcmeHelloBundle/Resources/config/routing.yml" # src/Acme/HelloBundle/Resources/config/routing.yml acme_hello: path: /hello/{name} defaults: { _controller: AcmeHelloBundle:Hello:index }
  • 77. Prefixing Imported Routes # app/config/routing.yml acme_hello: resource: "@AcmeHelloBundle/Resources/config/routing.yml" prefix: /admin
  • 78. Visualizing & Debugging Routes While adding and customizing routes, it's helpful to be able to visualize and get detailed information about your routes. A great way to see every route in your application is via the router:debug console command. Execute the command by running the following from the root of your project. > php app/console router:debug
  • 79. Generating URLs class MainController extends Controller { public function showAction($slug) { // ... $url = $this->generateUrl( // helper method 'blog_show', array('slug' => 'my-blog-post') ); } }
  • 80. Generating URLs $params = $this->get('router')->match('/blog/my-blog-post'); // array( // 'slug' => 'my-blog-post', // '_controller' => 'AcmeBlogBundle:Blog:show', // ) $uri = $this->get('router')->generate('blog_show', array('slug' => 'my-blog-post')); // /blog/my-blog-post $this->get('router')->generate('blog_show', array('slug' => 'my-blog-post'), true); // http://www.example.com/blog/my-blog-post
  • 81. Generating URLs // with query string $this->get('router')->generate('blog', array('page' => 2, 'category' => 'Symfony')); // /blog/2?category=Symfony // from template <a href="{{ path('blog_show', {'slug': 'my-blog-post'}) }}"> Read this blog post. </a> <a href="{{ url('blog_show', {'slug': 'my-blog-post'}) }}"> Read this blog post. </a>
  • 82. Routing :) Practice #3: - create route for AcmeDemoBundle:Hello:list, that accepts parameters: - category (string with no numbers) - page number (integer) - only GET method In template list: category, slug and page number like this: If url is: /ez-publish-summer-camp/3 Category slug: ez-publish-summer-camp Page number: 3 Use YAML format for routing! Time: 5 minutes
  • 83. MODEL ORM Doctrine 2 parameters.yml → Config.yml > php app/console doctrine:database:create
  • 84. MODEL - metadata // src/Acme/StoreBundle/Entity/Product.php namespace AcmeStoreBundleEntity; use DoctrineORMMapping as ORM; /** * @ORMEntity * @ORMTable(name="product") */ class Product { /** * @ORMId * @ORMColumn(type="integer") * @ORMGeneratedValue(strategy="AUTO") */ protected $id; ...
  • 85. MODEL - metadata .. /** * @ORMColumn(type="string", length=100) */ protected $name; /** * @ORMColumn(type="decimal", scale=2) */ protected $price; /** * @ORMColumn(type="text") */ protected $description; }
  • 86. MODEL – metadata - YAML # src/Acme/StoreBundle/Resources/config/doctrine/Product.orm.yml AcmeStoreBundleEntityProduct: 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
  • 87. MODEL – metadata - XML <!-- src/Acme/StoreBundle/Resources/config/doctrine/Product.orm.xml --> <?xml version="1.0" encoding="UTF-8" ?> <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="AcmeStoreBundleEntityProduct" 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>
  • 88. MODEL A bundle can accept only one metadata definition format. For example, it's not possible to mix YAML metadata definitions with annotated PHP entity class definitions. Be careful that your class name and properties aren't mapped to a protected SQL keyword (such as group or user). Create getters and setters > php app/console doctrine:generate:entities Acme/StoreBundle/Entity/Product > php app/console doctrine:schema:update –force
  • 89. Persist object to database // src/Acme/StoreBundle/Controller/DefaultController.php // ... use AcmeStoreBundleEntityProduct; use SymfonyComponentHttpFoundationResponse; public function createAction() { $product = new Product(); $product->setName('A Foo Bar'); $product->setPrice('19.99'); $product->setDescription('Lorem ipsum dolor'); $em = $this->getDoctrine()->getManager(); $em->persist($product); $em->flush(); return new Response('Created product id '.$product->getId()); }
  • 90. Fetching Objects from the Database 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 }
  • 91. Repository Basic // 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);
  • 92. Repository Basic // query for one product matching be name and price $product = $repository->findOneBy(array('name' => 'foo', 'price' => 19.99)); // query for all products matching the name, ordered by price $products = $repository->findBy( array('name' => 'foo'), array('price' => 'ASC') );
  • 94. Updating an Object public function updateAction($id) { $em = $this->getDoctrine()->getManager(); $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')); }
  • 96. Querying for Object with DQL $em = $this->getDoctrine()->getManager(); $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();
  • 97. Using Doctrine's Query Builder $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();
  • 98. Custom Repository Classes // using annotations // src/Acme/StoreBundle/Entity/Product.php namespace AcmeStoreBundleEntity; use DoctrineORMMapping as ORM; /** * @ORMEntity(repositoryClass="AcmeStoreBundleEntityProductRepository") */ class Product { //... }
  • 99. Custom Repository Classes // using YAML #src/Acme/StoreBundle/Resources/config/doctrine/Product.orm.yml AcmeStoreBundleEntityProduct: type: entity repositoryClass: AcmeStoreBundleEntityProductRepository # ...
  • 100. Custom Repository Classes // using XML <!-- src/Acme/StoreBundle/Resources/config/doctrine/Product.orm.xml --> <?xml version="1.0" encoding="UTF-8" ?> <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="AcmeStoreBundleEntityProduct" repository-class="AcmeStoreBundleEntityProductRepository"> <!-- ... --> </entity> </doctrine-mapping>
  • 101. Custom Repository Classes // src/Acme/StoreBundle/Entity/ProductRepository.php namespace AcmeStoreBundleEntity; use DoctrineORMEntityRepository; class ProductRepository extends EntityRepository { public function findAllOrderedByName() { return $this->getEntityManager() ->createQuery( 'SELECT p FROM AcmeStoreBundle:Product p ORDER BY p.name ASC' ) ->getResult(); } }
  • 102. Custom Repository Classes $em = $this->getDoctrine()->getManager(); $products = $em->getRepository('AcmeStoreBundle:Product') ->findAllOrderedByName();
  • 103. MODEL – custom repository public function updateGallery($photoId, $galleryId) { $qb = $this->createQueryBuilder('p'); $query = $qb ->update() ->set('p.gallery', $galleryId) ->where('p.id = :id') ->setParameter('id', $photoId); return $query->getQuery()->execute(); }
  • 104. Relationship Mapping Metadata // src/Acme/StoreBundle/Entity/Category.php // ... use DoctrineCommonCollectionsArrayCollection; class Category { // ... /** * @ORMOneToMany(targetEntity="Product", mappedBy="category") */ protected $products; public function __construct() { $this->products = new ArrayCollection(); } } Product (n) <- (1) Category
  • 105. Relationship Mapping Metadata <!-- src/Acme/StoreBundle/Resources/config/doctrine/Category.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="AcmeStoreBundleEntityCategory"> <!-- ... --> <one-to-many field="products" target-entity="Product" mapped-by="category" /> <!-- don't forget to init the collection in the __construct() method of the entity --> </entity> Product (n) <- (1) Category
  • 106. Relationship Mapping Metadata #src/Acme/StoreBundle/Resources/config/doctrine/Category.orm.yml AcmeStoreBundleEntityCategory: type: entity # ... oneToMany: products: targetEntity: Product mappedBy: category # don't forget to init the collection in the __construct() method of the entity Product (n) <- (1) Category
  • 107. Relationship Mapping Metadata // src/Acme/StoreBundle/Entity/Product.php // ... class Product { // ... /** * @ORMManyToOne(targetEntity="Category", inversedBy="products") * @ORMJoinColumn(name="category_id", referencedColumnName="id") */ protected $category; } Product (n) <- (1) Category
  • 108. Relationship Mapping Metadata # src/Acme/StoreBundle/Resources/config/doctrine/Product.orm.yml AcmeStoreBundleEntityProduct: type: entity # ... manyToOne: category: targetEntity: Category inversedBy: products joinColumn: name: category_id referencedColumnName: id Product (n) <- (1) Category
  • 109. Relationship Mapping Metadata <!-- 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="AcmeStoreBundleEntityProduct"> <!-- ... --> <many-to-one field="category" target-entity="Category" inversed-by="products" join-column="category" > <join-column name="category_id" referenced-column-name="id" /> </many-to-one> Product (n) <- (1) Category
  • 111. Saving related entities // ... use AcmeStoreBundleEntityCategory; use AcmeStoreBundleEntityProduct; use SymfonyComponentHttpFoundationResponse; 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()->getManager(); $em->persist($category); $em->persist($product);
  • 112. Fetching related Objects public function showAction($id) { $product = $this->getDoctrine() ->getRepository('AcmeStoreBundle:Product') ->find($id); $categoryName = $product->getCategory()->getName(); // ... }
  • 114. Fetching related Objects public function showProductAction($id) { $category = $this->getDoctrine() ->getRepository('AcmeStoreBundle:Category') ->find($id); $products = $category->getProducts(); // ... }
  • 115. Doctrine Field Types Reference Strings string (used for shorter strings) text (used for larger strings) Numbers integer smallint bigint decimal float Dates and Times (use a DateTime object for these fields in PHP) date time datetime Other Types boolean object (serialized and stored in a CLOB field) array (serialized and stored in a CLOB field)
  • 116. Some advanced stuff Events and lifecycle callbacks preRemove postRemove prePersist postPersist preUpdate postUpdate postLoad LoadClassMetadata Doctrine Extensions: Timestampable, Sluggable, etc.
  • 117. MODEL Practice #3: - Create entities for schema bellow and create empty custom repository for each, use XML Time: 15 minutes
  • 120. CRUD → create bundle → create entity
  • 121. CRUD → create bundle → create entity → create full CRUD* with routes, controllers and templates
  • 122. CRUD → create bundle → create entity → create full CRUD with routes, controllers and templates → use console :)
  • 123. FORMS AND VALIDATION Workshop: Symfony2 Forms – tomorrow 09:00am Bernhard Schussek The Symfony2 Form component helps you to build powerful forms with little code. This workshop shows you how to use the component in your daily life.
  • 125.

Notas del editor

  1. Basically, a framework consists of: A toolbox - a set of prefabricated, rapidly integratable software components. This means that you will have to write less code, with less risk of error. This also means greater productivity and the ability to devote more time to doing those things which provide greater added value, such as managing guiding principles, side effects, etc. Best Practices guaranteed! A methodology – an “assembly diagram” for applications. A structured approach may seem constraining at first. But in reality it allows developers to work both efficiently and effectively on the most complex aspects of a task, and the use of Best Practices guarantees the stability, maintainability and upgradeability of the applications you develop.