2016-10-27 56 views
1

标题有点含糊我知道,但让我解释一下我试图达到的目标。循环通过树枝中的值并替换空值

我正在尝试根据从Symfony2 CRM中的原则查询中提取的数据生成CSV。检索的数据基于OpenCart产品和属性数据,以及一些与此问题无关的定制信息。

每个产品最多可以有5个不同的属性值,分别命名为A,B,D,L1和L2。但是,有些产品并不是全部,只有A,B和L1。 CSV要求每个属性值位于单独的单元格中 - 所以标题如下所示:

ATTRIBUTE:A |属性:B |属性:D | ATTRIBUTE:L1 | ATTRIBUTE:L2

然后我遍历我的枝条文件,如下所示:

{% for attribute in row.product.attributes %} 
    {% if attribute.text is not null %} 
     {{ attribute.text }}, 
    {% else %}na,{% endif %} 
{% endfor %} 

如果产品有各种属性5,在CSV的结构是好的。但是,如果产品只有3个属性,则意味着所有后续值都会被拉回一个单元格,这意味着其他数据位于错误的标题下。我第一次尝试检查值:

{% for attribute in row.product.attributes %} 
    {% if attribute.attributeName.name == "A" %} 
     {% if attribute.text is not null %} 
      {{ attribute.text }}, 
     {% else %}na,{% endif %} 
    {% endif %} 
{% endfor %} 

而且我这样做是对每个可能的属性名称,但unfortuantely这行不通,因为如果名称不存在,它只是跳过也无妨。如果试图想通过这些属性进行循环并在不存在的情况下输入n/a,我无法想到 - 我确信有一种方法,但我不知道它是什么。

作为参考,这里是正在生成的数据的CSV的控制器编码:

public function adminCsvAction($filter) { 

    $repository = $this->getDoctrine()->getRepository('AppBundle:Project'); 
    $stages_repository = $this->getDoctrine()->getRepository('AppBundle:Stage'); 
    $users_repository = $this->getDoctrine()->getRepository('AppBundle:User'); 

    $results = $repository->getSearchResults($filter); 
    $users = $users_repository->findAll(); 
    $stages = $stages_repository->findBy(array('deleted' => 0), array('sortOrder' => 'ASC')); 

    $filename = "export_".date("Y_m_d_His").".csv"; 

    $response = $this->render('AppBundle:pages:csv.html.twig', array('data' => $results,'users' => $users, 'stages' => $stages)); 
    $response->headers->set('Content-Type', 'text/csv'); 

    $response->headers->set('Content-Disposition', 'attachment; filename='.$filename); 
    return $response; 
} 

Project实体具有各种映射,其中一个链接到Opencart的产品表,这意味着所有的属性和链接值可以通过这个访问。

在这方面的任何帮助,非常感谢。

+2

在树枝编程(与php相比)可能会很痛苦。就我个人而言,我会写一个接受产品数据作为输入的php函数,并返回一个csv就绪数组,其中包含所有五个插槽。 – Cerad

+1

我同意Cerad,'枝'应该用于介绍,而不是修改 – DarkBee

+0

你已经尝试var_dumping每个变量?我有一个类似的问题,并var_dumped发现,翻译成你的情况,我必须使用'attribute [0] .text'而不是'attribute.text' – Florian

回答

0

我也同意Cerad从评论部分 - 这不是Twig的工作。如果你真的需要做到这一点,我会尝试大致是这样的:

{% set allAttr = ["A","B","D","L1","L2"] %} 

{% for attribute in allAttr %} 
    {% if row.product.attributes[attribute] is defined %} 
     {{ row.product.attributes[attribute].text }} 
    {% endif %} 

    {% if not loop.last %},{% endif %} 
{% endfor %} 

我猜is defined是这里的关键...

+0

这是一个好主意,但'row.product.attributes [attribute]'不会存在,因为A,B,C等在Attributes实体数组中的另一个名为attributeName的实体中被引用。 –

+0

这就是为什么'定义'会跳过整个'if'如果它不存在,对吧? –

+0

不,我的意思是永远不会存在,因为属性名称在另一个实体中。基本上,使用您建议的代码每次都没有结果(即na,na,na,na,na)。假设row.product.attributes有一个数组键“A”或“B”等,当它不。 –

0

好,我想通了。使用Jovan Perovic建议的,我想出了这个:

{% set allAttr = ["A","B","D","L1","L2"] %} 
{% set prodAtts = [] %} 
{% for row in data %} 
    {% set existingAtts = [] %} 
    {% for att in allAttr %} 
     {% if att not in prodAtts %} 
      {% set prodAtts = prodAtts|merge([att]) %} 
     {% endif %} 
    {% endfor %} 
    {% for rowAtt in row.product.attributes %} 
     {% set existingAtts = existingAtts|merge({(rowAtt.attributeName.name|trim):(rowAtt.attributeName.name|trim~'_'~rowAtt.text|trim)}) %} 
    {% endfor %} 
    {% for prodAtt in prodAtts %} 
     {% if prodAtt not in existingAtts|keys %} 
      {% set existingAtts = existingAtts|merge({(prodAtt):(prodAtt~'_na')}) %} 
     {% endif %} 
    {% endfor %} 
     {% set orderedAtts = existingAtts|sort %} 
.... 

然后循环每行之后。为了能够正确地对它进行排序(因为它只按值而不是键进行排序),我使用了带有下划线的属性名称,然后使用preg_replace将其与名称的任何实例一起删除,因此我最终得到了该值。

一点冗长 - 也许是过度思考 - 解决方案,但它确实有效!