Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

can filter on object properties #31419

Open
wants to merge 64 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
348a0d7
can filter on object properties
frederic34 Oct 16, 2024
9b44b5e
can filter on object properties
frederic34 Oct 16, 2024
6152d2e
Merge remote-tracking branch 'upstream/develop' into extrafields_obje…
frederic34 Oct 16, 2024
f0f8bc5
can filter on object properties
frederic34 Oct 16, 2024
befaf26
can filter on object properties
frederic34 Oct 16, 2024
324fe1e
can filter on object properties
frederic34 Oct 16, 2024
c23f06d
fix sql
frederic34 Oct 17, 2024
f2ef148
Merge remote-tracking branch 'upstream/develop' into extrafields_obje…
frederic34 Oct 17, 2024
35935a5
fix
frederic34 Oct 17, 2024
bd25675
Merge branch 'develop' into extrafields_object_filter
frederic34 Oct 20, 2024
6f95ffe
Merge remote-tracking branch 'upstream/develop' into extrafields_obje…
frederic34 Oct 22, 2024
2a0d4bf
new ajax search with infinite scroll
frederic34 Oct 22, 2024
6b2767c
Merge remote-tracking branch 'origin/extrafields_object_filter' into …
frederic34 Oct 22, 2024
a7ee5b6
new ajax search with infinite scroll
frederic34 Oct 22, 2024
12a9b43
new ajax search with infinite scroll
frederic34 Oct 22, 2024
05c4dbc
new ajax search with infinite scroll
frederic34 Oct 22, 2024
3fcb57f
wip
frederic34 Oct 23, 2024
4f07ec9
Merge remote-tracking branch 'upstream/develop' into extrafields_obje…
frederic34 Oct 23, 2024
56ebe9b
Merge remote-tracking branch 'upstream/develop' into extrafields_obje…
frederic34 Oct 23, 2024
ee12679
Merge remote-tracking branch 'upstream/develop' into extrafields_obje…
frederic34 Oct 24, 2024
cf27abb
Merge remote-tracking branch 'upstream/develop' into extrafields_obje…
frederic34 Oct 24, 2024
36b507a
wip
frederic34 Oct 24, 2024
2e12fb0
Merge remote-tracking branch 'upstream/develop' into extrafields_obje…
frederic34 Oct 24, 2024
8828b41
Merge branch 'develop' into extrafields_object_filter
frederic34 Oct 26, 2024
3e685df
fix phpstan
frederic34 Oct 26, 2024
259ce60
Merge remote-tracking branch 'upstream/develop' into extrafields_obje…
frederic34 Oct 26, 2024
f4e05cf
Merge remote-tracking branch 'upstream/develop' into extrafields_obje…
frederic34 Oct 26, 2024
3246cab
Merge remote-tracking branch 'upstream/develop' into extrafields_obje…
frederic34 Oct 26, 2024
8d149c0
wip
frederic34 Oct 26, 2024
26f788b
Merge remote-tracking branch 'upstream/develop' into extrafields_obje…
frederic34 Oct 27, 2024
3e96b33
Merge remote-tracking branch 'upstream/develop' into extrafields_obje…
frederic34 Oct 27, 2024
66374f2
Merge branch 'develop' into extrafields_object_filter
frederic34 Nov 9, 2024
86d2641
Merge remote-tracking branch 'origin/extrafields_object_filter' into …
frederic34 Nov 9, 2024
1471626
clean code
frederic34 Nov 9, 2024
e16c012
Merge branch 'develop' into extrafields_object_filter
frederic34 Nov 11, 2024
6b45be1
Merge branch 'develop' into extrafields_object_filter
frederic34 Nov 13, 2024
98f7f21
Merge branch 'develop' into extrafields_object_filter
frederic34 Nov 15, 2024
2a19191
Merge remote-tracking branch 'origin' into extrafields_object_filter
frederic34 Nov 16, 2024
4492ced
fix
frederic34 Nov 16, 2024
b9f8c18
Merge remote-tracking branch 'origin/extrafields_object_filter' into …
frederic34 Nov 16, 2024
ad8a5c9
Merge remote-tracking branch 'upstream/develop' into extrafields_obje…
frederic34 Nov 19, 2024
4425f38
test
frederic34 Nov 19, 2024
af92519
test
frederic34 Nov 19, 2024
95fadde
Merge branch 'develop' into extrafields_object_filter
frederic34 Nov 25, 2024
6741ead
fix with last updates
frederic34 Nov 25, 2024
cdf71ad
doc
frederic34 Nov 25, 2024
4075f8f
Merge branch 'develop' into extrafields_object_filter
frederic34 Nov 26, 2024
02937ac
fix phpstan
frederic34 Nov 27, 2024
8bfb325
Merge remote-tracking branch 'upstream/develop' into extrafields_obje…
frederic34 Nov 27, 2024
365873a
fix
frederic34 Nov 27, 2024
07eab50
fix
frederic34 Nov 27, 2024
edd1a50
Merge remote-tracking branch 'upstream/develop' into extrafields_obje…
frederic34 Nov 27, 2024
da8ac80
fix merge
frederic34 Nov 27, 2024
4c97950
fix
frederic34 Nov 27, 2024
076ae6a
fix
frederic34 Nov 27, 2024
447a9f2
Merge remote-tracking branch 'upstream/develop' into extrafields_obje…
frederic34 Nov 27, 2024
8d5c5cf
Merge branch 'develop' into extrafields_object_filter
frederic34 Nov 27, 2024
17e31c1
Merge branch 'develop' into extrafields_object_filter
frederic34 Nov 28, 2024
a454940
wip
frederic34 Dec 8, 2024
c161abe
Merge remote-tracking branch 'origin/extrafields_object_filter' into …
frederic34 Dec 8, 2024
2e18d20
wip
frederic34 Dec 8, 2024
9773604
Merge branch 'develop' into extrafields_object_filter
frederic34 Dec 8, 2024
34517f7
Merge branch 'develop' into extrafields_object_filter
frederic34 Dec 8, 2024
786a657
Merge branch 'develop' into extrafields_object_filter
frederic34 Dec 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
342 changes: 342 additions & 0 deletions htdocs/core/ajax/ajaxextrafield.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,342 @@
<?php
/* Copyright (C) 2007-2024 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

/**
* \file htdocs/core/ajax/ajaxextrafield.php
* \ingroup extrafield
* \brief This script returns content of extrafield
*/

