路由
# 主路由配置app/config/routing.yml
# 加載某模塊的annotation路由,如AcmeBundle
acme:
resource: @XxxxBundle/Controller #該級目錄及子目錄annotation都被解析
type: annotation #必選
prefix: '' #路由前綴
# annotation配置路由
# 註解命令中引號必須用雙引號
# 註解命令必須以 /** 打頭, 註釋以 /* 打頭。
/**
* @Route(
"/Path/{slug}",
defaults: {},
name="",
requirements: {"_format": "html|rss"}
);
* @Method("GET");
*/
public function indexAction($slug){}
# annotation路由參數轉換 功能
# typehint參數爲一個doctrine實體類,自動查詢匹配路由參數的實體對象
# 沒有匹配對象則返回404頁
/**
* @Route("/{id}", name="admin_post_show")
*/
public function showAction(Post $post){}
# 還可明確的設定參數轉換細節
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
* @Route("/comment/{postSlug}/new", name = "comment_new")
* @ParamConverter("post", options={"mapping": {"postSlug": "slug"}})
app/console debug:router 【routeName】//調試路由
url、 參數相互轉換:
$params = $this->get('router')->match('/blog/my-blog-post'); //assoc-array, 匹配的路由參數
$uri = $this->get('router')->generate('blog_show', array('slug' => 'my-blog-post'), bool $生成絕對地址); //生成url
控制器
return $this->redirectToRoute('hello', array('name' => 'Fabien')); //跳轉
return $this->redirect($this->generateUrl('homepage'), 301); //重定向
return $this->forward('AcmeHelloBundle:Hello:fancy', array $context); //內部action轉發
模型AR查詢:
//管理器插入實體
$em = $this->getDoctrine()->getManager();
$em->persist($product);
$em->flush();
//倉庫中獲取實體
$repository = $this->getDoctrine()->getRepository('AppBundle:Product');
$repository->find($id);
$repository->findOneByName('foo');
$repository->findBy(array $filters);
$repository->findOneBy(array $filters);
$repository->findByPrice(19.99);
$repository->findAll();
//更新實體
$em = $this->getDoctrine()->getManager();
$product = $em->getRepository('AppBundle:Product')->find($id);
$product->setName('New product name!');
$em->flush();
//刪除實體
$em->remove($product);
$em->flush();
//調用repository類方法
$repo = $this->getDoctrine()->getRepository();
$result = $repo->倉庫定義的方法();
模型DQL查詢
1DQL查詢構建器:
$query = $repository->createQueryBuilder('p')
->where('p.price > :price')
->setParameter('price', '19.99')
->orderBy('p.price', 'ASC')
->getQuery();
$products = $query->getResult();
$product = $query->getSingleResult(); //沒有結果會拋出異常
$product = $query->getOneOrNullResult(); //沒有結果不會拋出異常
2純DQL查詢:
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery(
'SELECT p
FROM AppBundle:Product p
WHERE p.price > :price
ORDER BY p.price ASC'
)->setParameter('price', '19.99');
$products = $query->getResult();
Doctrine
鏈接配置: app/config/parameters.yml
doctrine配置: app/config/config.yml
app/console doctrine:database:create //建立庫(必須先建立好具有建庫權限的帳號)
app/console doctrine:database:drop --force //卸載庫
app/console doctrine:generate:entity 【--entity="AppBundle:Category"】 //建立實體
app/console doctrine:schema:update --force //更新映射,【可建立表】
app/console doctrine:generate:entities 【AppBundle】 //爲bundle生成getter,setter, repo等
一個bundle只能夠接受一種metadata定義格式(來指定字段類型),表名是可選的,若是省略,將基於entity類的名稱自動肯定。
受保護的SQL字段(如group和user)
基礎查詢方法:
$repo->findOneBy(Array)
->findLatest()
關聯查詢:
查詢到的關聯對象都是延遲加載
查詢到的關聯對象都是代理對象(代理類存儲在cache目錄), 除非調用getter方法纔會實際進行查詢
join一次性全查關聯對象:
$product = $this->getEntityManager()
->createQuery(
'SELECT p, c FROM AppBundle:Product p
JOIN p.category c
WHERE p.id = :id'
)->setParameter('id', $id)
->getSingleResult();
$category = $product->getCategory();
生命週期回調lifecycle callback:
* @ORM\HasLifecycleCallbacks() //實體頭部聲明
* @ORM\PrePersist //實體內部註冊回調方法並在頭部聲明相似該執行點
TWIG
控制器訪問模板路徑格式:
AcmeDemoBundle:Default:index.html.twig #模板保存在src/Bundle/Resource/views
default/index.html.twig #模板保存在app/Resource/views, 最佳實踐推薦模板保存在此處
定界符後須要跟一對空格
app/console twig:lint app/Resources/views【/article/recent_list.html.twig】 //模板語法檢查
{{ article.body|raw }} //關閉輸出轉義
Hello <?php echo $view->escape($name【, 'js'】) ?> //php模板形式的轉義, 默認html上下文, 能夠指定js上下文
全局模板變量:
app.user //當前用戶對象
app.request //當前Request對象
app.session //Session對象
app.environment //當前應用程序的環境(dev,prod等)
app.debug //若是是true說明是調試模式,false則不是。
<a href="{{ path('blog_show', {'slug': 'my-blog-post'}) }}"> //相對地址url, 可經過_format指定請求資源格式
<a href="{{ url('blog_show', {'slug': 'my-blog-post'}) }}"> //絕對地址url
{{ parent() }} //應用父模塊內容
{{ include('article/article_details.html.twig', { 'article': article }) }} //包含模板塊
{{ render(controller('AcmeArticleBundle:Article:recentArticles', { 'max': 3 })) }} //嵌入控制器
異步內容hinclude.js:
{{ render_hinclude(controller('...'), 【{'default': 'default/content.html.twig'}】) }}
{{ render_hinclude(url('...'), 【{'default': 'Loading...'})】) }}
資源連接:
<img src="{{ asset('images/logo.png'【, version='3.0'】【, absolute=true】) }}" alt="Symfony!" /> //version: null, 或未設置則默認版本號, false則停用版本號
## 給twig拓展本身的過濾器my_filter ##
# 自定義一個拓展類,並在其中輸出my_filter
# 拓展類文件推薦放在xxBundle/Tiwg下
namespace AppBundle\Twig;
class MyExtension extends \Twig_Extension{
public function getName()
{
return 'my_extension';
}
public function getFilters()
{
return array(
new \Twig_SimpleFilter(
'my_filter',
array($this, 'some_operation'),
array('is_safe' => array('html'))
),
);
}
public some_operation($content){...}
}
# 編輯app/config/services.yml
# 註冊拓展類爲服務,並tag其爲twig.extension
services:
xx.twig.my_extension:
class: xxBundle\Twig\MyExtension
public: false
tags:
- { name: twig.extension }
{{ content|my_filter }} #過濾器使用
靜態文件管理器Assetic
不使用assetic: <script src="{{ asset('js/script.js') }}"></script>
將bundle的靜態文件默認拷貝安裝到web目錄下, 通常用於第三方bundle(沒有用assetic的)的靜態資源安裝
app/console assets:install
//////////////////////////////
使用assetic:
壓縮、合併靜態文件(dev環境,每一個文件依然獨立;prod或者調試關閉時,文件合併)
LESS, SASS等等的編譯
圖片文件優化
隨意目錄存儲靜態文件
#引入一條合併的js, 來源於兩個目錄
{% javascripts '@AppBundle/Resources/public/js/*' '@AcmeBarBundle/Resources/public/js/form.js' %}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
#引入一條合併的css,來源於一個目錄
#css的assetic路徑寫法特殊,@AppBundle會報錯,一個已知的框架錯誤
#cssrewrite過濾器用於修復文件dump後, 圖片相對路徑出錯
{% stylesheets 'bundles/app/css/*' filter='cssrewrite' %}
<link rel="stylesheet" href="{{ asset_url }}" />
{% endstylesheets %}
#引入圖片
{% image '@AppBundle/Resources/public/images/example.jpg' %}
<img src="{{ asset_url }}" alt="Example" />
{% endimage %}
配置文件預約義命名資產
# app/config/config.yml
assetic:
assets:
xxxx:
inputs:
- '@AppBundle/Resources/public/js/thirdparty/jquery.js'
模板中應用命名資產
{% javascripts '@xxxx' %}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
靜態資源dump合併
prod環境:
資源路徑被合併,每次文件更新時,須要手動重建一下新的合併文件
app/console assetic:dump --env=prod --no-debug
dev環境:
資源路徑被合併,但沒有生成新文件, 內部控制器動態讀取文件併合並後直接輸出(文件更新當即起效,可是很慢)
# 若是靜態文件加載過慢,可關閉動態生成:
# app/config/config_dev.yml #這裏是!!開發環境!!下的配置文件
assetic:
use_controller: false
而後,手動dump出合併文件(每次文件更新都得dump一下)
app/console assetic:dump
app/console assetic:watch #結合參數主動監測文件是否變更而後決定更新
指定dump文件的輸出路徑
{% javascripts '@AppBundle/Resources/public/js/*' output='js/compiled/main.js' %}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
靜態文件壓縮(UglifyJS和UglifyCSS)
全局安裝壓縮組件
cnpm install -g uglify-js
cnpm install -g uglifycss
配置壓縮組件可用:
# app/config/config.yml
assetic:
node: /usr/bin/nodejs #可選, 手動指定node路徑
filters:
uglifyjs2:
bin: /usr/local/bin/uglifyjs
運用壓縮組件:
{% javascripts '@AppBundle/Resources/public/js/*' filter='uglifyjs2' %}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
配置壓縮組件在debug時自動關閉, 在filter上加 "?"
{% javascripts '@AppBundle/Resources/public/js/*' filter='?uglifyjs2' %}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
清理緩存, 壓縮重建dump文件
指定filter做用的文件
1. filter單獨某些文件:
直接在assetic標籤上標示filter
2. filter特定拓展名文件
# app/config/config.yml
assetic:
filters:
coffee:
bin: /usr/bin/coffee
apply_to: "\.coffee$" //filter拓展名coffee格式的文件
圖片優化filter
1. Jpegoptim
# 安裝開發包 並配置 app/config/config.yml
assetic:
filters:
jpegoptim:
bin: path/to/jpegoptim
strip_all: true //可選, 用於剔除EXIF信息
max: 70 //圖片質量
使用
{% image '@AppBundle/Resources/public/images/example.jpg' filter='jpegoptim' output='/images/example.jpg' %}
<img src="{{ asset_url }}" alt="Example"/>
{% endimage %}
簡短語法(twig函數)實現:
# 啓用配置 app/config/config.yml
assetic:
filters:
jpegoptim:
bin: path/to/jpegoptim
twig:
functions:
jpegoptim: ~ 或指定輸出目錄 { output: images/*.jpg }
使用 <img src="{{ jpegoptim('@AppBundle/Resources/public/images/example.jpg') }}" alt="Example"/>