首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >寻找将数据导出到以前在呈现窗体/DB查询的不同控制器路由中使用的CSV的干净方法

寻找将数据导出到以前在呈现窗体/DB查询的不同控制器路由中使用的CSV的干净方法
EN

Stack Overflow用户
提问于 2022-05-06 02:09:24
回答 2查看 372关注 0票数 1

我有一个页面,它的表单生成一个查询,该查询从我的数据库中呈现相关信息:渲染示例

我使用的控制器函数使用Symfony/Doctrine创建表单,然后调用存储库函数,根据用户提供的字段查询数据库。然后,我将这些结果显示在一个小枝文件中的一个表中,供用户检查。

我的问题是,我对Symfony相当陌生,我在创建一个“导出”按钮时,可以以某种方式获取传入的表单的数据,这样我就可以在新的路径中重新运行存储库函数,或者将数据从前面的查询本身传递到控制器中的一个新路由中的函数,然后我可以将这些数据转换为CSV文件。

目前,我让它以一种非常糟糕的方式工作,方法是在小枝文件中添加隐藏的输入字段,然后从每个字段中获取值,并将对象放在控制器函数中,然后将其转换为CVS。

我正在寻找一种简洁的方法,将ServiceController中的ServiceController函数/路由中的表单数据或查询数据转换为新的exportServiceAction函数/路由(或任何其他建议的方法来实现相同的目标)。

控制器函数

代码语言:javascript
复制
/**
 * Creates a form for Exporting Services associated with techs
 * @Route("/export", name="service_export", methods={"GET", "POST"})
 */
public function exportActions(Request $request, EntityManagerInterface $em)
{
    $staffEntities = $em->getRepository('AppBundle:User')->buildFindByRole('ROLE_STAFF')->getQuery()->getResult();
    $staffOptions = [];
    foreach ($staffEntities as $staff) {
        $staffUsername = $staff->getUsername();
        if(!array_key_exists($staffUsername, $staffOptions)) {
            $staffOptions[$staffUsername] = $staffUsername;
        }
    }

    $campusEntities = $em->getRepository('AppBundle:Campus')->findBy([], ['name' => 'ASC']);
    $campusOptions = [];
    foreach ($campusEntities as $campus) {
        $campusName = $campus->getName();
        if (!array_key_exists($campusName, $campusOptions)) {
            $campusOptions[$campusName] = $campusName;
        }
    }

    $buildingEntities = $em->getRepository('AppBundle:Building')->findBy([], ['name' => 'ASc']);
    $buildingOptions = [];
    foreach ($buildingEntities as $building) {
        $buildingName = $building->getName();
        if (!array_key_exists($buildingName, $buildingOptions)) {
            $buildingOptions[$buildingName] = $buildingName;
        }
    }

    $roomEntities = $em->getRepository('AppBundle:Room')->findBy([], ['name' => 'ASC']);
    $roomOptions = [];
    foreach ($roomEntities as $room) {
        $roomName = $room->getName();
        if (!array_key_exists($roomName, $roomOptions)) {
            $roomOptions[$roomName] = $roomName;
        }
    }

    $options = [
        'techs' => $staffOptions,
        'campuses' => $campusOptions,
        'buildings' => $buildingOptions,
        'rooms' => $roomOptions,
    ];

    $searchForm = $this->createForm('AppBundle\Form\SearchServiceType', [], $options);

    $searchForm->handleRequest($request);
    if($searchForm->isSubmitted() && $searchForm->isValid()) {
        $data = $searchForm->getData();
        dump($data);
        $queriedAssignments = $em->getRepository('AppBundle:Service')->findForExport($data);

        if (empty($queriedAssignments)) {
            $queriedAssignments = ["errorMessage" => "No Results Found!"];
        }
    }

    return $this->render('service/export.html.twig', [
        'form' => $searchForm->createView(),
        'assignments' => $queriedAssignments ?? null,
    ]);
}

(这里我想访问dataqueriedAssignments变量来创建CSV)

存储函数

