<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Symfony中文教程 &#187; 实战教程</title>
	<atom:link href="http://www.newlifeclan.com/symfony/archives/category/actual-combat/feed" rel="self" type="application/rss+xml" />
	<link>http://www.newlifeclan.com/symfony</link>
	<description>站在巨人肩膀上的phpweb框架</description>
	<lastBuildDate>Fri, 12 Dec 2025 00:58:27 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.0.38</generator>
	<item>
		<title>Twig中的隔行变色</title>
		<link>http://www.newlifeclan.com/symfony/archives/1198</link>
		<comments>http://www.newlifeclan.com/symfony/archives/1198#comments</comments>
		<pubDate>Sat, 07 Jan 2017 07:21:53 +0000</pubDate>
		<dc:creator><![CDATA[napoleon]]></dc:creator>
				<category><![CDATA[实战教程]]></category>

		<guid isPermaLink="false">http://www.newlifeclan.com/symfony/?p=1198</guid>
		<description><![CDATA[<p>隔行变色在表单中或者列表中非常常用，主要是让列表的每一行在奇数和偶数时，呈现不同的颜色，已达到视觉区分行的友好 [&#8230;]</p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/1198">Twig中的隔行变色</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>隔行变色在表单中或者列表中非常常用，主要是让列表的每一行在奇数和偶数时，呈现不同的颜色，已达到视觉区分行的友好体验。<span id="more-1198"></span></p>
<p>隔行变色大多数都是变换，一个行的背景颜色</p>
<p>比如我们下面代码展示的效果：</p><pre class="crayon-plain-tag">&lt;style&gt;
        div{ height:50px; width:100%}
        div .oddbg{ background-color:#88080A}
        div .evenbg{ background-color:#00b777}
    &lt;/style&gt;

    &lt;div class="oddbg"&gt;&lt;/div&gt;
    &lt;div class="evenbg"&gt;&lt;/div&gt;
    &lt;div class="oddbg"&gt;&lt;/div&gt;
    &lt;div class="evenbg"&gt;&lt;/div&gt;
    &lt;div class="oddbg"&gt;&lt;/div&gt;</pre><p><img class="alignnone size-full wp-image-1199" src="http://www.newlifeclan.com/symfony/wp-content/uploads/sites/2/2017/01/20170107151425.png" alt="20170107151425" width="317" height="292" /></p>
<p>这里面我们使用了class=“oddbg”来代表奇数样式，使用class=“evenbg”来代表偶数样式。那么如果在Twig模板中使用循环来，输出这样的效果呢，其实很简单。来看看官网的连个页面：<a href="http://twig.sensiolabs.org/doc/2.x/tests/odd.html">odd</a>，<a href="http://twig.sensiolabs.org/doc/2.x/tests/even.html">even</a>。</p>
<p>下面是twig输出11行的例子：</p><pre class="crayon-plain-tag">&lt;style&gt;
        div{ height:50px; width:100%}
        div .oddbg{ background-color:#88080A}
        div .evenbg{ background-color:#00b777}
    &lt;/style&gt;
    {% for i in 0..10 %}
        &lt;div class="{% if loop.index is odd %} oddbg {% else %} evenbg {% endif %}"&gt;&lt;/div&gt;
    {% endfor %}</pre><p>在这个例子里，只使用一个方法即可，例如只使用odd，那么我们就不用去判断even了，因为有了odd，else自然是even。</p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/1198">Twig中的隔行变色</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.newlifeclan.com/symfony/archives/1198/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>亲一亲Doctrine查询之2：QueryBuilder</title>
		<link>http://www.newlifeclan.com/symfony/archives/1003</link>
		<comments>http://www.newlifeclan.com/symfony/archives/1003#comments</comments>
		<pubDate>Fri, 08 Jul 2016 12:35:34 +0000</pubDate>
		<dc:creator><![CDATA[napoleon]]></dc:creator>
				<category><![CDATA[实战教程]]></category>

		<guid isPermaLink="false">http://www.newlifeclan.com/symfony/?p=1003</guid>
		<description><![CDATA[<p>Doctrine我们介绍了DQL，他很像SQL也最终把语句转换成了SQL。但，你可不写DQL。我们可以用Que [&#8230;]</p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/1003">亲一亲Doctrine查询之2：QueryBuilder</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>Doctrine我们介绍了DQL，他很像SQL也最终把语句转换成了SQL。但，你可不写DQL。我们可以用QueryBuilder去替换DQL：他是一个对象，可以我们构建DQL字符串。<code>QueryBuilder是我在Doctrine中最喜欢的一部分。</code><span id="more-1003"></span></p>
<h2>创建Query Builder</h2>
<p>让我们注释掉$dql。去创建一个QueryBuilder，创建一个$qb变量并从repository里调用$this-&gt;createQueryBuilder()。传入cat作为参数 &#8211; 他是Category类的别名。</p><pre class="crayon-plain-tag">//src/AppBundle/Entity/CategoryRepository.php
class CategoryRepository extends EntityRepository
{
    public function findAllOrdered()
    {
        $qb = $this-&gt;createQueryBuilder('cat')
... 
    }
}</pre><p></p>
<h2> 构建查询</h2>
<p>现在，让我们看一些精彩的！<code>QueryBuilder有很多的方法例如：andWhere, <code>leftJoin</code> 和 <code>addOrderBy。让我们用用它们：使用addOrderBy方法，并传入cat.name作为第一个参数，DESC作为第二个参数：</code></code></p><pre class="crayon-plain-tag">//src/AppBundle/Entity/CategoryRepository.php
class CategoryRepository extends EntityRepository
{
    public function findAllOrdered()
    {
        $qb = $this-&gt;createQueryBuilder('cat')
            -&gt;addOrderBy('cat.name', 'DESC');

    }</pre><p>这段和我们之前构建的DQL是一样的。因为我们的createQueryBuilder()函数在CategoryRepository内，所以我们的函数自动把Category实体配置进来，当然cat是他的别名。</p>
<p>从这里获取一个<code>Query对象，要使用 <code>$qb-&gt;getQuery()</code>:</code></p><pre class="crayon-plain-tag">//src/AppBundle/Entity/CategoryRepository.php
class CategoryRepository extends EntityRepository
{
    public function findAllOrdered()
    {
        $qb = $this-&gt;createQueryBuilder('cat')
            -&gt;addOrderBy('cat.name', 'ASC');
        $query = $qb-&gt;getQuery();

    }
}</pre><p>不错哈哈。</p>
<p>还记得我们之前是怎样输出查询语句的吗？我们也可以打印DQL。让我们来看看我们努力的工作转化的DQL。</p><pre class="crayon-plain-tag">//src/AppBundle/Entity/CategoryRepository.php
    public function findAllOrdered()
    {
        $qb = $this-&gt;createQueryBuilder('cat')
            -&gt;addOrderBy('cat.name', 'ASC');
        $query = $qb-&gt;getQuery();
        var_dump($query-&gt;getDQL());die;

        return $query-&gt;execute();
    }</pre><p>刷新~ 看看是不是很亲切：</p><pre class="crayon-plain-tag">SELECT cat FROM AppBundle\Entity\Category ORDER BY cat.name DESC</pre><p>这与我们之前写的DQL是相同的。所以，Query Builder仅仅是一个帮助我们写DQL好的方法，并且我喜欢他是因为我写一个方法他会替我自动完成语句构建，并且可以帮助你很容易的组合查询，就像一个复杂的JOIN，他可以传入多个查询条件。这个我以后再告诉你。</p>
<p>移除之前的die，刷新：</p><pre class="crayon-plain-tag">//src/AppBundle/Entity/CategoryRepository.php
    public function findAllOrdered()
    {
        $qb = $this-&gt;createQueryBuilder('cat')
            -&gt;addOrderBy('cat.name', 'ASC');
        $query = $qb-&gt;getQuery();

        return $query-&gt;execute();
    }</pre><p>他看起来很不错。你想知道更多关于QueryBuilder的使用你可以继续看，或者你可以使用编辑器去看他的不同方法。但是我建议你继续看。</p>
<p>&nbsp;</p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/1003">亲一亲Doctrine查询之2：QueryBuilder</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.newlifeclan.com/symfony/archives/1003/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>亲一亲Doctrine查询之1：Doctrine DQL</title>
		<link>http://www.newlifeclan.com/symfony/archives/990</link>
		<comments>http://www.newlifeclan.com/symfony/archives/990#comments</comments>
		<pubDate>Thu, 02 Jun 2016 03:55:35 +0000</pubDate>
		<dc:creator><![CDATA[napoleon]]></dc:creator>
				<category><![CDATA[实战教程]]></category>

		<guid isPermaLink="false">http://www.newlifeclan.com/symfony/?p=990</guid>
		<description><![CDATA[<p>看，我知道你已经理解了怎样用sql查询，也许有时你睡觉时还梦到了他们JOIN，order和子查询。这是不是很傻 [&#8230;]</p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/990">亲一亲Doctrine查询之1：Doctrine DQL</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>看，我知道你已经理解了怎样用sql查询，也许有时你睡觉时还梦到了他们JOIN，order和子查询。这是不是很傻，但是这是我的经历。但是当你看到Doctrine的时候，这些就完全不同了 ，他们以自己的方式去做JOIN。<span id="more-990"></span></p>
<p>但是你知道你可以在Doctrine中写原生的SQL查询吗？是的，你可以选择任何形式的功能。当你感觉Doctrine越来越好，你会在一个地方多次使用。当遇到困难的事情时，他会让事情变得简单。</p>
<p>下面我们将了解这一切。别担心，如果你SQL很好的话，你应该善于在Doctrine中写查询。</p>
<h3></h3>
<h3>查询幸运饼干</h3>
<p>我们的这个应用是一个幸运饼干库存系统。是的，这是一种带有预测性质的饼干：他能告诉你你的未来，在一个饼干内有一个字条。</p>
<p>在这里我们的数据中有六种不同的幸运分类。如果你点击任意一个分类，你会看到这个分类下所有的命运并能看到有多少已经打印出来了。</p>
<p><img class="alignnone size-large wp-image-997" src="http://www.newlifeclan.com/symfony/wp-content/uploads/sites/2/2016/06/20160604115700-1024x988.png" alt="Fortune" width="780" height="752" /></p>
<p>点击每个Fotrune</p>
<p><img class="alignnone size-large wp-image-998" src="http://www.newlifeclan.com/symfony/wp-content/uploads/sites/2/2016/06/20160604120424-1024x668.png" alt="Fortune" width="780" height="508" /></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>这个项目是一个小型的Symfony应用- 但Doctrine的东西都会用展现出来。现在我们有两个实体：<span style="color: #ff0000"><code>Category</code> </span>和<span style="color: #ff0000"><code>FortuneCookie ：</code></span></p>
<p>&nbsp;</p><pre class="crayon-plain-tag">... 
class Category
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;
    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;
    /**
     * @var string
     *
     * @ORM\Column(name="iconKey", type="string", length=20)
     */
    private $iconKey;
    /**
     * @ORM\OneToMany(targetEntity="FortuneCookie", mappedBy="category")
     */
    private $fortuneCookies;
... 
}</pre><p>&nbsp;</p><pre class="crayon-plain-tag">... 
class FortuneCookie
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;
    /**
     * @var Category
     *
     * @ORM\ManyToOne(targetEntity="Category", inversedBy="fortuneCookies")
     * @ORM\JoinColumn(nullable=false)
     */
    private $category;
    /**
     * @var string
     *
     * @ORM\Column(name="fortune", type="string", length=255)
     */
    private $fortune;
... 
}</pre><p>从FortuneCookie到Category有一个ManyToOne的关系映射：</p><pre class="crayon-plain-tag">class FortuneCookie
{
... 
    /**
     * @var Category
     *
     * @ORM\ManyToOne(targetEntity="Category", inversedBy="fortuneCookies")
     * @ORM\JoinColumn(nullable=false)
     */
    private $category;
... 
}</pre><p>回到主页，我们使用entity manager来查询Category&#8217;s repository并调用创建好的<code>findAll函数：</code></p><pre class="crayon-plain-tag">/**
     * @Route("/", name="homepage")
     */
    public function homepageAction()
    {
        $categoryRepository = $this-&gt;getDoctrine()
            -&gt;getManager()
            -&gt;getRepository('AppBundle:Category');
        $categories = $categoryRepository-&gt;findAll();
        return $this-&gt;render('fortune/homepage.html.twig',[
            'categories' =&gt; $categories
        ]);
    }</pre><p>他返回所有的分类，并且迄今为止，他让我们变得很懒，并且避免我们编写一个自定义的查询。这个模板会遍历他们，并输入。让人吃惊。</p>
<p>&nbsp;</p>
<h3>Doctrine Query语言（DQL）</h3>
<p>是时候写一个查询了！让分类按照字母顺序排序。调用一个findAllOrdered()新方法：</p><pre class="crayon-plain-tag">public function homepageAction()
    {
        $categoryRepository = $this-&gt;getDoctrine()
            -&gt;getManager()
            -&gt;getRepository('AppBundle:Category');
        $categories = $categoryRepository-&gt;findAllOrdered();
...
    }</pre><p>这个方法要写在 <span style="color: #ff0000"><code>CategoryRepository</code></span> 类里。因此在你需要去创建一个<span style="color: #ff0000">public function findAllOrdered()</span>。为了看看是否已经起效，用一个<span style="color: #ff0000">die</span>来测试：</p><pre class="crayon-plain-tag">class CategoryRepository extends EntityRepository
{
    public function findAllOrdered()
    {
        die('this query will blow your mind...');
    }
}</pre><p>刷新！丑陋的黑字出现了。</p>
<p>OK，下面你需要去写SQL，是MySQL查询。好，但是Doctrine使用一个不同的语言：DQL（Doctrine Query Language）。不用担心，他很接近SQL，很多时候你不会注意到他们的区别。</p>
<p>让我们来看一看DQL：<span style="color: #ff0000"><code>$dql = 'SELECT cat FROM AppBundle\Entity\Category cat';</code></span>:</p><pre class="crayon-plain-tag">class CategoryRepository extends EntityRepository
{
    public function findAllOrdered()
    {
        $dql = 'SELECT cat FROM AppBundle\Entity\Category cat';
... 
    }
}</pre><p>这个DQL最大的不同是你用php类来替代了数据表。这就是为什么我们选择了完整的类名实体。Symfony的用户习惯于AppBundle:Category，但它仅仅是一个别名-内部总会返回一个完整的类名。</p>
<p>这个<span style="color: #ff0000">cat</span>部分就好像SQL的别名。并且用你写的别名 <span style="color: #ff0000">SELECT cat </span>去替代 <span style="color: #ff0000">SELECT *</span>。它将查询每一列。最后，我会告诉你如何查询你想要的字段。</p>
<p>&nbsp;</p>
<h3>执行DQL</h3>
<p>要运行它，我们需要创建一个查询对象。获取<span style="color: #ff0000">EntityManager</span>，调用<span style="color: #ff0000">createQuery()</span>，并传入DQL。我们有了Query对象以后，在掉用他的<span style="color: #ff0000">execute()</span>；</p><pre class="crayon-plain-tag">class CategoryRepository extends EntityRepository
{
    public function findAllOrdered()
    {
        $dql = 'SELECT cat FROM AppBundle\Entity\Category cat';
        $query = $this-&gt;getEntityManager()-&gt;createQuery($dql);
        return $query-&gt;execute();
    }
}</pre><p>他将会返回<span style="color: #ff0000">Category</span>对象数组。Doctrie标准的模式就是返回对象。不是一个数组数据。但这是可以改变的。</p>
<p>让我们来查询命运！刷新页面。不错，我们看到了同样的结果-这就是<span style="color: #ff0000">findAll()</span>在背后做的事情。</p>
<p>&nbsp;</p>
<h3>添加 ORDER BY</h3>
<p>添加<span style="color: #ff0000">ORDER BY</span>，就像是SQL。添加<span style="color: #ff0000">ORDER BY</span>，然后追加<span style="color: #ff0000">cat.name DESC</span>；</p><pre class="crayon-plain-tag">public function findAllOrdered()
    {
        $dql = 'SELECT cat FROM AppBundle\Entity\Category cat ORDER BY cat.name DESC';
        $query = $this-&gt;getEntityManager()-&gt;createQuery($dql);
        return $query-&gt;execute();
    }</pre><p>刷新！分类按照字母排序了！所以这个DQL：您提到的类名,来替代SQL表名。如果你“Google：Doctrine DQL”，你可以找到更多的Doctrine文档。</p>
<p>&nbsp;</p>
<h3>显示我的SQL</h3>
<p>但是最终，Doctrine DQL会返回一个真实的Mysql语句，或者PostgreSQL （无论你用什么引擎）。</p>
<p>我们可以看到SQL吗？当然你作为调试他是很有用的。仅仅使用<span style="color: #ff0000"><code>var_dump</code> <code>$query-&gt;getSQL()</code></span>:</p><pre class="crayon-plain-tag">public function findAllOrdered()
    {
        $dql = 'SELECT cat FROM AppBundle\Entity\Category cat ORDER BY cat.name DESC';
        $query = $this-&gt;getEntityManager()-&gt;createQuery($dql);
        var_dump($query-&gt;getSQL());die;
        return $query-&gt;execute();
    }</pre><p>刷新！虽然不是很漂亮，但是他出来了。冷静,最靠谱的SQL居然在幕后。删除该调试代码吧。</p>
<p><img class="alignnone size-large wp-image-1001" src="http://www.newlifeclan.com/symfony/wp-content/uploads/sites/2/2016/06/20160604121040-1024x71.png" alt="sql" width="780" height="54" /></p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/990">亲一亲Doctrine查询之1：Doctrine DQL</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.newlifeclan.com/symfony/archives/990/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JMSDiExtraBundle配置</title>
		<link>http://www.newlifeclan.com/symfony/archives/938</link>
		<comments>http://www.newlifeclan.com/symfony/archives/938#comments</comments>
		<pubDate>Mon, 11 Apr 2016 10:50:40 +0000</pubDate>
		<dc:creator><![CDATA[napoleon]]></dc:creator>
				<category><![CDATA[实战教程]]></category>

		<guid isPermaLink="false">http://www.newlifeclan.com/symfony/?p=938</guid>
		<description><![CDATA[<p>默认情况下，你只能使用controller自带的annotations。没有其他的。 然而，如果你也想使用注释 [&#8230;]</p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/938">JMSDiExtraBundle配置</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>默认情况下，你只能使用controller自带的annotations。没有其他的。<span id="more-938"></span></p>
<p>然而，如果你也想使用注释来配置你的常规服务,看看下面：</p>
<h3>配置Locations</h3>
<p>如果你想使用annotations去配置一个服务在你的bundle，或者任何bundle以外的一些服务，比如你src/目录下的，您可以使用以下配置选项，这个bundle将捡起他们，并添加他们到你的依赖服务中。</p><pre class="crayon-plain-tag">jms_di_extra:
    locations:
        all_bundles: false
        bundles: [FooBundle, AcmeBlogBundle]
        directories: ["%kernel.root_dir%/../src"]</pre><p>&nbsp;</p>
<h3>自动控制器注入</h3>
<p>这个bundle允许你去配置注入某些属性，并自动到控制器方法。这是最有用的常用服务，然后不需要注释。</p><pre class="crayon-plain-tag">jms_di_extra:
    automatic_controller_injections:
        properties:
            request: "@request"
            router: "@router"

        method_calls:
            setRouter: ["@router"]</pre><p>如果你的控制器有任何上述属性或者方法，你就不需要去添加一个 @Inject 注释了，我们会自动为您注入配置的服务。那么，如果你声明一个@Inject注释他将自动覆盖所有配置。</p>
<p>&nbsp;</p>
<p>禁止使用grep</p>
<p>这个bundle使用不同地方法找到你文件中的注释，这取决于你的操作系统和使用的软件。如果您使用的是Linux发行版的<tt class="docutils literal"><span class="pre">grep安装，grep将默认代替symfony查找，来提高性能。</span></tt></p>
<p>有时，你可能不想让bundle去使用grep，例如，你的grep版本太旧，因此不支持一些较新的选项。在这种情况下，您可以禁止使用grep，请看下列配置：</p><pre class="crayon-plain-tag">jms_di_extra:
    disable_grep: true</pre><p>&nbsp;</p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/938">JMSDiExtraBundle配置</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.newlifeclan.com/symfony/archives/938/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JMSDiExtraBundle安装</title>
		<link>http://www.newlifeclan.com/symfony/archives/936</link>
		<comments>http://www.newlifeclan.com/symfony/archives/936#comments</comments>
		<pubDate>Mon, 11 Apr 2016 06:58:49 +0000</pubDate>
		<dc:creator><![CDATA[napoleon]]></dc:creator>
				<category><![CDATA[实战教程]]></category>

		<guid isPermaLink="false">http://www.newlifeclan.com/symfony/?p=936</guid>
		<description><![CDATA[<p>通过composer可以安装JMSDiExtraBundle。添加下列命令到composer.json文件：  [&#8230;]</p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/936">JMSDiExtraBundle安装</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>通过composer可以安装JMSDiExtraBundle。添加下列命令到composer.json文件：<span id="more-936"></span></p><pre class="crayon-plain-tag">// composer.json
{
    // ...
    require: {
        // ...
        "jms/di-extra-bundle": "dev-master"
    }
}</pre><p>然后，你可以通过update命令去更新composer.json文件的依赖安装：</p><pre class="crayon-plain-tag">php composer.phar update</pre><p>composer会自动下载所有需要的文件，并安装他们。所有的这些会都要去更新的你的AppKernel.php文件，并注册新的bundle：</p><pre class="crayon-plain-tag">&lt;?php

// in AppKernel::registerBundles()
$bundles = array(
    // ...
    new JMS\DiExtraBundle\JMSDiExtraBundle($this),
    new JMS\AopBundle\JMSAopBundle(),
    // ...
);</pre><p>&nbsp;</p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/936">JMSDiExtraBundle安装</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.newlifeclan.com/symfony/archives/936/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>将entities转换为Json</title>
		<link>http://www.newlifeclan.com/symfony/archives/933</link>
		<comments>http://www.newlifeclan.com/symfony/archives/933#comments</comments>
		<pubDate>Wed, 06 Apr 2016 15:49:18 +0000</pubDate>
		<dc:creator><![CDATA[napoleon]]></dc:creator>
				<category><![CDATA[实战教程]]></category>

		<guid isPermaLink="false">http://www.newlifeclan.com/symfony/?p=933</guid>
		<description><![CDATA[<p>我们有时需要将一个entity集合，转换成json来供ajax使用。这时有一个很好的bundle能够解决这样的 [&#8230;]</p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/933">将entities转换为Json</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>我们有时需要将一个entity集合，转换成json来供ajax使用。这时有一个很好的bundle能够解决这样的问题，当然 Symfony\Component\Serializer\Serializer也可以，但是使用bundle会更加便利。</p>
<p><span id="more-933"></span></p>
<p>安装JMSSerializerBundle</p><pre class="crayon-plain-tag">composer require jms/serializer-bundle</pre><p>注册bundle</p><pre class="crayon-plain-tag">// in AppKernel::registerBundles()
$bundles = array(
    // ...
    new JMS\SerializerBundle\JMSSerializerBundle(),
    // ...
);</pre><p>在controller中写入</p><pre class="crayon-plain-tag">/**
     * @Route("/ajax/list", name="ajax_list")
     * @Method("GET")
     */
    public function ajaxlistAction(Request $request)
    {
        $em = $this-&gt;getDoctrine()-&gt;getManager();
        $dnrientitys = $em-&gt;getRepository('AppBundle:Category')-&gt;find(1)-&gt;getDnri();

        //将entities转化为json
          $serializer=$this-&gt;get('serializer');
          $newdata=$serializer-&gt;serialize($dnrientitys,'json');
        $response= new Response($newdata);
        return $response;</pre><p>你可以访问，这个controller看看是否输出了JSON没有问题，但是当你使用中文时你会发现一个经常遇到的问题json的unicode中文编码问题。</p>
<p>通常我们要在json_encode($data,JSON_UNESCAPED_UNICODE) 来防止编码问题的出现。但在serializer中我们不能这样做，我们只需要配置一下即可：</p>
<p>打开config.yml</p><pre class="crayon-plain-tag">jms_serializer:
    visitors:
        json:
            options: [JSON_UNESCAPED_UNICODE]</pre><p>ok! 手工。</p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/933">将entities转换为Json</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.newlifeclan.com/symfony/archives/933/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CMF之BlockBundle</title>
		<link>http://www.newlifeclan.com/symfony/archives/919</link>
		<comments>http://www.newlifeclan.com/symfony/archives/919#comments</comments>
		<pubDate>Mon, 14 Mar 2016 15:01:03 +0000</pubDate>
		<dc:creator><![CDATA[napoleon]]></dc:creator>
				<category><![CDATA[实战教程]]></category>

		<guid isPermaLink="false">http://www.newlifeclan.com/symfony/?p=919</guid>
		<description><![CDATA[<p>这个Bundle整合了SonataBlockBundle。它是用来管理内容的一部分,所谓的块,保存在数据库中, [&#8230;]</p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/919">CMF之BlockBundle</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>这个Bundle整合了SonataBlockBundle。它是用来管理内容的一部分,所谓的块,保存在数据库中,可以被纳入任何页面布局。<span id="more-919"></span></p>
<p>这个symfony2 cmf BlockBundle还提供了一些常用的标准块，包含编辑它们的能力。看看<a class="reference internal" href="http://symfony.com/doc/master/cmf/bundles/block/types.html"><em>Block Types</em></a>.</p>
<p>&nbsp;</p>
<h3>安装</h3>
<p>你可以使用composer安装bundle，<a class="reference external" href="https://packagist.org/packages/symfony-cmf/block-bundle">symfony-cmf/block-bundle</a>包。</p>
<p>因为这个bundle使用<a class="reference external" href="https://github.com/sonata-project/SonataBlockBundle">SonataBlockBundle</a>,你需要实例化一些sonata bundle到CmfBlockBundle：</p><pre class="crayon-plain-tag">// app/AppKernel.php

// ...
class AppKernel extends Kernel
{
    public function registerBundles()
    {
        $bundles = array(
            // ...
            new Sonata\BlockBundle\SonataBlockBundle(),
            new Sonata\CoreBundle\SonataCoreBundle(),
            new Symfony\Cmf\Bundle\BlockBundle\CmfBlockBundle(),
        );

        // ...
    }

    // ...
}</pre><p>&nbsp;</p>
<h3>使用</h3>
<p>该BlockBundle需要配置一个persistence层。这可以在Core Bundle的全局配置内完成或者在个别地方完成如下所示：</p><pre class="crayon-plain-tag">cmf_block:
    persistence:
        phpcr:
            block_basepath: /cms/content</pre><p>一个块的默认setting定义在一个块服务中。如果你使用一个第三方块，你可能想为你的应用程序改变他们。给他定义一个sonata_block键。你能够为一个块服务类型或者为多个特定的块（block）类定义默认setting。后面，当你使用多个块类的相同的块服务，但你只想要块类的一个特定settings时，他会非常有用：</p><pre class="crayon-plain-tag"># app/config/config.yml
sonata_block:
    blocks:
        acme_main.block.news:
            settings:
                maxItems: 3
    blocks_by_class:
        Symfony\Cmf\Bundle\BlockBundle\Doctrine\Phpcr\RssBlock:
            settings:
                maxItems: 5</pre><p></p>
<blockquote><p> 你还可以存储settings到一个单一的块对象本身。它允许去分别配置每个块的实例。</p>
<p>如果你使用sonata admin编辑这个块，这里还提供 <a class="reference internal" href="http://symfony.com/doc/master/cmf/bundles/block/types.html#bundles-block-types-admin-extension">Block Sonata Admin Extension</a>来为<tt class="docutils literal"><code>BaseBlock普通的块添加编辑选项。</code></tt></p></blockquote>
<p>&nbsp;</p>
<h3>更新SonataBlockBundle默认值</h3>
<p>这个BlockBundle会自动改变一些默认值并将配置添加到SonataBlockBundle让他很好的工作。这是使用symfony的 <a class="reference external" href="http://symfony.com/doc/current/components/dependency_injection/compilation.html#prepending-configuration-passed-to-the-extension">prepended configuration</a> 选项。更新下面的默认值：</p>
<ul>
<li><strong>templates.block_base：</strong>这个CMF基础模板封装的块会输出到一个div里并把这个PHPCR路径作为id；这个基础模板和不是CMF块的sonata基础模板保持兼容；</li>
<li><strong>RssBlock configuration</strong> 添加了<a class="reference internal" href="http://symfony.com/doc/master/cmf/bundles/block/types.html#bundle-block-rss-settings">default RssBlock settings</a>.</li>
</ul>
<blockquote><p>Settings只是预先被考虑，意思是默认值被改变。你能通过在你的应用程序文件中设置配置的值你仍能改变这些值。</p></blockquote>
<p>&nbsp;</p>
<h3>Block Document</h3>
<p>你能够呈现一个块之前，你需要在库中去创建一个数据对象代表你的块。可以用下面的代码片段:</p><pre class="crayon-plain-tag">use Symfony\Cmf\Bundle\BlockBundle\Doctrine\Phpcr\SimpleBlock;

// ...
/** @var $dm \Doctrine\ODM\PHPCR\DocumentManager */
$parentDocument = $dm-&gt;find(null, '/cms/content/home');

$myBlock = new SimpleBlock();
$myBlock-&gt;setParentDocument($parentDocument);
$myBlock-&gt;setName('sidebarBlock');
$myBlock-&gt;setTitle('My first block');
$myBlock-&gt;setBody('Hello block world!');

$dm-&gt;persist($myBlock);</pre><p>注意这个<tt class="docutils literal"><code>sidebarBlock我们选择为这个块的标识符。与这个块的父document一起，定义了块的唯一标识符。其他属性（title和body）是Symfony\Cmf\Bundle\BlockBundle\Doctrine\Phpcr\SimpleBlock特定的。</code></tt></p>
<p>这个简单的块现在准备好了去渲染，请看 Block 渲染。</p>
<blockquote><p>确保你的块总是实现Sonata\BlockBundle\Model\BlockInterface接口或者继承一个已经存在的block document像<tt class="docutils literal"><code>Symfony\Cmf\Bundle\BlockBundle\Doctrine\Phpcr\AbstractBlock</code></tt>.</p></blockquote>
<p>&nbsp;</p>
<h3>Block Context</h3>
<p>该BlockContext包含了所有信息，并去渲染这个块需要的Block document.他集合并合并了所有配置的settings，block service（块服务），block document还有setting会传递到Twig模板助手。因此，使用这个BlockContext去获取和更改一个需要的settings。</p>
<p>&nbsp;</p>
<p>Block服务</p>
<p>&nbsp;</p>
<p>未完待续中。。。</p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/919">CMF之BlockBundle</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.newlifeclan.com/symfony/archives/919/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>cmf快速入门之第三方Bundle</title>
		<link>http://www.newlifeclan.com/symfony/archives/912</link>
		<comments>http://www.newlifeclan.com/symfony/archives/912#comments</comments>
		<pubDate>Sat, 12 Mar 2016 15:59:31 +0000</pubDate>
		<dc:creator><![CDATA[napoleon]]></dc:creator>
				<category><![CDATA[实战教程]]></category>

		<guid isPermaLink="false">http://www.newlifeclan.com/symfony/?p=912</guid>
		<description><![CDATA[<p>你还没走？你已经学习了基础的Symfony CMF并且你只是想学习，越来越多吗？那你就来阅读这一章吧！这一章将 [&#8230;]</p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/912">cmf快速入门之第三方Bundle</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>你还没走？你已经学习了基础的Symfony CMF并且你只是想学习，越来越多吗？那你就来阅读这一章吧！这一章将会快速介绍一些其他的CMF bundles。大多数的其他bundle都建立在巨人的肩膀上，像这个<a class="reference external" href="https://github.com/KnpLabs/KnpMenuBundle">KnpMenuBundle</a> 和 <a class="reference external" href="http://sonata-project.org/bundles/admin/master/doc/index.html">SonataAdminBundle</a>.<span id="more-912"></span></p>
<h3>MenuBundle</h3>
<p>让我们开始MenuBundle。如果你访问页面，你能够看到一个很棒的菜单。你能在AcmeDemoBundle的layout视图中找到这个渲染的菜单：</p><pre class="crayon-plain-tag">&lt;!-- src/Acme/DemoBundle/Resources/views/layout.html.twig --&gt;

&lt;!-- ... --&gt;
&lt;nav class="navbar  navbar-inverse  page__nav" role="navigation"&gt;
    &lt;div class="container-fluid"&gt;
        {{ knp_menu_render('simple', {'template': 'AcmeDemoBundle:Menu:bootstrap.html.twig', 'currentClass': 'active'}) }}

        &lt;!-- ... --&gt;
    &lt;/div&gt;
&lt;/nav&gt;</pre><p>正如你看到的，这个菜单通过  <tt class="docutils literal"><code>knp_menu_render标签渲染。</code></tt>这似乎有点奇怪，我们正在谈论CmfMenuBundle而不是KnpMenuBundle,不是吗? 当然正确，但事实是CmfMenuBundle建立在KnpMenuBundle基础上的bundle。</p>
<p>通常，knp_menu_render()是使用菜单名称作为参数去渲染，但当使用CmfMenuBundle时，他是一个节点id。在这个例子中，这个/cms/simple里菜单包含所有实现<tt class="docutils literal"><code>NodeInterface的项（因为这个web全路径在标准版里是 /cms）。</code></tt></p>
<p>除了包括PHPCR菜单提供器，这个CmfMenuBundle还提供了Admin类。看本章关于 <a class="reference internal" href="http://symfony.com/doc/master/cmf/quick_tour/the_third_party_bundles.html#sonata-admin">Sonata Admin</a>的知识。</p>
<p>&nbsp;</p>
<h3>CreateBundle</h3>
<p>我们已经在第一章看到过这个bundle。这个bundle使用FOSRestBundle结合了CreatePHP库（使用这个Create.js库）到Symfony2。</p>
<p>这个Create.js库使用一个REST层。页面上的所有元素获得<a class="reference external" href="http://en.wikipedia.org/wiki/RDFa">RDFa Mappings</a>,就是告诉Create.js如何将元素映射到文件。当你保存页面时，这个新的内容是传入到REST api并保存到数据库。</p>
<p>RDFa mappings呈现内容会非常容易，你能在标准版看到：</p><pre class="crayon-plain-tag">{% block main %}
{% createphp cmfMainContent as="rdf" %}
{{ rdf|raw }}
{% endcreatephp %}
{% endblock %}</pre><p>它将使用&lt; div &gt;元素输出内容对象。你也可以使用createphp_*函数来完全自定义。</p>
<p>&nbsp;</p>
<h3>BlockBundle</h3>
<p>如果你访问这个标准版的主页，你将看到三个块：</p>
<p><img class="alignnone size-large wp-image-916" src="http://www.newlifeclan.com/symfony/wp-content/uploads/sites/2/2016/03/3rd-party-bundles-homepage-1024x546.png" alt="3rd-party-bundles-homepage" width="780" height="415" /></p>
<p>这些块可以自己编辑和使用。这些块通过BlockBundle提供，他建立在SonataBlockBundle层之上。它提供实用PHPCR来存储块的能力并增加了一些常用的块。</p>
<p>这三个块在标准版里是自定义块。一个块是通过一个块服务来处理。你能够在Acme\DemoBundle\Block\UnitBlockService类中找到这个服务。自从这个块使用PHPCR持久化以来，他还需要一个块文档，他在Acme\DemoBundle\Document\UnitBlock中。</p>
<p>&nbsp;</p>
<h3>SeoBundle</h3>
<p>还有一个SeoBundle。这个bundle建立在SonataSeoBundle之上。它提供了一种方法来从文档提取SEO信息并使用admin来编辑SEO信息。</p>
<p>标准版集成了这个SeoBundle，你需要composer require symfony-cmf/seo-bundle命令把它包含到你的项目中，然后注册CMF和Sonata Bundle的seo到AppKernel：</p><pre class="crayon-plain-tag">// app/AppKernel.php

// ...
public function registerBundles()
{
    $bundles = array(
        // ...
        new Sonata\SeoBundle\SonataSeoBundle(),
        new Symfony\Cmf\Bundle\SeoBundle\CmfSeoBundle(),
    );
    // ...
}</pre><p>现在，你可以配置一个标准的title。当CmfSeoBundle从一个内容对象中取出这个title，这个title就被使用了：</p><pre class="crayon-plain-tag"># app/config/config.yml
cmf_seo:
    title: "%%content_title%% | Standard Edition"</pre><p>这个<tt class="docutils literal"><code>%%content_title%%将被从内容对象里获取的title所替换。你最后需要做的事情就是使用这个标题的标题元素。要做到这一点，就在<tt class="docutils literal"><code>src/Acme/DemoBundle/Resources/views/layout.html.twig模板中替换&lt;title&gt;标签：</code></tt></code></tt></p><pre class="crayon-plain-tag">{% block title %}{{ sonata_seo_title() }}{% endblock %}</pre><p>当你访问你的新网站时，你就能看到每个页面的标题了。</p>
<p>一些页面，像登陆页面，不需要使用内容对象。在这个例子中，你能配置默认的title：</p><pre class="crayon-plain-tag"># app/config/config.yml
sonata_seo:
    page:
        title: Standard Edition</pre><p></p>
<blockquote><p> 这个默认的title是配置在sonata_seo扩展下，这个标准版的title被配置在cmf_seo扩展下。</p></blockquote>
<p>这个title仅仅是SeoBundle的一个特性，它能够开始或者处理更多的seo信息。</p>
<p>&nbsp;</p>
<h3>Sonata Admin</h3>
<p>我们已经解释了你的这个CMF是基于数据库，为了可以不改变代码通过一个admin来编辑。但是我没有告诉你admin如何管理和维护网站。现在是时候该展示怎么做了：使用SonataAdminBundle。CMF bundle定义了一些可编辑的元素也提供了在admin中其他的元素可编辑。</p>
<p>默认，当这个<a class="reference external" href="http://sonata-project.org/bundles/doctrine-phpcr-admin/master/doc/index.html">SonataDoctrinePHPCRAdminBundle</a>被安装，在CMF bundle中的所有admin类将被启用。你可以在配置中关掉这个admin类。例如，禁用MenuBundle的admin类，你应该这么做：</p><pre class="crayon-plain-tag"># app/config/config.yml
cmf_menu:
    persistence:
        phpcr:
            use_sonata_admin: false</pre><p>你也能禁用／启用所有的CMF admin类，通过配置这个cmf_core bundle:</p><pre class="crayon-plain-tag"># app/config/config.yml
cmf_core:
    persistence:
        phpcr:
            use_sonata_admin: false</pre><p>当这个admin类被启用，这个admin能够访问/admin（如果你正确安装了SonataAdminBundle）并找到著名的admin dashboard，看到所有需要的：</p>
<p><img class="alignnone size-large wp-image-917" src="http://www.newlifeclan.com/symfony/wp-content/uploads/sites/2/2016/03/3rd-party-bundles-sonata-admin-1024x486.png" alt="3rd-party-bundles-sonata-admin" width="780" height="370" /></p>
<p>你看到在左边，admin使用<em><a class="reference internal" href="http://symfony.com/doc/master/cmf/bundles/tree_browser/introduction.html">TreeBrowserBundle</a>去显示现有的admin树，在这里这个admin能够去点击节点，去编辑，删除或者移动她们。</em></p>
<p>&nbsp;</p>
<h3>总结</h3>
<p>你做到了！让我们来总结一下你在快速入门学到了什么：</p>
<ul>
<li>symfony的CMF是高度可定制的内容管理系统；</li>
<li>Symfony CMF团队创建的bundle是一个具有CMS特性的bundle，可以两者一起使用还可独立使用；</li>
<li>Symfony CMF使用数据库为了让admin做更多编辑的事情，然而配置保存在文件系统去保持部署的简单并支持版本控制；</li>
<li>PHPCR是建立CMS系统的一个伟大的数据库，但symfony cmf也能使用任何其他的存储系统；</li>
<li>相反，结合控制器到路由，路由再绑定内容对象；</li>
<li>Symfony CMF当心不要重复发明轮子。很多的bundle集合一处俗称symfony2 bundle；</li>
</ul>
<p>&nbsp;</p>
<p>我不能告诉你更多关于体系结构和Symfony CMF Bundle，但仍然可以有很多的探索。看看<a class="reference internal" href="http://symfony.com/doc/master/cmf/book/index.html"><em>the book</em></a> ，开始使用Symfony CMF来做第一个项目。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/912">cmf快速入门之第三方Bundle</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.newlifeclan.com/symfony/archives/912/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>cmf快速入门之路由</title>
		<link>http://www.newlifeclan.com/symfony/archives/909</link>
		<comments>http://www.newlifeclan.com/symfony/archives/909#comments</comments>
		<pubDate>Thu, 10 Mar 2016 17:39:16 +0000</pubDate>
		<dc:creator><![CDATA[napoleon]]></dc:creator>
				<category><![CDATA[实战教程]]></category>

		<guid isPermaLink="false">http://www.newlifeclan.com/symfony/?p=909</guid>
		<description><![CDATA[<p>欢迎来到快速入门的第三部分。你似乎爱上了CMF，来到这么远！这是一件好事，你将在本章学习更多CMF的主干：路由 [&#8230;]</p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/909">cmf快速入门之路由</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>欢迎来到快速入门的第三部分。你似乎爱上了CMF，来到这么远！这是一件好事，你将在本章学习更多CMF的主干：路由。</p>
<p><span id="more-909"></span></p>
<p>&nbsp;</p>
<h3>CMF的主干</h3>
<p>已经说过，这个路由是主干。去了解他，你要有一个很好的观点，CMS要做什么。在一个普通的Symfony程序中，一个路由会归属于一个controller，来处理一个特定的实体。其他路由指派其他的controller处理其他的实体。这个方式，十个路由绑定一个控制器。事实上，使用symfony核心处理CMS对你来说也是有限的。</p>
<p>但如果你看看CMS的基础，他仅仅需要处理1个类型的entity：Content。所以大多数路由不必再被连接到一个控制器，因为只需要一个控制器。该路线已被绑定到特定的内容对象，在他的一侧&#8211;可以引用特定的模板和控制器。</p>
<p>在CMF的其他部分也涉及到路由。给两个例子：这个菜单（menu）是通过路由器生成特定的路由来创建的，这个块（Blocks）显示特定的路由（因为他们相关联一个模板）。</p>
<p>&nbsp;</p>
<h3>从PHPCR树加载路由</h3>
<p>在第一章，你已经学习了使用一个专门的DynamicRouter从数据库中加载路由。这个方式，并不是所有的路由都需要加载每个请求。</p>
<p>&nbsp;</p>
<p>未完待续中&#8230;&#8230;</p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/909">cmf快速入门之路由</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.newlifeclan.com/symfony/archives/909/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>cmf快速入门之Model</title>
		<link>http://www.newlifeclan.com/symfony/archives/903</link>
		<comments>http://www.newlifeclan.com/symfony/archives/903#comments</comments>
		<pubDate>Thu, 10 Mar 2016 16:12:02 +0000</pubDate>
		<dc:creator><![CDATA[napoleon]]></dc:creator>
				<category><![CDATA[实战教程]]></category>

		<guid isPermaLink="false">http://www.newlifeclan.com/symfony/?p=903</guid>
		<description><![CDATA[<p>你决定继续读10分钟Symfony CMF了吗?这是个好消息！在这一章，你将学习更多关于CMF默认的数据库层的 [&#8230;]</p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/903">cmf快速入门之Model</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>你决定继续读10分钟Symfony CMF了吗?这是个好消息！在这一章，你将学习更多关于CMF默认的数据库层的知识。<span id="more-903"></span></p>
<blockquote><p>这章会再次讨论PHPCR的存储层。但CMF的存储是可以混合创建的，这意味着他没有特定的存储系统。</p></blockquote>
<p>&nbsp;</p>
<h3>熟悉PHPCR</h3>
<p>PHPCR存储所有数据到一个大树状结构中。你能够比对一个文件系统的每个文件和目录包含的数据。这意味着所有的数据被存储，与PHPCR有关系，至少有一个其他数据：他的父节点。当然逆关系关系也是存在的，你也能获取一个数据元素的子节点。</p>
<p>让我们看一看上一章我们下载的标准版的树状。来到你的目录并执行下面命令：</p><pre class="crayon-plain-tag">$ php app/console doctrine:phpcr:node:dump</pre><p>PHPCR树状的结果是：</p><pre class="crayon-plain-tag">ROOT:
  cms:
    simple:
      about:
      contact:
        map:
        team:
      quick_tour:
      dynamic:
      docs:
      demo:
      demo_redirect:
      hardcoded_dynamic:
      hardcoded_static:</pre><p>在PHPCR中每个数据都是一个被调用的节点。在这个树中，有13个节点和一个根节点（通过PHPCR被创建）。你可能已经看到您在前一节中创建的文档，他调用<tt class="docutils literal"><code>quick_tour（并且他的路径是/cms/simple/quick_tour）。当使用SimpleCmsBundle时，所有节点存储在/cms/simple路径。</code></tt></p>
<p>每个节点都有属性，就是包含的数据。为你页面设置的content，title和label都被保存在quick_tour节点下的属性。你能够通过在dump命令行添加&#8211;props开关预览属性。</p>
<blockquote><p> 之前，这个PHPCR树与一个文件系统比较。他给你一个良好的形象，对于发生的，但他不是真相。你可以更好的比作他为一个XML文件，这里每一个节点是一个元素并他的属性比作是XML属性。</p></blockquote>
<p>&nbsp;</p>
<h3>Doctrine PHPCR-ODM</h3>
<p>Symfony CMF使用 <a class="reference external" href="http://docs.doctrine-project.org/projects/doctrine-phpcr-odm/en/latest/">Doctrine PHPCR-ODM</a>与PHPCR交互。Doctrine允许一个用户去创建对象（调用documents），直接持久化并从PHPCR中检索。这个类似于symfony2框架中Doctrine ORM的使用，但这是PHPCR。</p>
<h3>用代码创建一个页面</h3>
<p>现在你知道更多关于PHPCR的知识，并且你知道与它交互的工具，你自己可以开始使用它。在前面的章节中，你通过使用yaml文件创建一个页面，通过SimpleCmsBundle解析。这次，你将通过自己完成创建一个页面。</p>
<p>首先，你需要去创建一个新的DataFixture到你的新页面。在AcmeDemoBundle中创建一个新页面。</p><pre class="crayon-plain-tag">// src/Acme/DemoBundle/DataFixtures/PHPCR/LoadPageData.php
namespace Acme\DemoBundle\DataFixtures\PHPCR;

use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;

class LoadPageData implements FixtureInterface, OrderedFixtureInterface
{
    public function getOrder()
    {
        // refers to the order in which the class' load function is called
        // (lower return values are called first)
        return 10;
    }

    public function load(ObjectManager $documentManager)
    {
    }
}</pre><p>这个$documentManager对象将持久化这个document到PHPCR。但首先，你要创建一个新的document页面。</p><pre class="crayon-plain-tag">use Doctrine\ODM\PHPCR\DocumentManager;
use Symfony\Cmf\Bundle\SimpleCmsBundle\Doctrine\Phpcr\Page;

// ...
public function load(ObjectManager $documentManager)
{
    if (!$documentManager instanceof DocumentManager) {
        $class = get_class($documentManager);
        throw new \RuntimeException("Fixture requires a PHPCR ODM DocumentManager instance, instance of '$class' given.");
    }

    $page = new Page(); // create a new Page object (document)
    $page-&gt;setName('new_page'); // the name of the node
    $page-&gt;setLabel('Another new Page');
    $page-&gt;setTitle('Another new Page');
    $page-&gt;setBody('I have added this page myself!');
}</pre><p>每个document都需要一个父元素，这个父元素应该是root节点。要做到这一点，我们首先要从PHPCR中获取root document，然后设置它作为父元素：</p><pre class="crayon-plain-tag">public function load(ObjectManager $documentManager)
{
    if (!$documentManager instanceof DocumentManager) {
        $class = get_class($documentManager);
        throw new \RuntimeException("Fixture requires a PHPCR ODM DocumentManager instance, instance of '$class' given.");
    }

    // ...

    // get root document (/cms/simple)
    $simpleCmsRoot = $documentManager-&gt;find(null, '/cms/simple');

    $page-&gt;setParentDocument($simpleCmsRoot); // set the parent to the root
}</pre><p>最后，我们告诉Document管理使用Doctrine API去持久化我们的页面文档：</p><pre class="crayon-plain-tag">// ...
public function load(ObjectManager $documentManager)
{
    if (!$documentManager instanceof DocumentManager) {
        $class = get_class($documentManager);
        throw new \RuntimeException("Fixture requires a PHPCR ODM DocumentManager instance, instance of '$class' given.");
    }

    // ...
    $documentManager-&gt;persist($page); // add the Page in the queue
    $documentManager-&gt;flush(); // add the Page to PHPCR
}</pre><p>现在你需要执行doctrine:phpcr:fixtures:load命令，然后你就能再次访问你的web页面了。你能够看到新添加的页面了：</p>
<p><img class="alignnone size-large wp-image-907" src="http://www.newlifeclan.com/symfony/wp-content/uploads/sites/2/2016/03/the-model-new-page-1024x547.png" alt="the-model-new-page" width="780" height="416" /></p>
<blockquote><p>如果你想知道更多关于symfony应用中如何使用PHPCR的请阅读&#8221;<a class="reference internal" href="http://symfony.com/doc/master/cmf/book/database_layer.html"><em>The Database Layer: PHPCR-ODM</em></a>&#8220;</p></blockquote>
<p>&nbsp;</p>
<h3>总结</h3>
<p>PHPCR是很强大的方法在CMS中存储你的页面。但，如果你感到不舒服，你可以使用别的存储层http://symfony.com/doc/master/cmf/cookbook/database/choosing_storage_layer.html。</p>
<p>我们回顾这些已经20分钟了，你应该已经学会了如何使用一个新的存储层工作并添加了2个新页面。你看到你制作的应用程序在CMF中是如何简单的工作了吗？他提供的很多东西，在以前你可能都要自己完成。</p>
<p>但现在你只看到一个CMF的小部分，还有很多要学习的东西在等着你。在做这些所有事情之前，你要先了解CMF的主干：路由系统。在下一章你会了解更多关于他的信息。准备好另一个10分钟了吗？</p>
<p>&nbsp;</p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/903">cmf快速入门之Model</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.newlifeclan.com/symfony/archives/903/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