if (!defined('NOTOKENRENEWAL')) {
// Disables token renewal
define('NOTOKENRENEWAL', 1);
}
if (!defined('NOREQUIREMENU')) {
define('NOREQUIREMENU', '1');
}
if (!defined('NOREQUIREHTML')) {
define('NOREQUIREHTML', '1');
}
if (!defined('NOREQUIREAJAX')) {
define('NOREQUIREAJAX', '1');
}
if (!defined('NOHEADERNOFOOTER')) {
define('NOHEADERNOFOOTER', '1');
}

include '../../main.inc.php';
include_once DOL_DOCUMENT_ROOT . '/core/class/html.form.class.php';
/**
* @var Conf $conf
* @var DoliDB $db
* @var Translate $langs
* @var User $user
*/

// object id
$objectid = GETPOST('objectid', 'aZ09');
// 'module' or 'myobject@mymodule', 'mymodule_myobject'
$objecttype = GETPOST('objecttype', 'aZ09arobase');
$objectkey = GETPOST('objectkey', 'restricthtml');
$search = GETPOST('search', 'restricthtml');
$page = GETPOSTINT('page');
$mode = GETPOSTINT('mode');
$value = GETPOST('value', 'alphanohtml');
$limit = 10;
$offset = (($page - 1) * $limit);
$element_ref = '';
if (is_numeric($objectid)) {
$objectid = (int) $objectid;
} else {
$element_ref = $objectid;
$objectid = 0;
}
// Load object according to $element
$object = fetchObjectByElement($objectid, $objecttype, $element_ref);
if (empty($object->element)) {
httponly_accessforbidden('Failed to get object with fetchObjectByElement(id=' . $objectid . ', objecttype=' . $objecttype . ')');
}

$module = $object->module;
$element = $object->element;

$usesublevelpermission = ($module != $element ? $element : '');
if ($usesublevelpermission && !$user->hasRight($module, $element)) { // There is no permission on object defined, we will check permission on module directly
$usesublevelpermission = '';
}

// print $object->id.' - '.$object->module.' - '.$object->element.' - '.$object->table_element.' - '.$usesublevelpermission."\n";

// Security check
restrictedArea($user, $object->module, $object, $object->table_element, $usesublevelpermission);


/*
* View
*/

top_httphead();

