diff --git a/lib/Alchemy/Phrasea/Controller/Thesaurus/Xmlhttp.php b/lib/Alchemy/Phrasea/Controller/Thesaurus/Xmlhttp.php index 89c9bcdf12..209c3c16fd 100644 --- a/lib/Alchemy/Phrasea/Controller/Thesaurus/Xmlhttp.php +++ b/lib/Alchemy/Phrasea/Controller/Thesaurus/Xmlhttp.php @@ -358,82 +358,45 @@ class Xmlhttp implements ControllerProviderInterface public function EditingPresetsJson(Application $app, Request $request) { - $usr_id = $app['authentication']->getUser()->getId(); - $ret = ['parm' => [ 'act' => $request->get('act'), 'sbas' => $request->get('sbas'), 'presetid' => $request->get('presetid'), 'title' => $request->get('title'), - 'f' => $request->get('f'), + 'fields' => $request->get('fields'), 'debug' => $request->get('debug'), ]]; switch ($request->get('act')) { case 'DELETE': - $sql = 'DELETE FROM edit_presets - WHERE edit_preset_id = :editpresetid - AND usr_id = :usr_id'; + if (null === $preset = $app['repo.presets']->find($id = $request->get('presetid'))) { + $app->abort(404, sprintf("Preset with id '%' could not be found", $id)); + } + $app['manipulator.preset']->delete($preset); - $params = [ - ':editpresetid' => $request->get('presetid'), - ':usr_id' => $usr_id - ]; - - $stmt = $app['phraseanet.appbox']->get_connection()->prepare($sql); - $stmt->execute($params); - $stmt->closeCursor(); - - $ret['html'] = $this->getPresetHTMLList($app, $request->get('sbas'), $usr_id); + $ret['html'] = $this->getPresetHTMLList($app, $request->get('sbas'), $app['authentication']->getUser()->getId()); break; case 'SAVE': - $dom = new \DOMDocument('1.0', 'UTF-8'); - $dom->standalone = true; - $dom->preserveWhiteSpace = false; - $dom->formatOutput = true; + $app['manipulator.preset']->create( + $app['authentication']->getUser(), + $request->get('sbas'), + $request->get('title'), + $request->get('fields') + ); - $xml = '' . $request->get('f') . ''; - $dom->loadXML($xml); - - $sql = 'INSERT INTO edit_presets - (creation_date, sbas_id, usr_id, title, xml) - VALUES - (NOW(), :sbas_id, :usr_id, :title, :presets)'; - - $params = [ - ':sbas_id' => $request->get('sbas'), - ':usr_id' => $usr_id, - ':title' => $request->get('title'), - ':presets' => $dom->saveXML(), - ]; - - $stmt = $app['phraseanet.appbox']->get_connection()->prepare($sql); - $stmt->execute($params); - $stmt->closeCursor(); - - $ret['html'] = $this->getPresetHTMLList($app, $request->get('sbas'), $usr_id); + $ret['html'] = $this->getPresetHTMLList($app, $request->get('sbas'), $app['authentication']->getUser()->getId()); break; case 'LIST': - $ret['html'] = $this->getPresetHTMLList($app, $request->get('sbas'), $usr_id); + $ret['html'] = $this->getPresetHTMLList($app, $request->get('sbas'), $app['authentication']->getUser()->getId()); break; case "LOAD": - $sql = 'SELECT edit_preset_id, creation_date, title, xml - FROM edit_presets - WHERE edit_preset_id = :edit_preset_id'; - - $stmt = $app['phraseanet.appbox']->get_connection()->prepare($sql); - $stmt->execute([':edit_preset_id' => $request->get('presetid')]); - $row = $stmt->fetch(\PDO::FETCH_ASSOC); - $stmt->closeCursor(); + if (null === $preset = $app['repo.presets']->find($id = $request->get('presetid'))) { + $app->abort(404, sprintf("Preset with id '%' could not be found", $id)); + } $fields = []; - if ($row && ($sx = @simplexml_load_string($row['xml']))) { - foreach ($sx->fields->children() as $fn => $fv) { - if (!array_key_exists($fn, $fields)) { - $fields[$fn] = []; - } - $fields[$fn][] = trim($fv); - } + foreach ($preset->getData() as $field) { + $fields[$field['name']][] = $field['value']; } $ret['fields'] = $fields; @@ -443,45 +406,21 @@ class Xmlhttp implements ControllerProviderInterface return $app->json($ret); } - private function getPresetHTMLList(Application $app, $sbas_id, $usr_id) + private function getPresetHTMLList(Application $app, $sbasId, User $user) { - $conn = $app['phraseanet.appbox']->get_connection(); + $data = []; + foreach ($app['repo.presets']->findBy(['user' => $user, 'sbasId' => $sbasId], ['creadted' => 'asc']) as $preset) { + $presetData = $fields = []; + array_walk($preset->getData(), function($field) use ($fields) { + $fields[$field['name']][] = $field['value']; + }); + $presetData['id'] = $preset->getId(); + $presetData['title'] = $preset->getTilte(); + $presetData['fields'] = $fields; - $sql = 'SELECT edit_preset_id, creation_date, title, xml - FROM edit_presets - WHERE usr_id = :usr_id AND sbas_id = :sbas_id - ORDER BY creation_date ASC'; - - $stmt = $conn->prepare($sql); - $stmt->execute([ - ':sbas_id' => $sbas_id, - ':usr_id' => $usr_id, - ]); - $rs = $stmt->fetchAll(\PDO::FETCH_ASSOC); - $stmt->closeCursor(); - - $presets = []; - foreach ($rs as $row) { - $preset = []; - if (!($sx = @simplexml_load_string($row['xml']))) { - continue; - } - $fields = []; - foreach ($sx->fields->children() as $fn => $fv) { - if (!array_key_exists($fn, $fields)) { - $t_desc[$fn] = trim($fv); - } else { - $t_desc[$fn] .= ' ; ' . trim($fv); - } - } - $preset['fields'] = $fields; - $preset['title'] = $row['title']; - $preset['id'] = $row['edit_preset_id']; - - $presets[] = $preset; + $data[] = $presetData; } - - return $app['twig']->render('thesaurus/presets.html.twig', ['presets' => $presets]); + return $app['twig']->render('thesaurus/presets.html.twig', ['presets' => $data]); } public function GetSynonymsXml(Application $app, Request $request) diff --git a/lib/Alchemy/Phrasea/Core/Provider/ManipulatorServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/ManipulatorServiceProvider.php index 2ded0578b5..ef34de65c4 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/ManipulatorServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/ManipulatorServiceProvider.php @@ -12,6 +12,7 @@ namespace Alchemy\Phrasea\Core\Provider; use Alchemy\Phrasea\Model\Manipulator\ACLManipulator; +use Alchemy\Phrasea\Model\Manipulator\PresetManipulator; use Alchemy\Phrasea\Model\Manipulator\RegistrationManipulator; use Alchemy\Phrasea\Model\Manipulator\TaskManipulator; use Alchemy\Phrasea\Model\Manipulator\TokenManipulator; @@ -36,6 +37,10 @@ class ManipulatorServiceProvider implements ServiceProviderInterface return new TokenManipulator($app['EM'], $app['random.medium'], $app['repo.tokens']); }); + $app['manipulator.preset'] = $app->share(function ($app) { + return new PresetManipulator($app['EM'], $app['repo.presets']); + }); + $app['manipulator.acl'] = $app->share(function ($app) { return new ACLManipulator($app['acl'], $app['phraseanet.appbox']); }); diff --git a/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php index 02768a6400..66124296a6 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php @@ -94,6 +94,9 @@ class RepositoriesServiceProvider implements ServiceProviderInterface $app['repo.tokens'] = $app->share(function ($app) { return $app['EM']->getRepository('Phraseanet:Token'); }); + $app['repo.presets'] = $app->share(function (PhraseaApplication $app) { + return $app['EM']->getRepository('Phraseanet:Preset'); + }); } public function boot(Application $app) diff --git a/lib/Alchemy/Phrasea/Model/Entities/Preset.php b/lib/Alchemy/Phrasea/Model/Entities/Preset.php new file mode 100644 index 0000000000..13de824621 --- /dev/null +++ b/lib/Alchemy/Phrasea/Model/Entities/Preset.php @@ -0,0 +1,166 @@ +id; + } + + /** + * @return User + */ + public function getUser() + { + return $this->user; + } + + /** + * @param User $user + * + * @return UserQuery + */ + public function setUser(User $user) + { + $this->user = $user; + + return $this; + } + + /** + * @return string + */ + public function getSbasId() + { + return $this->sbasId; + } + + /** + * @param $sbasId + * + * @return $this + */ + public function setSbasId($sbasId) + { + $this->sbasId = $sbasId; + + return $this; + } + + /** + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * @param $title + * + * @return $this + */ + public function setTitle($title) + { + $this->title = $title; + + return $this; + } + + /** + * @param array $data + * + * @return $this + */ + public function setData(array $data) + { + $this->data = json_encode($data); + + return $this; + } + + /** + * @return array + */ + public function getData() + { + return (array) json_decode($this->data, true); + + return $this; + } + + /** + * @return \DateTime + */ + public function getCreated() + { + return $this->created; + } + + /** + * @param \DateTime $created + * + * @return UserQuery + */ + public function setCreated(\DateTime $created) + { + $this->created = $created; + + return $this; + } +} diff --git a/lib/Alchemy/Phrasea/Model/Manipulator/PresetManipulator.php b/lib/Alchemy/Phrasea/Model/Manipulator/PresetManipulator.php new file mode 100644 index 0000000000..1c61a1eb53 --- /dev/null +++ b/lib/Alchemy/Phrasea/Model/Manipulator/PresetManipulator.php @@ -0,0 +1,54 @@ +om = $om; + $this->repository = $repo; + } + + public function create(User $user, $sbasId, $title, array $data) + { + $preset = new Preset(); + + $preset->setUser($user); + $preset->setTitle($title); + $preset->setData($data); + $preset->setSbasId($sbasId); + + $this->om->persist($preset); + $this->om->flush(); + + return $preset; + } + + public function delete(Preset $preset) + { + $this->om->remove($preset); + $this->om->flush(); + } +} diff --git a/lib/Alchemy/Phrasea/Model/Repositories/PresetRepository.php b/lib/Alchemy/Phrasea/Model/Repositories/PresetRepository.php new file mode 100644 index 0000000000..c81b284a6e --- /dev/null +++ b/lib/Alchemy/Phrasea/Model/Repositories/PresetRepository.php @@ -0,0 +1,18 @@ +release; + } + + /** + * {@inheritdoc} + */ + public function require_all_upgrades() + { + return false; + } + + /** + * {@inheritdoc} + */ + public function concern() + { + return $this->concern; + } + + /** + * {@inheritdoc} + */ + public function getDoctrineMigrations() + { + return []; + } + + /** + * {@inheritdoc} + */ + public function apply(base $appbox, Application $app) + { + $sql = ' SELECT edit_preset_id, creation_date, title, xml + FROM edit_presets'; + + $em = $app['EM']; + $n = 0; + $em->getEventManager()->removeEventSubscriber(new TimestampableListener()); + foreach ($app['phraseanet.appbox']->get_connection()->fetchAll($sql) as $row) { + if (null === $user = $this->loadUser($app['EM'], $row['usr_id'])) { + continue; + } + $preset = new Preset(); + $preset->setUser($user); + $preset->setSbasId($row['sbas_id']); + $preset->setTitle($row['title']); + $fields = []; + if (false !== ($sx = @simplexml_load_string($row['xml']))) { + foreach ($sx->fields->children() as $name => $value) { + $fields[] = ['name' => $name, 'value' => $value]; + } + } + $preset->setData($fields); + + $em->persist($preset); + $n++; + + if ($n % 20 === 0) { + $em->flush(); + $em->clear(); + } + } + + $em->flush(); + $em->clear(); + + $em->getEventManager()->addEventSubscriber(new TimestampableListener()); + + return true; + } +} diff --git a/templates/web/thesaurus/presets.html.twig b/templates/web/thesaurus/presets.html.twig index ec490cd359..d2a8f83ba5 100644 --- a/templates/web/thesaurus/presets.html.twig +++ b/templates/web/thesaurus/presets.html.twig @@ -6,8 +6,8 @@ {{ 'boutton::supprimer'| trans }}
- {% for name, field in preset['fields'] %} -

