Slide 1

Slide 1 text

COIFFARD Xavier ABBAS Hussein Expression language @ Sell Secure

Slide 2

Slide 2 text

Hussein ABBAS Ingénieur d’études et développement @habbas92 L’accent est Libanais Xavier Coiffard Lead Developer SELL SECURE @angezanetti http://angezanetti.com About us

Slide 3

Slide 3 text

COIFFARD Xavier ABBAS Hussein SellSecure ?

Slide 4

Slide 4 text

Sell Secure ● Lutte contre la fraude à la CB sur les stores e- commerce ● Start up ! ● 4 dev / 4 analystes / 15 enqueteurs / 2 bizdev ● MVP ftw!

Slide 5

Slide 5 text

Sell Secure

Slide 6

Slide 6 text

● Analyser des centaines de datas ● Déclencher un traitement statistique ● Scorer une transaction: Go/Nogo livraison Un moteur de règle ?

Slide 7

Slide 7 text

COIFFARD Xavier ABBAS Hussein Historique !

Slide 8

Slide 8 text

Task force TAAASSK FORCE

Slide 9

Slide 9 text

Un choix constestable… ● Choix de Ruler contestable ● Coder vite vite ● Plus personne après 100 jours

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

● Dette technique ● Construire à chaque fois le même objet (temps de traitement énorme) ● Petit projet opensource Problématiques techniques

Slide 12

Slide 12 text

Problématiques métiers ● Compléxité des règles demandées par le métier qui explose ● Les métiers écrivent du JSON dans la BDD….

Slide 13

Slide 13 text

COIFFARD Xavier ABBAS Hussein Et ça marche ?

Slide 14

Slide 14 text

Un OR et un AND ?… !

Slide 15

Slide 15 text

·Petit projet Open Source (pas maintenu, en version bêta)

Slide 16

Slide 16 text

Des alternatives ?

Slide 17

Slide 17 text

hallelujah !

Slide 18

Slide 18 text

COIFFARD Xavier ABBAS Hussein Expression Language

Slide 19

Slide 19 text

● Component Symfony symfony/expression-language ● Evaluer/Compiler des expressions ● Basé sur l’expression syntaxe de twig ● Simple à mettre en place Expression langage

Slide 20

Slide 20 text

Exemple class Order { public $amount; } $order = new Order(); $order->amount = 150;

Slide 21

Slide 21 text