代码语言:javascript
复制
public function findForExport(array $params = [])
{

    $em = $this->getEntityManager();

    $qb = $em->createQueryBuilder();

    $qb->select('a', 'u', 'bg', 'bsi', 'e', 's')
      ->from('AppBundle:Assignment', 'a')
      ->leftJoin('a.staff', 'u')
      ->leftJoin('a.task', 't')
      ->leftJoin('a.billingGroup', 'bg')
      ->leftJoin('bg.billingServiceItems', 'bsi')
      ->leftJoin('a.eventInstance', 'e')
      ->leftJoin('e.serviceRequest', 's')

      ->groupBy('a');

    $qb->orderBy('a.date', 'ASC')
            ->addOrderBy('a.startTime', 'ASC')
            ->addOrderBy('a.endTime', 'ASC');


    if (isset($params['startDate'])) {
      $qb->andWhere('a.date >= :startDate')
        ->setParameter('startDate', $params['startDate']);
    }
    if (isset($params['endDate'])) {
      $qb->andWhere('a.date <= :endDate')
        ->setParameter('endDate', $params['endDate']);
    }

    if ($params['promptStaff']) {
      if ($this->paramIsNotEmpty($params['techs'])) {
        $qb->andWhere('u.username IN (:techs)');
        $qb->setParameter('techs', $params['techs']);

                $qb->orderBy('u.username', 'ASC')
                    ->addOrderBy('a.date', 'ASC');
      }
    }

    if ([$params['promptLocation']]) {
      if ($this->paramIsNotEmpty($params['campusName']) || $this->paramIsNotEmpty($params['buildingName']) || $this->paramIsNotEmpty($params['roomName'])) {
        $qb->join('s.location', 'l');
      }
    }
    if ($this->paramIsNotEmpty($params['campusName'])) {
      $qb->andWhere('l.campusName IN (:campusName)');
      $qb->setParameter('campusName', $params['campusName']);
    }
    if ($this->paramIsNotEmpty($params['buildingName'])) {
      $qb->andWhere('l.buildingName IN (:buildingName)');
      $qb->setParameter('buildingName', $params['buildingName']);
    }
    if($this->paramIsNotEmpty($params['roomName'])) {
      $qb->andWhere('l.roomName IN (:roomName)');
      $qb->setParameter('roomName', $params['roomName']);
    }
        if ($this->paramIsNotEmpty($params['campusName']) || $this->paramIsNotEmpty($params['buildingName']) || $this->paramIsNotEmpty($params['roomName'])) {
            $qb->orderBy('l.campusName', 'ASC')
                ->addOrderBy('l.buildingName', 'ASC')
                ->addOrderBy('l.roomName', 'ASC')
                ->addOrderBy('a.date', 'ASC')
                ->addOrderBy('a.startTime', 'ASC')
                ->addOrderBy('a.endTime', 'ASC');
        }

    if ($this->paramIsNotEmpty($params['searchVenue'])) {
      $qb->leftJoin('s.location', 'l');
      $qb->andWhere(
        $qb->expr()->orX(
          $qb->expr()->like('l.venueName', ':searchVenue'),
          $qb->expr()->like('l.venueAddress', ':searchVenue'),
          $qb->expr()->like('l.venueCity', ':searchVenue'),
          $qb->expr()->like('l.venueState', ':searchVenue'),
          $qb->expr()->like('l.venueZipCode', ':searchVenue')
        )
        );
        $qb->setParameter('searchVenue', '%'.$params['searchVenue'].'%');

                $qb->orderBy('l.venueState', 'ASC')
                    ->addOrderBy('l.venueCity', 'ASC')
                    ->addOrderBy('l.venueName', 'ASC')
                    ->addOrderBy('a.date', 'ASC')
                    ->addOrderBy('a.startTime', 'ASC')
                    ->addOrderBy('a.endTime', 'ASC');
    }

    if ($this->paramIsNotEmpty($params['startTime'])) {
      $qb->andWhere('a.startTime >= :startTime');
      $qb->setParameter('startTime', $params['startTime']);
    }
    if ($this->paramIsNotEmpty($params['endTime'])) {
        $qb->andWhere('a.endTime <= :endTime');
        $qb->setParameter('endTime', $params['endTime']);
    }

    return $qb->getQuery()->getResult();
}

