Commit 49263da7 authored by Sebastian Castro's avatar Sebastian Castro

Element import: lot of improvements

parent 15abc316
......@@ -34,12 +34,12 @@
.bs-callout-warning { border-left-color: #f39c12; }
.btn i { margin-right: 6px; }
.btn i + i { margin-left: -4px; }
.btn i + i { margin-left: -4px; }
.markItUpHeader ul li {
padding-right: 5px;
padding-bottom: 5px;
}
}
.markItUpHeader ul .markItUpSeparator
{
......@@ -47,17 +47,17 @@
color: transparent;
border-right: 1px solid #b9b9b9;
margin: 0 15px 0 5px;
}
}
.markItUpEditor {
font-size: 15px;
padding: 10px;
font-family: 'Source Sans Pro','Helvetica Neue',Helvetica,Arial,sans-serif;
}
}
.markItUpButton4, .markItUpButton5, .markItUpButton6, .markItUpButton12 + .markItUpSeparator, .markItUpButton13, .markItUpButton14 { display: none; }
.box-body > .alert:last-child { margin-bottom: 0 }
.box-body > .alert:last-child { margin-bottom: 0 }
label[title]:hover {
cursor: help;
......@@ -69,7 +69,7 @@
margin-left: 5px;
}
.box-body .iframe-container { text-align: center; margin-top: -20px; }
.box-body .iframe-container-aside {
.box-body .iframe-container-aside {
float: left;
margin: -20px 20px 20px 0;
}
......@@ -80,14 +80,19 @@
.main-header .logo { width: auto; }
.main-header .logo label:hover { cursor: pointer; }
.main-header .navbar { flex: auto; margin-left: 0; }
pre {
font-size: 11px;
line-height: 13px;
}
</style>
{% endblock %}
{% block javascripts %}
{{ parent() }}
{{ parent() }}
{# CKEDITOR FORMATTER #}
<script src="//cdn.ckeditor.com/4.7.3/full/ckeditor.js"></script>
......@@ -95,7 +100,7 @@
<script src="{{ asset('bundles/sonataformatter/markitup/sets/markdown/set.js') }}" type="text/javascript"></script>
<script src="{{ asset('bundles/sonataformatter/markitup/sets/html/set.js') }}" type="text/javascript"></script>
<script src="{{ asset('bundles/sonataformatter/markitup/sets/textile/set.js') }}" type="text/javascript"></script>
<script>
// bootstrap-ckeditor-modal-fix.js
// hack to fix ckeditor/bootstrap compatiability bug when ckeditor appears in a bootstrap modal dialog
......@@ -105,13 +110,13 @@
modal_this = this;
console.log("enforce focus");
$(document).on('focusin.modal', function (e) {
if (modal_this.$element[0] !== e.target && !modal_this.$element.has(e.target).length
&& !$(e.target.parentNode).hasClass('cke_dialog_ui_input_select')
if (modal_this.$element[0] !== e.target && !modal_this.$element.has(e.target).length
&& !$(e.target.parentNode).hasClass('cke_dialog_ui_input_select')
&& !$(e.target.parentNode).hasClass('cke_dialog_ui_input_text')) {
modal_this.$element.focus()
}
})
};
};
// CONFIGURATION ADMIN, disable the whole feature box according to checkbox "feature active"
$(document).ready(function() {
......@@ -121,7 +126,7 @@
$('.gogo-feature').each(function() {
checkGoGoFeatureActivated(this);
});
$('.gogo-feature .sonata-ba-field.sonata-ba-field-inline-natural > .form-group:first-child .icheckbox_square-blue .iCheck-helper').click(function() {
$('.gogo-feature .sonata-ba-field.sonata-ba-field-inline-natural > .form-group:first-child .icheckbox_square-blue .iCheck-helper').click(function() {
var that = this;
setTimeout(function() { checkGoGoFeatureActivated($(that).closest('.gogo-feature'));  }, 10);
});
......@@ -133,13 +138,13 @@
$('.collaborative-moderation-box').css('opacity', opacity);
}
function checkGoGoFeatureActivated(object) {
console.log("feature", object);
function checkGoGoFeatureActivated(object) {
console.log("feature", object);
var featureActive = $(object).find('.sonata-ba-field.sonata-ba-field-inline-natural > .form-group:first-child .icheckbox_square-blue').hasClass('checked');
var opacity = featureActive ? '1' : '0.5';
$(object).css('opacity', opacity);
$(object).css('opacity', opacity);
}
// Helpers
var formBuilder;
var formBuilderInitialized = false;
......@@ -168,7 +173,7 @@
{{ newErrorsCount }} {{ newErrorsCount == 1 ? 'erreur' : 'erreurs' }}
</label>
{% endif %}
</a>
{% endspaceless %}
{% endblock %}
......@@ -185,19 +190,19 @@
<li><a href={{ path('biopen_element_add') }} target='_blank'>Formulaire</a></li>
<li><a href={{ path('biopen_partners') }} target='_blank'>Qui sommes nous</a></li>
</ul>
</div>
</div>
{% endblock %}
{% block side_bar_after_nav %}
{% block side_bar_after_nav %}
{# CUSTOM Menu #}
<ul class="sidebar-menu">
<li class="first treeview">
<a href="{{ path('biopen_bulk_actions_index') }}"><i class="fa fa-bullhorn"></i><span>Actions de masse</span></a>
<li class="first treeview">
<a href="{{ path('biopen_bulk_actions_index') }}"><i class="fa fa-bullhorn"></i><span>Actions de masse</span></a>
</li>
<li>
<a href="{{ path('biopen_core_help') }}"><i class="fa fa-question"></i><span>Aide</span></a>
</li>
{% if use_as_saas %}
{% if use_as_saas %}
<li>
{% if is_root_project() %}
<a href="{{ path('admin_biopen_saas_project_list') }}"><i class="fa fa-folder-open"></i><span>Projets</span></a>
......
......@@ -14,8 +14,8 @@ class ImportDynamicAdminController extends Controller
$object = $this->admin->getSubject();
$result = $this->get('biopen.element_import')->collectData($object);
$this->addFlash('sonata_flash_success', "Les données ont été chargées avec succès. Vous pouvez maintenant compléter les tables de correspondances, puis importer les données.");
$url = $this->admin->generateUrl('edit', ['id' => $object->getId()]) . "#tab_3";
$this->addFlash('sonata_flash_success', "Les données ont été chargées avec succès.</br>Voici le résultat obtenu pour le premier élément à importer :<pre>" . print_r($result, true) . '</pre>');
$url = $this->admin->generateUrl('edit', ['id' => $object->getId()]);
return $this->redirect($url);
}
......@@ -89,8 +89,16 @@ class ImportDynamicAdminController extends Controller
'SonataAdminBundle'
)
);
// redirect to edit mode
return $this->redirectTo($object);
if ($request->get('collect')) {
$url = $this->admin->generateUrl('collect', ['id' => $object->getId()]);
} else if ($request->get('import')) {
$url = $this->admin->generateUrl('refresh', ['id' => $object->getId()]);
} else {
$url = $this->admin->generateUrl('edit', ['id' => $object->getId()]);
}
return $this->redirect($url);
} catch (ModelManagerException $e) {
$this->handleModelManagerException($e);
$isFormValid = false;
......
......@@ -39,7 +39,7 @@ class OptionValue
{
$result = "{";
$result .= '"id":' . $this->optionId ;
if ($optionName) $result .= ', "name":' . $optionName;
if ($optionName) $result .= ', "name":' . json_encode($optionName);
$result .=', "description":' . json_encode($this->description);
$result .=', "index":' . $this->index;
$result .= "}";
......
......@@ -74,17 +74,6 @@ class ElementJsonGenerator
// OPTIONS VALUES (= TAXONOMY)
$sortedOptionsValues = $element->getSortedOptionsValues();
$optValuesLength = count($sortedOptionsValues);
// Options values ids
$baseJson .= ', "categoriesIds": [';
if ($sortedOptionsValues)
{
for ($i=0; $i < $optValuesLength; $i++) {
$baseJson .= $sortedOptionsValues[$i]->getOptionId() . ',';
}
}
$baseJson = rtrim($baseJson, ',');
$baseJson .= '],';
// option values names
$optionsString = '';
$optionsFullJson = [];
if ($sortedOptionsValues)
......@@ -97,7 +86,7 @@ class ElementJsonGenerator
}
}
$optionsString = rtrim($optionsString, ',');
$baseJson .= '"categories": [' . $optionsString . '],';
$baseJson .= ',"categories": [' . $optionsString . '],';
$element->setOptionsString($optionsString); // we also update optionsString attribute which is used in exporting from element admin list
// Options values with description
if (count($optionsFullJson)) $baseJson .= '"categoriesFull": [' . implode(",", $optionsFullJson) . '],';
......
......@@ -12,14 +12,16 @@
<th>Attribut d'origine</th>
<th style="width:20px"></th>
<th>à transformer en</th>
<th style="width:20px"></th>
</tr>
</thead>
<tbody class="table-striped">
{% for originName, mappedName in mapping %}
<tr>
<td class="original">{{originName}}</td>
<td><i class="arrow-icon fa fa-arrow-circle-right"></i></td>
<td><i class="arrow-icon fa fa-arrow-circle-right" title="Utiliser le nom d'origine"></i></td>
<td class="mapped"><input type="text" name="ontology[{{originName}}]" class="form-control property-selector" value={{mappedName}} /></td>
<td><i class="clear-icon fa fa-ban" title="Ne pas importer ce champ"></i></td>
</tr>
{% endfor %}
</tbody>
......@@ -29,7 +31,7 @@
<style>
.arrow-icon { font-size: 18px; }
.arrow-icon:hover { cursor: pointer; }
.arrow-icon:hover, .clear-icon:hover { cursor: pointer; }
td { vertical-align: middle !important; }
</style>
......@@ -40,13 +42,18 @@
$(this).parent().parent().find('.property-selector:not(.select2-container)').val($(this).parent().siblings('.original').text()).trigger('change');
});
var formProperties = JSON.parse('{{ form.vars.attr["data-form-props"]|raw }}');
var dataProperties = JSON.parse('{{ form.vars.attr["data-props"]|raw }}');
$('.clear-icon').click(function() {
$(this).parent().parent().find('.property-selector:not(.select2-container)').val("/").trigger('change');
});
var formProperties = {{ form.vars.attr["data-form-props"]|raw }};
var dataProperties = {{ form.vars.attr["data-props"]|raw }};
var coreFields = ['id', 'name', 'categories', 'streetAddress', 'addressLocality', 'postalCode', 'addressCountry', 'latitude', 'longitude', 'images', 'owner', 'source']
var formData = [], allProperties = [], otherData = []; var importedData = [];
formData.push({id: 'id', text: 'Identifiant unique'});
formData.push({id: 'name', text: 'Titre de la fiche'});
formData.push({id: 'categories', text: 'Liste des catégories (en tableau ou séparées par des virgules)'});
formData.push({id: 'streetNumber', text: 'Adresse: numéro de rue'});
formData.push({id: 'streetAddress', text: 'Adresse: rue'});
formData.push({id: 'addressLocality', text: 'Adresse: ville'});
formData.push({id: 'postalCode', text: 'Adresse: code postal'});
......
......@@ -9,14 +9,16 @@
<th>Catégories lues depuis le fichier d'origine</th>
<th style="width:20px"></th>
<th>Catégories du site</th>
<th style="width:20px"></th>
</tr>
</thead>
<tbody class="table-striped">
{% for originName, mappedName in mapping %}
<tr>
<td class="original">{{originName}}</td>
<td><i class="fa fa-arrow-circle-right"></i></td>
<td>></td>
<td class="mapped"><input type="text" name="taxonomy[{{originName}}]" class="form-control category-selector" value={{mappedName}} /></td>
<td><i class="clear-icon fa fa-ban" title="Ne pas utiliser cette catégorie"></i></td>
</tr>
{% endfor %}
</tbody>
......@@ -30,8 +32,8 @@
<script>
jQuery(document).ready(function() {
var optionsList = JSON.parse('{{ form.vars.attr["data-options"]|raw }}');
var formData = []
var optionsList = {{ form.vars.attr["data-options"]|raw }};
var formData = [{ id: "", text: ""}]
for(var key in optionsList) {
var option = optionsList[key];
......@@ -42,5 +44,9 @@
data: formData
});
$('.clear-icon').click(function() {
$(this).parent().parent().find('.category-selector:not(.select2-container)').val("").trigger('change');
});
});
</script>
\ No newline at end of file
......@@ -8,16 +8,19 @@
<p>Dernière mise à jour : {{ object.lastRefresh|date('d/m/Y') }}</p>
{% endif %}
<button type="submit" class="btn btn-success" name="submit"><i class="fa fa-save" aria-hidden="true"></i>Sauvegarder</button>
{% include '@BiopenAdmin/partials/list__action_refresh.html.twig' with {'class': 'btn-primary'} %}
{% if object.id != "" and object.ontologyMapping|length > 0 %}
<button type="submit" class="btn btn-primary" name="import" value="import">
<i class="fa fa-download" aria-hidden="true"></i>Importer les données
</button>
{% endif %}
{% set class = object.ontologyMapping|length > 0 ? 'btn-default' : 'btn-primary' %}
{% if object.id != "" %}
<a href="{{ admin.generateObjectUrl('collect', object) }}" class="btn {{ class }} view_link" title="Met à jour les tables de correspondance sans réellement importer les données">
<i class="fa fa-eye" aria-hidden="true"></i>
Lire les données
</a>
<button type="submit" class="btn btn-default" name="collect" value="collect" title="Met à jour les tables de correspondance sans réellement importer les données">
<i class="fa fa-eye" aria-hidden="true"></i>Lire les données
</button>
{% endif %}
<a href="{{ admin.generateObjectUrl('list', object) }}" class="btn btn-default view_link">
<i class="fa fa-list" aria-hidden="true"></i>Retour à la liste
......@@ -27,5 +30,6 @@
<i class="fa fa-trash" aria-hidden="true"></i>Supprimer (ainsi que tous les éléments importés)
</a>
{% endif %}
{% endblock %}
......@@ -51,49 +51,59 @@ class ElementImportMappingService
$parent = $import->getParentCategoryToCreateOptions() ?: $this->em->getRepository('BiopenGeoDirectoryBundle:Category')->findOneByIsRootCategory(true);
$this->parentCategoryIdToCreateMissingOptions = $parent->getId();
// Execute custom code (the <?php is used to have proper code highliting in text editor, we remove it before executing)
eval(str_replace('<?php', '', $import->getCustomCode()));
// elements is ofently stored nested in a data attribute
if (array_key_exists('data', $data)) $data = $data['data'];
// Fixs gogocarto ontology when importing
// Fixs gogocarto ontology when importing, to simplify import/export from gogocarto to gogocarto
foreach ($data as $key => $row) {
if (array_key_exists('geo', $row))
{
$data[$key]['latitude'] = $row['geo']['latitude'];
$data[$key]['longitude'] = $row['geo']['longitude'];
unset($data[$key]['geo']);
}
if (array_key_exists('address', $row))
{
$address = $row['address'];
if (gettype($address) == "string") $data[$key]['streetAddress'] = $address;
else if ($address) {
if (array_key_exists('streetAddress', $address)) $data[$key]['streetAddress'] = $address['streetAddress'];
if (array_key_exists('addressLocality', $address)) $data[$key]['addressLocality'] = $address['addressLocality'];
if (array_key_exists('postalCode', $address)) $data[$key]['postalCode'] = $address['postalCode'];
if (array_key_exists('addressCountry', $address)) $data[$key]['addressCountry'] = $address['addressCountry'];
if (is_array($row)) {
if (array_key_exists('geo', $row))
{
$data[$key]['latitude'] = $row['geo']['latitude'];
$data[$key]['longitude'] = $row['geo']['longitude'];
unset($data[$key]['geo']);
}
if (array_key_exists('address', $row))
{
$address = $row['address'];
if (gettype($address) == "string") $data[$key]['streetAddress'] = $address;
else if ($address) {
if (array_key_exists('streetNumber', $address)) $data[$key]['streetNumber'] = $address['streetNumber'];
if (array_key_exists('streetAddress', $address)) $data[$key]['streetAddress'] = $address['streetAddress'];
if (array_key_exists('addressLocality', $address)) $data[$key]['addressLocality'] = $address['addressLocality'];
if (array_key_exists('postalCode', $address)) $data[$key]['postalCode'] = $address['postalCode'];
if (array_key_exists('addressCountry', $address)) $data[$key]['addressCountry'] = $address['addressCountry'];
}
unset($data[$key]['address']);
}
if (array_key_exists('categories', $row) && array_key_exists('categoriesFull', $row)) {
$data[$key]['categories'] = $data[$key]['categoriesFull'];
unset($data[$key]['categoriesFull']);
}
unset($data[$key]['address']);
} else {
// the $row is not an array, probably a string so we ignore it
unset($data[$key]);
}
}
// Execute custom code (the <?php is used to have proper code highliting in text editor, we remove it before executing)
eval(str_replace('<?php', '', $import->getCustomCode()));
// Ontology
$this->collectOntology($data, $import);
$data = $this->mapOntology($data);
// remove empty row, i.e. without name
$data = array_filter($data, function($row) { return array_key_exists('name', $row); });
// Taxonomy
if ($import->isCategoriesFieldMapped())
{
$this->collectTaxonomy($data, $import);
$data = $this->mapTaxonomy($data);
}
$data = $this->addMissingFieldsToData($data);
$this->em->persist($import);
$this->em->flush();
return $data;
......@@ -127,15 +137,15 @@ class ElementImportMappingService
$value = in_array($key, $this->coreFields) ? $key : "";
if (!$value && array_key_exists($key, $this->mappedCoreFields) && in_array($this->mappedCoreFields[$key], $this->coreFields))
$value = $this->mappedCoreFields[$key];
$this->ontologyMapping[$keyName] = $value;
if (!$value || !in_array($value, array_values($this->ontologyMapping))) $this->ontologyMapping[$keyName] = $value;
}
}
private function isAssociativeArray($a) {
if (!is_array($a)) return false;
foreach(array_keys($a) as $key)
if (!is_int($key)) return TRUE;
return FALSE;
if (!is_int($key)) return true;
return false;
}
public function collectTaxonomy($data, $import)
......@@ -149,6 +159,7 @@ class ElementImportMappingService
$categories = $row['categories'];
$categories = is_array($categories) ? $categories : explode(',', $categories);
foreach($categories as $category) {
if (is_array($category)) $category = $category['name'];
if (!in_array($category, $allNewCategories)) $allNewCategories[] = $category;
if ($category && !array_key_exists($category, $taxonomyMapping))
{
......@@ -180,36 +191,45 @@ class ElementImportMappingService
$mapping = $this->import->getOntologyMapping();
foreach ($data as $key => $row) {
// First map nested fields
foreach ($mapping as $search => $replace) {
$searchKeys = explode('/', $search);
if (count($searchKeys) == 2) { $searchkey = $searchKeys[0]; $subkey = $searchKeys[1]; }
else { $searchkey = $searchKeys[0]; $subkey = null; }
if (count($searchKeys) == 2) {
$searchkey = $searchKeys[0]; $subkey = $searchKeys[1];
if ($replace == '/' || $replace == '') {
unset($data[$key][$search]);
}
else if (isset($row[$searchkey]) && !isset($row[$replace])) {
if ($subkey) {
if (!in_array($replace, ['/', '']) && isset($data[$key][$searchkey]) && !isset($data[$key][$replace])) {
$data[$key][$replace] = $row[$searchkey][$subkey];
unset($data[$key][$searchkey][$subkey]);
} else {
}
}
}
// Then remove non mapped fields
foreach ($mapping as $search => $replace) {
if (in_array($replace, ['/', ''])) unset($data[$key][$search]);
}
// Finally map non nested fields
foreach ($mapping as $search => $replace) {
$searchKeys = explode('/', $search);
if (count($searchKeys) == 1) {
$searchkey = $search;
if (!in_array($replace, ['/', '']) && isset($data[$key][$searchkey]) && !isset($data[$key][$replace])) {
$data[$key][$replace] = $row[$searchkey];
unset($data[$key][$searchkey]);
}
}
}
}
return $data;
}
private function addMissingFieldsToData($data)
{
foreach ($data as $key => $row) {
$missingFields = array_diff($this->coreFields, array_keys($row));
foreach ($missingFields as $missingField) {
$data[$key][$missingField] = "";
// add streetNumber into streetAddress
if (isset($data[$key]['streetNumber']) && isset($data[$key]['streetAddress'])) {
$data[$key]['streetAddress'] = $data[$key]['streetNumber'] . ' ' . $data[$key]['streetAddress'];
unset($data[$key]['streetNumber']);
}
}
return $data;
}
......@@ -218,12 +238,31 @@ class ElementImportMappingService
$mapping = $this->import->getTaxonomyMapping();
foreach ($data as $key => $row)
{
if (is_array($row['categories'])) {
if (isset($data[$key]['categories'])) {
if (is_string($row['categories'])) $row['categories'] = explode(',', $row['categories']);
$categories = array_map(function($el) use ($mapping) {
return array_key_exists($el, $mapping) && array_key_exists($mapping[$el], $this->mappingTableIds) ? $this->mappingTableIds[$mapping[$el]]['idAndParentsId'] : [];
}, $row['categories']);
$data[$key]['categories'] = array_unique($this->array_flatten($categories));
$categories = []; $categoriesIds = [];
foreach ($row['categories'] as $category)
{
$val = is_array($category) ? $category['name'] : $category;
if (array_key_exists($val, $mapping) && array_key_exists($mapping[$val], $this->mappingTableIds))
{
$newcat['originalValue'] = $val;
$newcat['mappedName'] = $this->mappingTableIds[$mapping[$val]]['name'];
$newcat['mappedId'] = $this->mappingTableIds[$mapping[$val]]['id'];
if (isset($category['index'])) $newcat['index'] = $category['index'];
if (isset($category['description'])) $newcat['description'] = $category['description'];
$categories[] = $newcat;
$categoriesIds[] = $newcat['mappedId'];
$parentIds = $this->mappingTableIds[$mapping[$val]]['idAndParentsId'];
foreach ($parentIds as $id) {
if (!in_array($id, $categoriesIds)) {
$categories[] = ['mappedId' => $id, 'info' => "Automatiquement ajoutée (category parente d'une category importée)"];
$categoriesIds[] = $id;
}
}
}
}
$data[$key]['categories'] = $categories;
}
}
return $data;
......@@ -243,6 +282,7 @@ class ElementImportMappingService
{
$ids = [
'id' => $option->getId(),
'name' => $option->getName(),
'idAndParentsId' => $option->getIdAndParentOptionIds()
];
$this->mappingTableIds[$this->slugify($option->getNameWithParent())] = $ids;
......
......@@ -91,9 +91,14 @@ class ElementImportOneService
}
$this->currentRow = $row;
// adds missings fields instead of checking if each field is set before accessing
$missingFields = array_diff($this->coreFields, array_keys($row));
foreach ($missingFields as $missingField) {
$data[$key][$missingField] = "";
}
$element->setOldId($row['id']);
$element->setName($row['name']);
$address = new PostalAddress($row['streetAddress'], $row['addressLocality'], $row['postalCode'], $row["addressCountry"]);
$element->setAddress($address);
......@@ -200,8 +205,10 @@ class ElementImportOneService
$optionsIdAdded = [];
$options = $row['categories'];
foreach ($options as $optionId) {
$this->addOptionValue($element, $optionId);
$defaultOption = array("index" => 0, "description" => "");
foreach ($options as $option) {
$option = array_merge($defaultOption, $option);
$this->addOptionValue($element, $option['mappedId'], $option['index'], $option['description']);
}
if ($import->getNeedToHaveOptionsOtherThanTheOnesAddedToEachElements()) {
......@@ -217,12 +224,13 @@ class ElementImportOneService
if (count($element->getOptionValues()) == 0) $element->setModerationState(ModerationState::NoOptionProvided);
}
private function addOptionValue($element, $id)
private function addOptionValue($element, $id, $index = 0, $description = "")
{
if (!$id || $id == "0" || $id == 0) return;
$optionValue = new OptionValue();
$optionValue->setOptionId($id);
$optionValue->setIndex(0);
$optionValue->setIndex($index);
$optionValue->setDescription($description);
$element->addOptionValue($optionValue);
return $id;
}
......
......@@ -101,7 +101,7 @@ class ElementImportService
public function collectData($import)
{
$data = $import->getUrl() ? $this->importJson($import, true) : $this->importCsv($import, true);
$this->mappingService->transform($data, $import);
return $this->mappingService->transform($data, $import);
}
public function importData($data, $import)
......@@ -149,7 +149,7 @@ class ElementImportService
if (!array_key_exists($e->getMessage(), $this->errorsCount)) $this->errorsCount[$e->getMessage()] = 1;
else $this->errorsCount[$e->getMessage()]++;
$message = '<u>' . $e->getMessage() . '</u> <b>(x' . $this->errorsCount[$e->getMessage()] . ')</b></br>' . $e->getFile() . ' LINE ' . $e->getLine() . '</br>';
$message .= 'CONTEXT : ' . print_r($row, true);
$message .= 'CONTEXT : <pre>' . print_r($row, true) . '</pre>';
$this->errorsMessages[$e->getMessage()] = $message;
}
......
{
"licence": "https://opendatacommons.org/licenses/odbl/summary/",
"ontology":"gogofull",
"data":[{
"bala":[{
"id":"Rhm",
"newfields": "balam",
"name":"Entropie",
"coord":{"latitude":45.18679,"longitude":5.70548},
"sourceKey":"CapOuPasCap",
"address":{"streetAddress":"5 rue Georges Jacquet Grenoble"},
"addresses":{"street_num": "5", "streetAddress":"rue Georges Jacquet Grenoble"},
"createdAt":"21/12/2018 à 18:26",
"updatedAt":"17/03/2019 à 13:38",
"taxonomy": ["vert foncé", "tandem"],
"categories": ["Habitat"],
"categoriesFull": [
{
"id": 2,
"name": "boum",
"description": "un bel habitat",
"index": 5
},
{
"id": 8,
"name": "Couveuse",
"description": null,
"index": 1
}
],
"abstract": "Ateliers bricole",
"openHoursString": "",
"openHours": null,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment