md-systems / crm_core Goto Github PK
View Code? Open in Web Editor NEWDrupal 8 port of the CRM Core module
Home Page: https://www.drupal.org/project/crm_core
Drupal 8 port of the CRM Core module
Home Page: https://www.drupal.org/project/crm_core
The Matchers currently don't support instances and all forms just work for the default instances.
This needs a proper port to D8 plugin concept.
When I go to crm-core/activity-types I get WSOD and drupal log show 3 errors:
Notice: Undefined variable: langcode in Drupal\crm_core_activity\ActivityTypeAccessControlHandler->checkAccess() (line 23 of /var/www/html/crmcore8/modules/contrib/crm_core/modules/crm_core_activity/src/ActivityTypeAccessControlHandler.php)
Recoverable fatal error: Argument 3 passed to Drupal\Core\Entity\EntityAccessControlHandler::checkAccess() must implement interface Drupal\Core\Session\AccountInterface, null given, called in /var/www/html/crmcore/modules/contrib/crm_core/modules/crm_core_activity/src/ActivityTypeAccessControlHandler.php on line 23 and defined in Drupal\Core\Entity\EntityAccessControlHandler->checkAccess() (line 134 of /var/www/html/crmcore/core/lib/Drupal/Core/Entity/EntityAccessControlHandler.php).
Recoverable fatal error: Argument 1 passed to Drupal\Core\Access\AccessResult::allowedIfHasPermission() must implement interface Drupal\Core\Session\AccountInterface, null given, called in /var/www/html/crmcore8/core/lib/Drupal/Core/Entity/EntityAccessControlHandler.php on line 139 and defined in Drupal\Core\Access\AccessResult::allowedIfHasPermission() (line 107 of /var/www/html/crmcore8/core/lib/Drupal/Core/Access/AccessResult.php).
A matcher offers a simple matching for a specific set.
Previously, there was a global match thing to call all matchers for action.
This leads to trouble in case a matcher is only to be executed for a specific case and makes no sense in a global scope.
A chaining Matcher can be selected as a single matcher and internally operates on all selected matchers.
Also it maintains an order and a strategy if it stops after a first successfull match.. or if it executes all matchers and reorders the results at the end by score...
The rules / fields for matching need to be collected from all called matchers to offer contexts.
A problem is if the matchers then allow multiple contact types. Currently the contact type is the bundle that is always set on the contact template. The contact type newly needs to be optional.
Matching names are a complex problem:
Some systems store them separately, others store it splitted up.
When matching, in many cases, the names come in without structure and need to be dynamically matched across multiple fields... or possibly a single one with different naming order.
Example:
company - firstname lastname
firstname lastname, company
And many more possible orders.
When matching a mail address, the data comes in as a single string, in my example:
"Miro Dietiker, MD Systems" [email protected]
Separating the mail is easy.
We could try splitting by know separators such as comma:
Miro Dietiker
MD Systems
And we could try splitting further by spaces.
Miro, Dietiker, MD, Systems
And then apply a contains (or even a equals) match on normalised name component fields.
Possibly we should only consider components that are 3+ characters long and keep shorter connected?
Also we could identify known titles.
We could also first try the longer connected names for a full match. Full matches would receive a higher score.
With partial matches of components, we possibly should divide the score by the total components somehow.
The matcher would need to offer a virtual field to pass in the combined data.
Similar to TMGMT we want to build a menu link structure to maintain the default CRM UI.
All UI elements will be switched to the admin UI by default.
Below the CRM item, we can create a hierarchical menu structure with direct access from the toolbar. The lower levels are only accessible if the toolbar is on the left side, not on top.
The match() method just returns matches above the threshold.
Sometimes the thresholds are not that hard. There might be a safe threshold to run something with strict assignment and some lower threshold where matches are not considered to be sharp and possibly need review. Still, we want to continue process.
To allow this kind of stuff, the match should return some result with data about match quality, in addition to the contacts.
Implementing EntityWithPluginCollectionInterface would help us to:
preSave()
method on the Matcher (added to save plugin configuration properly)Investigate core examples (e.g. Block) and upload the patch.
We should add a list of activities that this issue participates in, so we can find them easily.
The problem is, we are passing in a contact template to the matcher.
Thus it needs to follow field definition of the contact template.
We discussed and started implemeting an approach to let a Matcher return typed data rules it offers.
Then the matcher would also need to tell us what bundles / contact types it supports... and possibly also offer a factory to provide a contact template to fill with data.
Then matchers can offer any typed data fields they want and we can pass in data...
If a matcher offers to match across multiple bundles, the contact template possibly can skip the bundle. So this might be an optional selection and the matcher needs to support enumerating both field definition for all bundles or for a specific bundle.
While working on https://www.drupal.org/node/2624240 I had a problem with CRM Core related fields.
In that issue we are displaying list of fields and creating links from their field-edit-form link template. The problem appeared with these fields:
We manage find a field-edit-form link template (e.g. crm_core_activity-field-edit-form), but the route for that template does not exist/it's not discovered...
These fields are added in Collect CRM module - so not sure if this is the right place to open an issue.
Hi there. Great job guys!
This is just a notification that I'm continuing your work in forked repo, so when you will be back to continue porting CRM Core to Drupal 8.x you can use my work to save some time.
A match() should only depend to ContactInterface and not Contact.
Please add a composer.json file so this module can be loaded with Composer. :)
crm_core_match_testing_page()
will be removed in #12.
From @Berdir's comment:
This could be a useful feature but should be re-introduced as an entity operation or so with an auto-complete to select a contact or something like that? Probably easier to drop and have a task/issue to add it again?
Here is the old code of crm_core_match.test.inc that has been removed.
<?php
/**
* @file
* Contains functionality for testing purposes.
*/
function crm_core_match_testing_page_title($contact) {
return t('Matching Rules for @contact_name', array('@contact_name' => crm_core_contact_title($contact)));
}
/**
* Page callback to display match debug info.
*
* @param object $contact
* CRM Core Contact.
*
* @return string
*/
function crm_core_match_testing_page($contact) {
$output = '';
$engines = crm_core_match_get_engines();
// Display engines table.
$rows = array();
foreach ($engines as $engine) {
if ($engine->getStatus()) {
$rows[] = array(
'data' => array(
$engine->getID(),
$engine->getName(),
$engine->getDescription(),
$engine->getMachineName(),
$engine->getWeight(),
),
);
}
}
$header = array(
t('Engine ID'),
t('Engine name'),
t('Engine description'),
t('Engine machine name'),
t('Weight'),
);
$output .= theme('table', array(
'header' => $header,
'rows' => $rows,
'empty' => t('No matching engines enabled or associated with contacts of this type.'),
));
foreach ($engines as $engine) {
$matches = array();
$engine->execute($contact, $matches);
}
if (empty($matches)) {
$output .= '<h1>No matches currently available.</h1>';
}
else {
$output .= '<h1>Matches:</h1>';
// Display matched contacts table.
$rows = array();
$contacts = crm_core_contact_load_multiple($matches);
foreach ($contacts as $matched_contact) {
$uri = $matched_contact->uri();
$link = l($matched_contact->label(), $uri['path']);
$rows[] = array(
'data' => array(
$matched_contact->contact_id,
$link,
),
);
}
$header = array(
t('Contact ID'),
t('Contact Name'),
);
$output .= theme('table', array(
'header' => $header,
'rows' => $rows,
));
}
return $output;
}
function crm_core_match_info_page() {
$output = '';
$engines = crm_core_match_get_engines();
// Display engines table.
$rows = array();
foreach ($engines as $engine) {
if ($engine->getStatus()) {
$rows[] = array(
'data' => array(
$engine->getID(),
$engine->getName(),
$engine->getDescription(),
$engine->getMachineName(),
$engine->getWeight(),
),
);
}
}
$header = array(
t('Engine ID'),
t('Engine name'),
t('Engine description'),
t('Engine machine name'),
t('Weight'),
);
$output .= theme('table', array(
'header' => $header,
'rows' => $rows,
'empty' => t('No matching engines enabled or associated with contacts of this type.'),
));
if (module_exists('crm_core_default_matching_engine')) {
$contact_types = crm_core_contact_types(TRUE);
foreach (array_keys($contact_types) as $contact_type) {
$rules = crm_core_default_matching_engine_load_field_config($contact_type);
// Display rules table.
$rows = array();
foreach ($rules as $rule) {
$rows[] = array(
'data' => array(
$rule->mrid,
$rule->field_name,
$rule->field_type,
$rule->field_item,
$rule->operator,
$rule->options,
$rule->score,
$rule->weight,
),
);
}
$header = array(
t('Rule ID'),
t('Field name'),
t('Field type'),
t('Field item'),
t('Field operator'),
t('Field options'),
t('Field score'),
t('Field weight'),
);
$output .= theme('table', array(
'header' => $header,
'caption' => t('Matching rules for @contact_type', array(
'@contact_type' => $contact_types[$contact_type]->name)
),
'rows' => $rows,
'empty' => t('Matching is not enabled for this contact type.'),
));
}
}
return $output;
}
Missing leading slash at start of the request gives error trying to access diferent entities when crm-core installed.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.