protected function paramIsNotEmpty($param)
{
    return $param instanceof ArrayCollection ? !$param->isEmpty() : !empty($param);
}

表单

代码语言:javascript
复制
public function buildForm(FormBuilderInterface $builder, array $options)
{
  $builder
    ->add('startDate', DateTimeType::class, [
      'widget' => 'single_text',
      'required' => false,
      'html5' => false,
      'attr' => ['class' => 'date', 'placeholder' => 'e.g. mm/dd/yyyy', 'autocomplete' => 'off'],
      'format' => 'MM/dd/yyyy',
    ])
    ->add('endDate', DateTimeType::class, [
      'widget' => 'single_text',
      'required' => false,
      'html5' => false,
      'attr' => ['class' => 'date', 'placeholder' => 'e.g. mm/dd/yyyy', 'autocomplete' => 'off'],
      'format' => 'MM/dd/yyyy',
    ])
    ->add('searchVenue', SearchType::class, [
      'required' => false,
      'label' => 'Venue Search (Name, Address, City, State, Zip)',
      'attr' => ['placeholder' => 'Press Enter to Search']
    ])
    ->add('promptStaff', CheckboxType::class, [
      'required' => false,
      'label' => 'Filter by Staff'
    ])
    ->add('promptLocation', CheckboxType::class, [
      'required' => false,
      'label' => 'Filter by Location'
    ])
    ->add('promptTime', CheckboxType::class, [
      'required' => false,
      'label' => 'Filter by Time'
    ])
    ->add('promptVenue', CheckboxType::class, [
      'required' => false,
      'label' => 'Search Venues'
    ])
    ->add('techs', ChoiceType::class, array(
      'required' => false,
      'expanded' => true,
      'multiple' => true,
      'label' => 'Staff Username',
      'choices' => $options['techs']
    ))
    ->add('campusName', ChoiceType::class, array(
      'required' => false,
      'expanded' => true,
      'multiple' => true,
      'choices' => $options['campuses']
    ))
    ->add('buildingName', ChoiceType::class, array(
      'required' => false,
      'expanded' => true,
      'multiple' => true,
      'choices' => $options['buildings']
    ))
    ->add('roomName', ChoiceType::class, array(
      'required' => false,
      'expanded' => true,
      'multiple' => true,
      'choices' => $options['rooms']
    ))
    ->add('startTime', ChoiceType::class, array(
      'choices' => $times,
      'required' => false,
      'placeholder' => 'Please Select'
    ))
    ->add('endTime', ChoiceType::class, array(
      'choices' => $times,
      'required' => false,
      'placeholder' => 'Please Select'
    ));
}

Twig

代码语言:javascript
复制
{% block body %}
<h1>Staff Time Export</h1>
{{ form_start(form) }}
{{ form_row(form.startDate) }}
{{ form_row(form.endDate) }}
<div class="filter-prompts">
  {{ form_row(form.promptStaff) }}
  {{ form_row(form.promptLocation) }}
  {{ form_row(form.promptTime) }}
</div>
<div class="staff-select">
  {{ form_row(form.techs) }}
