mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-08-22 15:43:51 +00:00
Squashed commit of the following:
commit e1236655e1514fd207818aeb57789eca0d949453
Merge: c0b349b fb15bd3
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Tue Jun 30 09:51:35 2015 +0200
Merge remote-tracking branch 'origin/master' into add_acl
In order to prepare merging of add_acl to master
Conflicts:
composer.json
commit c0b349bb5f31fe79c84f82d4dd6658c9e90ef728
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Tue Jun 30 00:40:13 2015 +0200
fix infos in composer.json
[ci skip]
commit 106bbf56a5060efd2a89232f278692eeb57e3092
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Mon Jun 29 22:58:48 2015 +0200
add username and password to client auth options
[ci skip]
commit c4990972711850616aa1426394884223d63b504f
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Mon Jun 29 22:22:20 2015 +0200
fix quoting in timelinebuilder
commit 1db7cbea5a0fb0e8d396f8c9d8dc01240b47e96f
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Thu Jun 25 22:43:46 2015 +0200
remove data_class to allow edit form
commit 7c999279310b5e2b9ecef8a9b5001c71910a822d
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Wed Jun 24 22:33:42 2015 +0200
fix doc for AppendScopeChoiceTypeTrait
commit 839d4c43bf6f463e705b47d5dbc0cdf7853db0b6
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Wed Jun 24 22:30:13 2015 +0200
refactor: move scope field to a trait
Example usage :
```
class AbcType extends Symfony\Component\Form\AbstractType
{
use AppendScopeChoiceTypeTrait;
protected $authorizationHelper;
protected $translatableStringHelper;
protected $user;
public function __construct(AuthorizationHelper $helper,
TokenStorageInterface $tokenStorage,
TranslatableStringHelper $translatableStringHelper)
{
$this->authorizationHelper = $helper;
$this->user = $tokenStorage->getToken()->getUser();
$this->translatableStringHelper = $translatableStringHelper;
}
public function buildForm(FormBuilder $builder, array $options)
{
// ... add your form there
// append the scope using FormEvents: PRE_SET_DATA
$this->appendScopeChoices($builder, $options['role'],
$options['center'], $this->user,
$this->authorizationHelper,
$this->translatableStringHelper);
}
public function configureOptions(OptionsResolver $resolver)
{
// ... add your options
// add an option 'role' and 'center' to your form (optional)
$this->appendScopeChoicesOptions($resolver);
}
}
```
[ci skip]
commit a1ac530f343146eee12b5982e4e6fceb6dc1da66
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Wed Jun 24 00:24:30 2015 +0200
remove unused statements
commit 74f0a4ce5dfdfa4f8fc39ce1cfe726d945e9bdec
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Wed Jun 24 00:09:47 2015 +0200
add missing unused statement
commit b3a49f2de8758b51c57af6ff0437f30b2fdef72e
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Tue Jun 23 23:58:57 2015 +0200
remove ScopeType strategy and fix autorization helper
commit aaa70b5eeae76b0950110f51b8274e08bef10576
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Tue Jun 23 21:35:06 2015 +0200
create scope type
commit 8f5b2b23c9448b8c8e752e46bdd7f9f721054a98
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Fri Jun 19 18:13:54 2015 +0200
add getREachableCenter method + test on Autho.Helper
commit ab2ccb8c287f9aef12912ea9b7f5dc4998209d77
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Fri Jun 19 17:27:22 2015 +0200
remove debug information [ci skip]
commit 9d481c07966a5d769d1418bb366bd6b1ea9d4f76
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Fri Jun 19 17:24:57 2015 +0200
fix role hierarchy
Now we test effectively that a user has access, not that a role may grant access
commit f4b17d0ae398fd6c26d4907377761e9f15d36a90
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Thu Jun 18 02:08:55 2015 +0200
fix trait conflicts
traits does not share the same instance of prophet any more
commit baac8ce97ba0acd4c4fe6f03278f7a0d30da28ad
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Thu Jun 18 01:56:39 2015 +0200
try to fix trait error in zend strict mode (used by travis)
commit 7b9fa4b14bde72c7036a29c03a0c6cca3c7e6c74
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Thu Jun 18 01:24:09 2015 +0200
fix error on trait hierarchy (should be)
commit f8b3451089f7017653bf8d280b640356df6a1841
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Thu Jun 18 01:03:04 2015 +0200
add userHasAccess method to AuthorizationHelper
This method may be used in voter to check access.
It supports both hasCenterInterface and HasScopeInterface and check all
required permission.
commit 9ad9f624a0aa73ca2e639fd68fe4d5559da2bbd7
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Thu Jun 18 01:01:16 2015 +0200
add utilities to generate prophesized entities
entities
- User (with permissions)
- Center
- Scope
may be generated by trait/methods
This ease test writing about acl
commit 16008b9e64bb7f551319abea494db1c1c5a12b82
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Fri Jun 12 22:42:46 2015 +0200
add test to CenterType
commit 55e2c64aba9714caf09df8dbc9595980826b296a
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Fri Jun 12 20:50:05 2015 +0200
first implementation of test on CenterType
[TRANSFER][ci skip]
commit 548fb24927cc470794a51d81f1ba6af52237363f
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Wed Jun 10 21:15:52 2015 +0200
add center type
the center type is hidden if the current user can reach only one center,
and is `entity` type if the user can reach multiple centers
commit 024e3ef8d969d25560406864d86768a260ef4402
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Mon Jun 8 00:28:51 2015 +0200
add first impl of Access Model
- first classes and interfaces
- authorizationHelper + test
- rewrite loadUser to have multi-center
commit bc5ae70c83c39a0a738e78313e33020fc284f456
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Sun Jun 7 22:11:13 2015 +0200
make deprecations message not fail tests
commit ab9308ed62e45171e9d355ec033b0862b9274e07
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Sat Jun 6 10:19:19 2015 +0200
introducting phpunit-bridge to handle deprecation warnings
commit 5b7a43c4d058af58578c30120670c5be5b11cfd8
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Fri Jun 5 12:49:23 2015 +0200
fix options resolver deprecation
commit a5b4e5743f790c16dfd04e5068c5ecca9c2b1583
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Fri Jun 5 12:36:17 2015 +0200
remove warning about deprecation in phpunit
commit 56621767936df1ea1293c49ae06380d7735c8d6c
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Fri Jun 5 11:59:50 2015 +0200
fix pattern deprecation in routing/test
pattern=> path
commit 17d40fc5294b245d7377572a8c918abab2484985
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Fri Jun 5 11:40:59 2015 +0200
fix deprecation of pattern in routing
pattern => path in routing
commit 6a33752c6439bd9dbc707df010ce1d8765eeb5fe
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Fri Jun 5 11:21:18 2015 +0200
fix twig.form.resources deprecation
the new key is twig.form_themes
commit adf03eb819f2d443f87d7b744f59a5adf51d2b31
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date: Fri Jun 5 10:56:51 2015 +0200
switch to symfony 2.7 [ci-skip]
263 lines
8.4 KiB
PHP
263 lines
8.4 KiB
PHP
<?php
|
|
|
|
/*
|
|
* Copyright (C) 2015 Champs-Libres Coopérative <info@champs-libres.coop>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
namespace Chill\MainBundle\Timeline;
|
|
|
|
use Doctrine\ORM\Query\ResultSetMapping;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
|
|
|
/**
|
|
* Build timeline
|
|
*
|
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
|
*/
|
|
class TimelineBuilder implements ContainerAwareInterface
|
|
{
|
|
|
|
use \Symfony\Component\DependencyInjection\ContainerAwareTrait;
|
|
|
|
/**
|
|
*
|
|
* @var \Doctrine\ORM\EntityManagerInterface
|
|
*/
|
|
private $em;
|
|
|
|
public function __construct(EntityManagerInterface $em)
|
|
{
|
|
$this->em = $em;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @var string references to providers services
|
|
*/
|
|
private $providers = array();
|
|
|
|
/**
|
|
* return an HTML string with timeline
|
|
*
|
|
* This function must be called from controller
|
|
*
|
|
* @example https://redmine.champs-libres.coop/projects/chillperson/repository/revisions/bd2e1b1808f73e39532e9538413025df5487cad0/entry/Controller/TimelinePersonController.php#L47 the implementation in person bundle
|
|
*
|
|
* @param string $context
|
|
* @param array $args arguments defined by the bundle which create the context
|
|
* @param int $page first page = 0
|
|
* @param int $number number of items by page
|
|
* @return string an HTML representation, must be included using `|raw` filter
|
|
*/
|
|
public function getTimelineHTML($context, array $args, $page = 0, $number = 20)
|
|
{
|
|
$query = $this->buildUnionQuery($context, $args, $page, $number);
|
|
$fetched = $this->runQuery($query);
|
|
$entitiesByKey = $this->getEntities($fetched, $context);
|
|
|
|
return $this->render($fetched, $entitiesByKey, $context, $args);
|
|
}
|
|
|
|
/**
|
|
* add a provider id
|
|
*
|
|
* @internal This function is called by the TimelineCompilerClass
|
|
*
|
|
* @param string $context the context of the service
|
|
* @param string $id the
|
|
*/
|
|
public function addProvider($context, $id)
|
|
{
|
|
$this->providers[$context][] = $id;
|
|
}
|
|
|
|
/**
|
|
* Get providers by context
|
|
*
|
|
* @param string $context
|
|
* @return TimelineProviderInterface[]
|
|
*/
|
|
public function getProvidersByContext($context)
|
|
{
|
|
$providers = array();
|
|
|
|
foreach($this->providers[$context] as $providerId) {
|
|
$providers[] = $this->container->get($providerId);
|
|
}
|
|
|
|
return $providers;
|
|
}
|
|
|
|
/**
|
|
* build the UNION query with all providers
|
|
*
|
|
* @uses self::buildSelectQuery to build individual SELECT queries
|
|
*
|
|
* @param string $context
|
|
* @param mixed $args
|
|
* @param int $page
|
|
* @param int $number
|
|
* @return string
|
|
* @throws \LogicException if no builder have been defined for this context
|
|
*/
|
|
private function buildUnionQuery($context, array $args, $page, $number)
|
|
{
|
|
//throw an exception if no provider have been defined for this context
|
|
if (!array_key_exists($context, $this->providers)) {
|
|
throw new \LogicException(sprintf('No builders have been defined for "%s"'
|
|
. ' context', $context));
|
|
}
|
|
|
|
//append SELECT queries with UNION keyword between them
|
|
$union = '';
|
|
foreach($this->getProvidersByContext($context) as $provider) {
|
|
$select = $this->buildSelectQuery($provider, $context, $args);
|
|
$append = ($union === '') ? $select : ' UNION '.$select;
|
|
$union .= $append;
|
|
}
|
|
//add ORDER BY clause and LIMIT
|
|
$union .= sprintf(' ORDER BY date LIMIT %d OFFSET %d',
|
|
$number, $page * $number);
|
|
|
|
return $union;
|
|
}
|
|
|
|
/**
|
|
* return the SQL SELECT query as a string,
|
|
*
|
|
* @uses TimelineProfiderInterface::fetchQuery use the fetchQuery function
|
|
* @param \Chill\MainBundle\Timeline\TimelineProviderInterface $provider
|
|
* @param string $context
|
|
* @param mixed[] $args
|
|
* @return string
|
|
*/
|
|
private function buildSelectQuery(TimelineProviderInterface $provider, $context, array $args)
|
|
{
|
|
$data = $provider->fetchQuery($context, $args);
|
|
|
|
return sprintf(
|
|
'SELECT %s AS id, '
|
|
. '%s AS "date", '
|
|
. "'%s' AS type "
|
|
. 'FROM %s '
|
|
. 'WHERE %s',
|
|
$data['id'],
|
|
$data['date'],
|
|
$data['type'],
|
|
$data['FROM'],
|
|
$data['WHERE']);
|
|
}
|
|
|
|
/**
|
|
* run the UNION query and return result as an array
|
|
*
|
|
* @param string $query
|
|
* @return array
|
|
*/
|
|
private function runQuery($query)
|
|
{
|
|
$resultSetMapping = (new ResultSetMapping())
|
|
->addScalarResult('id', 'id')
|
|
->addScalarResult('type', 'type')
|
|
->addScalarResult('date', 'date');
|
|
|
|
return $this->em->createNativeQuery($query, $resultSetMapping)
|
|
->getArrayResult();
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param array $queriedIds
|
|
* @param string $context
|
|
* @return array with the form array($type => [$entity, $entity, $entity])
|
|
*/
|
|
private function getEntities(array $queriedIds, $context)
|
|
{
|
|
//gather entities by type to pass all id with same type to the TimelineProvider.
|
|
$idsByType = array();
|
|
|
|
foreach($queriedIds as $result) {
|
|
$idsByType[$result['type']][] = $result['id'];
|
|
}
|
|
|
|
//fetch entities from providers
|
|
$entitiesByType = array();
|
|
foreach ($idsByType as $type => $ids) {
|
|
//iterate providers for current context
|
|
foreach($this->getProvidersByContext($context) as $provider) {
|
|
if ($provider->supportsType($type)) {
|
|
$entitiesByType[$type] = $provider->getEntities($ids);
|
|
break; //we assume that providers have unique keys => we break the loop
|
|
}
|
|
}
|
|
}
|
|
|
|
return $entitiesByType;
|
|
}
|
|
|
|
/**
|
|
* render the timeline as HTML
|
|
*
|
|
* @param array $fetched
|
|
* @param array $entitiesByType
|
|
* @param string $context
|
|
* @param mixed[] $args
|
|
* @return string the HTML representation of the timeline
|
|
*/
|
|
private function render(array $fetched, array $entitiesByType, $context, array $args)
|
|
{
|
|
//add results to a pretty array
|
|
$timelineEntries = array();
|
|
foreach ($fetched as $result) {
|
|
$data = $this->getTemplateData(
|
|
$result['type'],
|
|
$entitiesByType[$result['type']][$result['id']], //the entity
|
|
$context,
|
|
$args);
|
|
$timelineEntry['date'] = new \DateTime($result['date']);
|
|
$timelineEntry['template'] = $data['template'];
|
|
$timelineEntry['template_data'] = $data['template_data'];
|
|
|
|
$timelineEntries[] = $timelineEntry;
|
|
}
|
|
|
|
return $this->container->get('templating')
|
|
->render('ChillMainBundle:Timeline:index.html.twig', array(
|
|
'results' => $timelineEntries
|
|
));
|
|
|
|
}
|
|
|
|
/**
|
|
* get the template data from the provider for the given entity, by type.
|
|
*
|
|
* @param string $type
|
|
* @param mixed $entity
|
|
* @param string $context
|
|
* @param mixed[] $args
|
|
* @return array the template data fetched from the provider
|
|
*/
|
|
private function getTemplateData($type, $entity, $context, array $args)
|
|
{
|
|
foreach($this->getProvidersByContext($context) as $provider) {
|
|
if ($provider->supportsType($type)) {
|
|
return $provider->getEntityTemplate($entity, $context, $args);
|
|
}
|
|
}
|
|
}
|
|
}
|