$data = [
'results' => [],
'pagination' => [
'more' => true,
]
];
if ($page == 1) {
$data['results'][] = [
'id' => -1,
'text' => '&nbsp;',
];
}
$i = 0;
if ($object instanceof CommonObject) {
$extrafields = new ExtraFields($db);
$extrafields->fetch_name_optionals_label($element);
$options = $extrafields->attributes[$element]['param'][$objectkey]['options'];
if (is_array($options)) {
$tmpparamoptions = array_keys($options);
$paramoptions = preg_split('/[\r\n]+/', $tmpparamoptions[0]);

$InfoFieldList = explode(":", $paramoptions[0], 5);
// 0 : tableName
// 1 : label field name
// 2 : key fields name (if different of rowid)
// optional parameters...
// 3 : key field parent (for dependent lists). How this is used ?
// 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value. Or use USF on the second line.
// 5 : string category type. This replace the filter.
// 6 : ids categories list separated by comma for category root. This replace the filter.
// 7 : sort field (not used here but used into format for commobject)

// If there is a filter, we extract it by taking all content inside parenthesis.
if (! empty($InfoFieldList[4])) {
$pos = 0; // $pos will be position of ending filter
$parenthesisopen = 0;
while (substr($InfoFieldList[4], $pos, 1) !== '' && ($parenthesisopen || $pos == 0 || substr($InfoFieldList[4], $pos, 1) != ':')) {
if (substr($InfoFieldList[4], $pos, 1) == '(') {
$parenthesisopen++;
}
if (substr($InfoFieldList[4], $pos, 1) == ')') {
$parenthesisopen--;
}
$pos++;
}
$tmpbefore = substr($InfoFieldList[4], 0, $pos);
$tmpafter = substr($InfoFieldList[4], $pos + 1);
//var_dump($InfoFieldList[4].' -> '.$pos); var_dump($tmpafter);
$InfoFieldList[4] = $tmpbefore;
if ($tmpafter !== '') {
$InfoFieldList = array_merge($InfoFieldList, explode(':', $tmpafter));
}

// Fix better compatibility with some old extrafield syntax filter "(field=123)"
$reg = array();
if (preg_match('/^\(?([a-z0-9]+)([=<>]+)(\d+)\)?$/i', $InfoFieldList[4], $reg)) {
$InfoFieldList[4] = '(' . $reg[1] . ':' . $reg[2] . ':' . $reg[3] . ')';
}

//var_dump($InfoFieldList);
}

$parentName = '';
$parentField = '';
$keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2] . ' as rowid');

if (count($InfoFieldList) > 3 && !empty($InfoFieldList[3])) {
list($parentName, $parentField) = explode('|', $InfoFieldList[3]);
$keyList .= ', ' . $parentField;
}
if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
if (strpos($InfoFieldList[4], 'extra.') !== false) {
$keyList = 'main.' . $InfoFieldList[2] . ' as rowid';
} else {
$keyList = $InfoFieldList[2] . ' as rowid';
}
}

$filter_categorie = false;
if (count($InfoFieldList) > 5) {
if ($InfoFieldList[0] == 'categorie') {
$filter_categorie = true;
}
}