</div>
<div class="location-select">
  {{ form_row(form.promptVenue)}}
  <div class="location-on-campus">
    {# dropdowns #}
    {{ form_row(form.campusName) }}
    {{ form_row(form.buildingName) }}
    {{ form_row(form.roomName) }}
  </div>
  <div class="location-off-campus">
    {{ form_row(form.searchVenue) }}
  </div>
</div>
<div class="time-select">
  {{ form_row(form.startTime)}}
  {{ form_row(form.endTime)}}
</div>

<div class="button-container">
    <button class="button button--grey" type="submit">Search</button>
</div>
{{ form_end(form) }}

{% if assignments is not null and assignments is not empty and assignments.errorMessage is not defined %}
<form action="{{ path('service_export_do')}}" method="post">
  <table class="table--dashboard">
    <thead>
      <tr>
        <th>Task Description</th>
        <th>Staff Name</th>
        <th>Username</th>
        <th>Date</th>
        <th>Start Time</th>
        <th>End Time</th>
        <th>Hours</th>
        <th>Unit Cost</th>
      </tr>
    </thead>
    <tbody>
      {% for assignment in assignments %}
        <tr>
          <td><input type="hidden" name="serviceIDs[]" value="{{ assignment.id }}"></input>{{ assignment.task.description ?? 'n/a'}}</td>
          <td>{{ assignment.staff.lastname }}, {{ assignment.staff.firstname }}</td>
          <td> {{ assignment.staff.username }}</td>
          <td> {{ assignment.date|date("m/d/Y") }}</td>
          <td> {{ assignment.startTime|date("H:i:s") }}</td>
          <td> {{ assignment.endTime|date("H:i:s") }}</td>
          <td> {% for billingServiceItem in assignment.billingServiceItems %}
            {% if billingServiceItem.hours %}{% endif %}
            {{ billingServiceItem.hours }}
            {% else %}
              0
          {% endfor %}</td>
          <td> {% for billingServiceItem in assignment.billingServiceItems %}
            ${{ billingServiceItem.unitCost }}
          {% endfor %}</td>
        </tr>
      {% endfor %}
    </tbody>
  </table>
  <div class="button-container">
        <button class="button button--grey" name="export_all" type="submit">Export</button>
    </div>
</form>
{% elseif (assignments.errorMessage is defined)%}
  <h1>
    {{ assignments['errorMessage'] }}
  </h1>
{% endif %}{% endblock %}

(在这里,除了一种隐藏的输入类型之外,我忽略了以前为便于阅读而使用的所有输入类型)

我尝试了一些基于google搜索的东西(可能不是很好)

  1. 通过路由参数将数据传递到路由:路径参数的符号文档
  2. 在控制器中为数据创建一个私有变量,然后通过getter/setters访问它(是的,哑巴,我非常绝望)
  3. 尝试将导出按钮移动到与查询相同的表单中,并有条件地呈现它,然后向新的控制器路由添加href路径。
  4. 试图重新呈现表单,并使用相同的信息重新查询表单,然后将该数据转换为CSV。

我觉得我缺少一种非常简单的方法来在这里添加一个函数和/或路由,它使用用户用来查询和显示表的相同数据来创建一个csv。谢谢您的任何建议,如果这是很难理解的。

编辑:我最后做的是,在尝试了这些有用的建议之后,我发现在我的经验级别上,最简单的解决方案就是通过隐藏的input标记从查询中获取每个条目的ID。在我的控制器中,我创建了一个创建cvs的新路径,并使用$request->request->get('IdsFromEntries');获取In,然后在我的存储库中创建了一个新函数,它连接了我想要的与这些条目相关的字段所需的相关表。然后,我能够循环遍历这些查询数据,并将每个字段分配给cvs的一个列。为此,我能够保持前端不变,让用户只需单击搜索结果表按钮上的导出按钮就可以下载包含表数据的cvs。

EN

回答 2

Stack Overflow用户

发布于 2022-05-06 06:35:30

最简单的方法是在当前路由中添加一些可选的后缀,比如.csv。如果设置了它,那么获取所需的所有数据,并使用它创建CSV。

这样您就不需要创建新的控制器并提取复制的代码..。只需添加一个条件,在一种情况下返回呈现的页面,在另一种情况下返回CSV文件。

票数 0
EN

Stack Overflow用户

发布于 2022-05-06 17:02:32

我还有一个类似的问题要解决。我创造了两条路线。

其中一条路径显示了用户界面,包括表单、数据表和导出按钮。第二条路线被用来导出数据。这两条路线都连接到相同的表格上。由于用户选择可以公开共享,而不会泄露任何秘密,因此附加表单使用http谓词"GET“有效地将用户选择作为查询字符串参数附加到视图路由。在呈现导出按钮时,我将导出路由路径与查询字符串连接起来。

通过这种方式,我能够将这两个操作分成两条路线,并在它们之间共享内容,而不需要cookie或js。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72135424

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档