{{ name }} : {{ field }}

+ {% for name, fields in preset['fields'] %} +

{{ name }} : {{ fields|join(';') }}

{% endfor %}
diff --git a/tests/Alchemy/Tests/Phrasea/Core/Provider/RepositoriesServiceProviderTest.php b/tests/Alchemy/Tests/Phrasea/Core/Provider/RepositoriesServiceProviderTest.php index 5b8cd3de36..65eb629cd2 100644 --- a/tests/Alchemy/Tests/Phrasea/Core/Provider/RepositoriesServiceProviderTest.php +++ b/tests/Alchemy/Tests/Phrasea/Core/Provider/RepositoriesServiceProviderTest.php @@ -32,6 +32,7 @@ class RepositoriesServiceProviderTest extends ServiceProviderTestCase ['Alchemy\Phrasea\Core\Provider\RepositoriesServiceProvider', 'repo.ftp-exports', 'Alchemy\Phrasea\Model\Repositories\FtpExportRepository'], ['Alchemy\Phrasea\Core\Provider\RepositoriesServiceProvider', 'repo.user-queries', 'Alchemy\Phrasea\Model\Repositories\UserQueryRepository'], ['Alchemy\Phrasea\Core\Provider\RepositoriesServiceProvider', 'repo.tokens', 'Alchemy\Phrasea\Model\Repositories\TokenRepository'], + ['Alchemy\Phrasea\Core\Provider\RepositoriesServiceProvider', 'repo.presets', 'Alchemy\Phrasea\Model\Repositories\PresetRepository'], ]; } } diff --git a/tests/Alchemy/Tests/Phrasea/Model/Manipulator/PresetManipulatorTest.php b/tests/Alchemy/Tests/Phrasea/Model/Manipulator/PresetManipulatorTest.php new file mode 100644 index 0000000000..4a10cedbac --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Model/Manipulator/PresetManipulatorTest.php @@ -0,0 +1,34 @@ +assertCount(0, self::$DI['app']['repo.presets']->findAll()); + $fields = [ + ['name' => 'titi', 'value' => 'titi_value'], ['name' => 'tutu', 'value' => 'tutu_value'], + ['name' => 'titi', 'value' => 'titi2_value'], ['name' => 'tutu', 'value' => 'tutu2_value'], + ]; + $title = 'title'; + $preset = $manipulator->create(self::$DI['user'], self::$DI['collection']->get_sbas_id(), $title, $fields); + $this->assertEquals($title, $preset->getTitle()); + $this->assertEquals($fields, $preset->getData()); + $this->assertEquals(self::$DI['collection']->get_sbas_id(), $preset->getSbasId()); + $this->assertEquals(self::$DI['user']->getid(), $preset->getUser()->getId()); + $this->assertCount(1, self::$DI['app']['repo.presets']->findAll()); + } + + public function testDelete() + { + $manipulator = new PresetManipulator(self::$DI['app']['EM'], self::$DI['app']['repo.presets']); + $preset = $manipulator->create(self::$DI['user'], self::$DI['collection']->get_sbas_id(), 'title', []); + $countBefore = count(self::$DI['app']['repo.presets']->findAll()); + $manipulator->delete($preset); + $this->assertGreaterThan(count(self::$DI['app']['repo.presets']->findAll()), $countBefore); + } +} diff --git a/tmp/doctrine-proxies/__CG__AlchemyPhraseaModelEntitiesPreset.php b/tmp/doctrine-proxies/__CG__AlchemyPhraseaModelEntitiesPreset.php new file mode 100644 index 0000000000..7a639b432f --- /dev/null +++ b/tmp/doctrine-proxies/__CG__AlchemyPhraseaModelEntitiesPreset.php @@ -0,0 +1,301 @@ +__initializer__ = $initializer; + $this->__cloner__ = $cloner; + } + + + + + + + + /** + * + * @return array + */ + public function __sleep() + { + if ($this->__isInitialized__) { + return array('__isInitialized__', 'id', 'user', 'sbasId', 'title', 'data', 'created'); + } + + return array('__isInitialized__', 'id', 'user', 'sbasId', 'title', 'data', 'created'); + } + + /** + * + */ + public function __wakeup() + { + if ( ! $this->__isInitialized__) { + $this->__initializer__ = function (Preset $proxy) { + $proxy->__setInitializer(null); + $proxy->__setCloner(null); + + $existingProperties = get_object_vars($proxy); + + foreach ($proxy->__getLazyProperties() as $property => $defaultValue) { + if ( ! array_key_exists($property, $existingProperties)) { + $proxy->$property = $defaultValue; + } + } + }; + + } + } + + /** + * + */ + public function __clone() + { + $this->__cloner__ && $this->__cloner__->__invoke($this, '__clone', array()); + } + + /** + * Forces initialization of the proxy + */ + public function __load() + { + $this->__initializer__ && $this->__initializer__->__invoke($this, '__load', array()); + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + */ + public function __isInitialized() + { + return $this->__isInitialized__; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + */ + public function __setInitialized($initialized) + { + $this->__isInitialized__ = $initialized; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + */ + public function __setInitializer(\Closure $initializer = null) + { + $this->__initializer__ = $initializer; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + */ + public function __getInitializer() + { + return $this->__initializer__; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + */ + public function __setCloner(\Closure $cloner = null) + { + $this->__cloner__ = $cloner; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific cloning logic + */ + public function __getCloner() + { + return $this->__cloner__; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + * @static + */ + public function __getLazyProperties() + { + return self::$lazyPropertiesDefaults; + } + + + /** + * {@inheritDoc} + */ + public function getId() + { + if ($this->__isInitialized__ === false) { + return (int) parent::getId(); + } + + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'getId', array()); + + return parent::getId(); + } + + /** + * {@inheritDoc} + */ + public function getUser() + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'getUser', array()); + + return parent::getUser(); + } + + /** + * {@inheritDoc} + */ + public function setUser(\Alchemy\Phrasea\Model\Entities\User $user) + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'setUser', array($user)); + + return parent::setUser($user); + } + + /** + * {@inheritDoc} + */ + public function getSbasId() + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'getSbasId', array()); + + return parent::getSbasId(); + } + + /** + * {@inheritDoc} + */ + public function setSbasId($sbasId) + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'setSbasId', array($sbasId)); + + return parent::setSbasId($sbasId); + } + + /** + * {@inheritDoc} + */ + public function getTitle() + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'getTitle', array()); + + return parent::getTitle(); + } + + /** + * {@inheritDoc} + */ + public function setTitle($title) + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'setTitle', array($title)); + + return parent::setTitle($title); + } + + /** + * {@inheritDoc} + */ + public function setData(array $data) + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'setData', array($data)); + + return parent::setData($data); + } + + /** + * {@inheritDoc} + */ + public function getData() + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'getData', array()); + + return parent::getData(); + } + + /** + * {@inheritDoc} + */ + public function getCreated() + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'getCreated', array()); + + return parent::getCreated(); + } + + /** + * {@inheritDoc} + */ + public function setCreated(\DateTime $created) + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'setCreated', array($created)); + + return parent::setCreated($created); + } + +} diff --git a/www/skins/prod/jquery.edit.js b/www/skins/prod/jquery.edit.js index 840c83c43c..a555c2b4b0 100644 --- a/www/skins/prod/jquery.edit.js +++ b/www/skins/prod/jquery.edit.js @@ -1823,30 +1823,23 @@ function startThisEditing(sbas_id, what, regbasprid, ssel) { "act": "SAVE", "sbas": p4.edit.sbas_id, "title": jtitle.val(), - "f": {} + "fields": [] }; - var f = {}; - var x = ""; - $(":checkbox", form).each( - function (idx, elem) { - if (elem.checked) { - var i = 0 | elem.value; - var f; - if (p4.edit.T_fields[i].multi) - f = p4.edit.T_fields[i]._value.split(";"); - else - f = [ p4.edit.T_fields[i]._value ]; - for (j in f) { - x += "<" + p4.edit.T_fields[i].name + ">" - + cleanTags(f[j]) - + ""; - } - } - } - ); - x += ""; - p["f"] = x; + $(":checkbox", form).each(function (idx, elem) { + var $el = $(elem); + if ($el.is(":checked")) { + var val = $el.val(); + var field = {name: p4.edit.T_fields[val].name}; + + if (p4.edit.T_fields[val].multi) { + field.value = $.map(p4.edit.T_fields[i]._value.split(";"), cleanTags); + } else { + field.value = $.map([p4.edit.T_fields[i]._value], cleanTags); + } + p.fields.push(field); + } + }); $.ajax({ type: 'POST',