Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Expression language Symfony live

Expression language Symfony live

Hussein Abbas

April 10, 2016
Tweet

Other Decks in Programming

Transcript

  1. 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
  2. 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!
  3. • Analyser des centaines de datas • Déclencher un traitement

    statistique • Scorer une transaction: Go/Nogo livraison Un moteur de règle ?
  4. Un choix constestable… • Choix de Ruler contestable • Coder

    vite vite • Plus personne après 100 jours
  5. • Dette technique • Construire à chaque fois le même

    objet (temps de traitement énorme) • Petit projet opensource Problématiques techniques
  6. 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….
  7. • Component Symfony symfony/expression-language • Evaluer/Compiler des expressions • Basé

    sur l’expression syntaxe de twig • Simple à mettre en place Expression langage
  8. Exemple class Order { public $amount; } $order = new

    Order(); $order->amount = 150; $language->evaluate( ‘order.amount in 100..200', array( 'order' => $order, ) );
  9. Est-ce la bonne solution? • Répond à nos besoins •

    Valider par les métiers • Extensible
  10. 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
  11. 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);
 }
 }
  12. [
 {
 "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:
  13. <?php
 
 
 namespace WS\RESTBundle\Services\jsonBuilder;
 
 use Symfony\Component\DependencyInjection\ContainerInterface as Container;


    use Ruler\RuleBuilder;
 
 /**
 * Class InsertRulesObjectDB
 *
 * @category Treatment_Standard_Data
 * @package WS\RESTBundle\Services\jsonBuilder
 * @author deploiement <[email protected]>
 * @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) {
 }
 }
 }
  14. Bilan ! • Ca va vite ! • Le métier

    est content • To be continued…