Exemple class Order { public $amount; } $order = new Order(); $order->amount = 150; $language->evaluate( ‘order.amount in 100..200', array( 'order' => $order, ) );

Slide 22

Slide 22 text

COIFFARD Xavier ABBAS Hussein Ok, mais en vrai ?

Slide 23

Slide 23 text

Est-ce la bonne solution? ● Répond à nos besoins ● Valider par les métiers ● Extensible

Slide 24

Slide 24 text

public function rulesTreatment($rules, $context, $isbref)
 {
 foreach ($rules as $expression) {
 try {
 $return
 = $this->expressionLanguage->evaluate(
 $expression,
 $context
 ); if ($return === true) { //On déclenche la règle }
 } catch (SyntaxError $e) {
 }
 }
 } Implémentation

Slide 25

Slide 25 text

Surcharge du composant class ExpressionLanguage extends BaseExpressionLanguage
 {
 /**
 * @param GetListElementsFunction $elementsList ;the object
 * @param ParserCacheInterface|null $parser
 * @param array $providers
 */
 public function __construct(
 GetListElementsFunction $elementsList,
 ParserCacheInterface $parser = null,
 array $providers = array()
 ) {
 // prepend the default provider to let users override it easily
 array_unshift($providers, $elementsList);
 
 parent::__construct($parser, $providers);
 }
 }

Slide 26

Slide 26 text

COIFFARD Xavier ABBAS Hussein Avant / Après:

Slide 27

Slide 27 text

[
 {
 "type": "group",
 "logical": "and",
 "children": [
 {
 "type": "condition",
 "variable": "var1",
 "operator": "lists-NotIn",
 "parameter": [
 "2"
 ]
 },
 {
 "type": "condition",
 "variable": "var2",
 "operator": "lists-NotIn",
 "parameter": [
 "3"
 ]
 },
 {
 "type": "condition",
 "variable": "var3",
 "operator": "lists-NotIn",
 "parameter": [
 "4"
 ]
 },
 {
 "type": "condition",
 "variable": "var4",
 "operator": "lists-NotIn",
 "parameter": [
 "5"
 ]
 },
 {
 "type": "condition",
 "variable": "var5",
 "operator": "lists-NotIn",
 "parameter": [
 "6"
 ]
 },
 {
 "type": "condition",
 "variable": "var6",
 "operator": "lists-NotIn",
 "parameter": [
 "15"
 ]
 }
 ]
 }
 ] var1 not in getListElement(2)
 and var2 not in getListElement(3)
 and var3 not in getListElement(4)
 and var4 not in getListElement(5)
 and var5 not in getListElement(6)
 and var6 not in getListElement(15) Les règles:

Slide 28

Slide 28 text


 * @license copyright SellSecure
 * @version Release: <2.0>
 * @link www.sellsecure.com
 */
 class InsertRulesObjectDB
 {
 private $_container;
 private $_connexion;
 private $_tableTransaction;
 private $_arrayDecisionRuler;
 private $_arrayRulesScoreRuler;
 
 /**
 * Method constructor
 *
 * @param connexion $connexion :connection to database
 * @param Container $container :container object
 */
 public function __construct($connexion, Container $container)
 {
 $this->_container = $container;
 $this->_connexion = $connexion;
 $this->_tableTransaction
 = $this->_container->getParameter('ISB_TRANSACTIONS');
 }
 
 
 /**
 * Insert rules object into DB
 *
 * @return void
 */
 public function insertObjectDB()
 {
 $rules = $this->getRulesFromDB();
 $this->rulesTreatment($rules);
 $this->insertRuleObjectDB($this->_arrayDecisionRuler);
 $this->insertRuleObjectDB($this->_arrayRulesScoreRuler);
 }
 
 
 /**
 * Get all rules from the DB
 *
 * @return Array
 */
 public function getRulesFromDB()
 {
 $sql = 'Select *
 FROM ' . $this->_tableTransaction . '.REGLES
 WHERE version = :version
 AND actif = :actif';
 
 $queryFlux = $this->_connexion->prepare($sql);
 $queryFlux->bindValue("version", 0);
 $queryFlux->bindValue("actif", 1);
 $queryFlux->execute();
 $rules = $queryFlux->fetchAll();
 
 return $rules;
 }
 
 
 /**
 * Separate the rules in 2 categories, for simple rules & decision
 *
 * @param Array $rules :the Array of the rules
 *
 * @return void
 */
 public function rulesTreatment($rules)
 {
 $arrayJsonRuler = array();
 $arrayDecisionRuler = array();
 foreach ($rules as $rule) {
 if ($rule['UTILISATION_SCORE'] == 1) {
 $arrayJsonRuler[]
 = $this->returnArrayRuler(
 $rule['JSON'],
 $rule['EMPLACEMENT'],
 $rule['NOM'],
 $rule['ID'],
 $rule['MOTIF'],
 $rule['SCORE']
 );
 } elseif ($rule['UTILISATION_SCORE'] == 2) {
 $arrayDecisionRuler[]
 = $this->returnArrayRuler(
 $rule['JSON'],
 $rule['EMPLACEMENT'],
 $rule['NOM'],
 $rule['ID'],
 $rule['MOTIF'],
 $rule['SCORE']
 );
 }
 }
 $this->_arrayRulesScoreRuler = $arrayJsonRuler;
 $this->_arrayDecisionRuler = $arrayDecisionRuler;
 }
 
 /**
 * Insert the object of rules into DB
 *
 * @param Array $rules :the json of rules to insert the object
 *
 * @return void;
 */
 public function insertRuleObjectDB($rules)
 {
 $jsonToRuleBuilder
 = $this->_container->get('JsonToRulerBuilder');
 
 foreach ($rules as $rule) {
 $ruleBuilder = new RuleBuilder();
 $parameters
 = $jsonToRuleBuilder->jsonToRuleBuilder(
 $rule,
 $ruleBuilder
 );
 
 
 $serializeRules = serialize($rule);
 $encodeRules = base64_encode($serializeRules);
 
 $serializeParameters = serialize($parameters);
 $encodeParameters = (base64_encode($serializeParameters));
 
 $sql = "DECLARE
 vClobVal varchar2(32767) := '$encodeParameters';
 vClobVal1 varchar2(32767) := '$encodeRules';
 begin ";
 
 $sql .= "UPDATE "
 . $this->_tableTransaction
 . ".REGLES SET PARAMETERS = vClobVal,
 RULES = vClobVal1 WHERE ID = '"
 . utf8_decode($rule[0]['id']) . "'; end;";
 
 
 $query = $this->_connexion->prepare($sql);
 $query->execute();
 }
 }
 
 
 /**
 * Convert the rules into an array
 *
 * @param string $json_ruler :the rule to convert
 * @param string $emplacement :the emplacement of the rule
 * @param string $name :the name of the rule
 * @param string $id :the name of the rule
 * @param string $motif :the motif of the rule
 * @param string $score :the score of the rule
 *
 * @return Array
 */
 public function returnArrayRuler(
 $json_ruler,
 $emplacement = '',
 $name = '',
 $id = '',
 $motif = '',
 $score = ''
 ) {
 $jsonInfosRule
 = ',"emplacement":"'
 . $emplacement
 . '","nom":"'
 . $name
 . '","id":"'
 . $id
 . '","motif":"'
 . $motif
 . '","score":"'
 . $score . '"}]';
 $jsonRuler = substr($json_ruler, 0, -2) . $jsonInfosRule;
 $objectRuler = json_decode($jsonRuler);
 $arrayRuler = json_decode(json_encode($objectRuler), true);
 
 return $arrayRuler;
 }
 }
 Plus de 450 lignes de codes 15 lignes de code Le code : public function rulesTreatment($rules, $context, $isbref)
 {
 foreach ($rules as $expression) {
 try {
 $return
 = $this->expressionLanguage->evaluate(
 $expression,
 $context
 ); if ($return === true) { //On déclenche la règle }
 } catch (SyntaxError $e) {
 }
 }
 }

Slide 29

Slide 29 text

temps en ms 0 200 400 600 800 Avant Après ms ms Les perfs :

Slide 30

Slide 30 text

One more thing…

Slide 31

Slide 31 text

COIFFARD Xavier ABBAS Hussein DEMOOO !

Slide 32

Slide 32 text

Bilan ! ● Ca va vite ! ● Le métier est content ● To be continued…

Slide 33

Slide 33 text

COIFFARD Xavier ABBAS Hussein Questions ?