if (!$filter_categorie) {
$fields_label = explode('|', $InfoFieldList[1]);
if (count($fields_label) > 0) {
$keyList .= ', ';
$keyList .= implode(', ', $fields_label);
}

$sqlwhere = '';
$sql = "SELECT " . $keyList;
$sql .= ' FROM ' . $db->prefix() . $InfoFieldList[0];

// Add filter from 4th field
if (!empty($InfoFieldList[4])) {
$tags = [];
preg_match_all('/\$(.*?)\$/', $InfoFieldList[4], $tags);
foreach ($tags[0] as $keytag => $valuetag) {
$property = strtolower($tags[1][$keytag]);
if (strpos($InfoFieldList[4], $valuetag) !== false && property_exists($object, $property) && !empty($object->$property)) {
$InfoFieldList[4] = str_replace($valuetag, (string) $object->$property, $InfoFieldList[4]);
} else {
$InfoFieldList[4] = str_replace($valuetag, '0', $InfoFieldList[4]);
}
}
// can use current entity filter
if (strpos($InfoFieldList[4], '$ENTITY$') !== false) {
$InfoFieldList[4] = str_replace('$ENTITY$', (string) $conf->entity, $InfoFieldList[4]);
}
// can use SELECT request
if (strpos($InfoFieldList[4], '$SEL$') !== false) {
$InfoFieldList[4] = str_replace('$SEL$', 'SELECT', $InfoFieldList[4]);
}
// can use MODE request (list or view)
if (strpos($InfoFieldList[4], '$MODE$') !== false) {
$InfoFieldList[4] = str_replace('$MODE$', (string) $mode, $InfoFieldList[4]);
}

// current object id can be use into filter
if (strpos($InfoFieldList[4], '$ID$') !== false && !empty($objectid)) {
$InfoFieldList[4] = str_replace('$ID$', (string) $objectid, $InfoFieldList[4]);
} else {
$InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
}

// We have to join on extrafield table
$errstr = '';
if (strpos($InfoFieldList[4], 'extra.') !== false) {
$sql .= ' as main, ' . $db->sanitize($db->prefix() . $InfoFieldList[0]) . '_extrafields as extra';
$sqlwhere .= " WHERE extra.fk_object = main." . $db->sanitize($InfoFieldList[2]);
$sqlwhere .= " AND " . forgeSQLFromUniversalSearchCriteria($InfoFieldList[4], $errstr, 1);
} else {
$sqlwhere .= " WHERE " . forgeSQLFromUniversalSearchCriteria($InfoFieldList[4], $errstr, 1);
}
} else {
$sqlwhere .= ' WHERE 1=1';
}

// Some tables may have field, some other not. For the moment we disable it.
if (in_array($InfoFieldList[0], array('tablewithentity'))) {
$sqlwhere .= ' AND entity = ' . ((int) $conf->entity);
}
if ($search) {
if ($fields_label) {
$sqlwhere .= " " . natural_search($fields_label, $search, 0);
}
}
$sql .= $sqlwhere;
$orderfields = explode('|', $InfoFieldList[1]);
$keyList = $InfoFieldList[1];
if (count($orderfields)) {
$keyList = implode(', ', $orderfields);
}
$sql .= $db->order($keyList);
$sql .= $db->plimit($limit, $offset);

$data['sql'] = $sql;

$resql = $db->query($sql);
if ($resql) {
// $out .= '<option value="0">&nbsp;</option>';
$num = $db->num_rows($resql);
$i = 0;
while ($i < $num) {
$labeltoshow = '';
$obj = $db->fetch_object($resql);

// Several field into label (eq table:code|label:rowid)
$notrans = false;
$fields_label = explode('|', $InfoFieldList[1]);
if (count($fields_label) > 1) {
$notrans = true;
foreach ($fields_label as $field_toshow) {
$labeltoshow .= $obj->$field_toshow . ' ';
}
} else {
$labeltoshow = $obj->{$InfoFieldList[1]};
}

if ($value == $obj->rowid) {
if (!$notrans) {
foreach ($fields_label as $field_toshow) {
$translabel = $langs->trans($obj->$field_toshow);
$labeltoshow = $translabel . ' ';
}
}
// $out .= '<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
$data['results'][] = [
'id' => $obj->rowid,
'text' => $labeltoshow,
];
} else {
if (!$notrans) {
$translabel = $langs->trans($obj->{$InfoFieldList[1]});
$labeltoshow = $translabel;
}
if (empty($labeltoshow)) {
$labeltoshow = '(not defined)';
}

if (!empty($InfoFieldList[3]) && $parentField) {
$parent = $parentName . ':' . $obj->{$parentField};
}

// $out .= '<option value="'.$obj->rowid.'"';
// $out .= ($value == $obj->rowid ? ' selected' : '');
// $out .= (!empty($parent) ? ' parent="'.$parent.'"' : '');
// $out .= '>'.$labeltoshow.'</option>';
$data['results'][] = [
'id' => $obj->rowid,
'text' => $labeltoshow,
];
}

$i++;
}
$db->free($resql);
} else {
dol_syslog('Error in request ' . $db->lasterror() . '. Check setup of extra parameters.', LOG_ERR);
}
} else {
require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
require_once DOL_DOCUMENT_ROOT . '/core/class/html.form.class.php';
$form = new Form($db);
$categories = $form->select_all_categories(Categorie::$MAP_ID_TO_CODE[$InfoFieldList[5]], '', 'parent', 64, $InfoFieldList[6], 1, 1);
// $out .= '<option value="0">&nbsp;</option>';
// if (is_array($categories)) {
// foreach ($categories as $category_key => $category_value) {
// $out .= '<option value="'.$category_key.'"';
// $out .= ($value == $category_key ? ' selected' : '');
// $out .= '>'.$category_value.'</option>';
// }
// }
}
}
}

if ($page > 1 && $i < 9) {
$data['pagination'] = [
'more' => false,
];
}
print json_encode($data);

$db->close();
2 changes: 2 additions & 0 deletions htdocs/core/class/commonobject.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -7931,6 +7931,8 @@ function handlemultiinputdisabling(htmlname){
} else {
$sql .= " ORDER BY ".$this->db->sanitize(implode(', ', $fields_label));
}
$sql .= ' LIMIT ' . getDolGlobalInt('MAIN_EXTRAFIELDS_LIMIT_SELLIST_SQL', 1000);
// print $sql;

dol_syslog(get_class($this) . '::showInputField type=sellist', LOG_DEBUG);
$resql = $this->db->query($sql);
Expand Down
Loading
Loading