mercredi 14 juin 2017

Prestashop add keywords from tags for products

Here is a little code to be added to header.tpl if you want to add the meta keywords ofr a product page

 

  {if isset($product->tags) AND $product->tags}
   {if isset($product->tags[$cart->id_lang]) AND $product->tags[$cart->id_lang]}
    <meta name="keywords" content="
     {foreach from=$product->tags[$cart->id_lang] item=foo}
     {$foo|escape:'html':'UTF-8'};
     {/foreach}
     " />
   {/if}  
  {/if}

mercredi 13 juillet 2016

Prestashop combinations prices and images

great snippet

 
  SELECT 
    p.id_product,
    pa.reference,
    pl.name,
    @id_image := ifnull(pai.id_image, pi.id_image) as id_image,
    concat('http://',
            ifnull(shop_domain.value, 'domain'),
            '/img/p/',
            if(CHAR_LENGTH(@id_image) >= 5,
                concat(SUBSTRING(@id_image from - 5 FOR 1), '/'),
                ''),
            if(CHAR_LENGTH(@id_image) >= 4,
                concat(SUBSTRING(@id_image from - 4 FOR 1), '/'),
                ''),
            if(CHAR_LENGTH(@id_image) >= 3,
                concat(SUBSTRING(@id_image from - 3 FOR 1), '/'),
                ''),
            if(CHAR_LENGTH(@id_image) >= 2,
                concat(SUBSTRING(@id_image from - 2 FOR 1), '/'),
                ''),
            if(CHAR_LENGTH(@id_image) >= 1,
                concat(SUBSTRING(@id_image from - 1 FOR 1), '/'),
                ''),
            @id_image,
            '.jpg') as image_url,
    GROUP_CONCAT(DISTINCT (pal.name)
        SEPARATOR ', ') as combination,
    ROUND(p.price, 2) as price,
    p.active,
    pq.quantity
FROM
    ps_product p
        LEFT JOIN
    ps_product_attribute pa ON (p.id_product = pa.id_product)
        LEFT JOIN
    ps_stock_available pq ON (p.id_product = pq.id_product
        AND pa.id_product_attribute = pq.id_product_attribute)
        LEFT JOIN
    ps_product_lang pl ON (p.id_product = pl.id_product)
        LEFT JOIN
    ps_product_attribute_combination pac ON (pa.id_product_attribute = pac.id_product_attribute)
        LEFT JOIN
    ps_attribute_lang pal ON (pac.id_attribute = pal.id_attribute)
        LEFT JOIN
    ps_product_attribute_image pai ON (pa.id_product_attribute = pai.id_product_attribute)
        LEFT JOIN
    ps_image pi ON p.id_product = pi.id_product
        LEFT JOIN
    ps_configuration shop_domain ON shop_domain.name = 'PS_SHOP_DOMAIN'
WHERE
    pl.id_lang = (
        SELECT 
            id_lang
        FROM
            ps_lang
        ORDER BY id_lang ASC
        LIMIT 1
    )
        AND
    pal.id_lang = pl.id_lang
GROUP BY pa.reference
ORDER BY p.id_product , pac.id_attribute;


dimanche 24 avril 2016

Php script to to close unclosed HTML tags in text

When displaying the few words or characters of a post,
we usually use
 
echo substr($string,0,numberOfChars);


The problem is that if the text was extracted from a rich edited post, some unclosed tags will impact the display of your site, since the extracted characters may contain unclosed HTML tags.

The solution is to use that little code found at
http://stackoverflow.com/questions/3059398/how-to-close-unclosed-html-tags
written by
https://stackoverflow.com/users/342999/kamal

That's great

 
function closetags($html) {

    preg_match_all('#<(?!meta|img|br|hr|input\b)\b([a-z]+)(?: .*)?(?<![/|/ ])>#iU', $html, $result);

    $openedtags = $result[1];

    preg_match_all('#</([a-z]+)>#iU', $html, $result);

    $closedtags = $result[1];

    $len_opened = count($openedtags);

    if (count($closedtags) == $len_opened) {

        return $html;

    }

    $openedtags = array_reverse($openedtags);

    for ($i=0; $i < $len_opened; $i++) {

        if (!in_array($openedtags[$i], $closedtags)) {

            $html .= '</'.$openedtags[$i].'>';

        } else {

            unset($closedtags[array_search($openedtags[$i], $closedtags)]);

        }

    }

    return $html;

} 

jeudi 25 février 2016

Prestashop Affectation tous les produits à un entrepot | Warehouse product affectation

In prestashop if we want to affect all products to one warehouse automatically, we ca use this little snippet.
Note that you have to backup warehouse_product_location table before any data modification.
You have to change id_warehouse=> XXX with the new warehouse id
The script is launches two instructions : 1- Affect simple product to warehouse then 2- Affect products with combinations to warehouse
 
<?php
/* 
 * Wassim JIED
 * coderspirit.blogspot.com (2016)
 * Well made in 619
 */ header("Cache-Control: no-cache, must-revalidate");
     require_once(dirname(__FILE__).'/config/config.inc.php');
  function processMoveToWareHouse()
 {      
  
   Logger::addLog('Affecting warehouses',1);
   $sql = 'SELECT id_product FROM '._DB_PREFIX_.'product';
   echo 'running : '.$sql .'
';
   if ($results = Db::getInstance()->ExecuteS($sql))
   foreach ($results as $row){
    Db::getInstance()->insert('warehouse_product_location', array(
    'id_product' => (int)$row['id_product'],
    'id_product_attribute' => 0,
    'id_warehouse'=> 2
    ));
   }
   Logger::addLog('Done with products without combinations ... gonna continue',1);
   
   
   $sql = 'SELECT id_product,id_product_attribute FROM '._DB_PREFIX_.'product_attribute';
   echo 'running : '.$sql .'
';
   if ($results = Db::getInstance()->ExecuteS($sql))
   foreach ($results as $row){
    Db::getInstance()->insert('warehouse_product_location', array(
    'id_product' => (int)$row['id_product'],
    'id_product_attribute' => (int)$row['id_product_attribute'],
    'id_warehouse'=> 2
    ));
   }
   Logger::addLog('Done with warehouses... going to die',1);


  
  die('OK');
     }
  processMoveToWareHouse();
  
Note lase that this script can be run on mysql script window using this command:
 
  insert into `ps_warehouse_product` (`id_product`,`id_product_attribute`,`id_warehouse`) 
    select p.id_product,0,2 from ps_product_attribute p;
insert into `ps_warehouse_product_location` (`id_product`,`id_product_attribute`,`id_warehouse`) select pa.id_product,pa.id_product_attribute,2 from ps_product_attribute pa ;

dimanche 23 août 2015

Phonetic search of arabic names latin spelled

The goal of this article is to give an approach to search record on a latin database of recrods containing arab names / surnames,  of course, there is no problem if the records were written in arabic letter encoded in a charset that supports this language such ar8mswin1256 charset recommended for oracle databases, but when we phonetic translate an arabic name and spell it in latin chars, that's another kind of non bijective job,
Let's take a look:

Mohammed (salla Allah Alyhi wa sallam) can be spelled :
   1- Mohamed
   2- Muhamed
   3- Mouhamed
   4- Mouhammed
   5- Med (Abusive spelling in north Afraica countries ex french occupied  countries)
   6- Mohd(Same a 5)

you must note that in arabic theres there is often a successive double consonant, and those who don't respect phonetic translation can omit the second char, even if the word become incorrect in certain case
eg:
 'S' between two vowels that become 'Z'

Prohet's name is a very frequent name in Muslim countries, we can say then that's a particular case?
Let's get another look


i'll take now my name and others
Wassim, can be spelled:
   1- Ouassim
   2- Wessim
   3- Ouessim
   4- Wassime
   5- Ouassime
   6- Ouessime

And that for all names with 'W' char, we can replace the W by ou and we have the same name.
We can note also that the 'E' char at the end of the word often doesn't metter

Tayeb can be spelled:
   1-Taieb
We can note that 'Y' char and 'I' (also 'EE' in middle east culture ) have the same phonetic effect.
then we can spell
Sami-->Samy (don't forget Sammy -double consonant - evoked earlier)
Rym -->Rim

etcetera etcetera...

Let's now comeback to the approach that can be adapted to resolve the problem.

First of all, we must establish our names dictionary, not a real dictionary because arabic language has the must vast dictionary with 12 000 000 word vs 600 000 word in english **, but let's say that we will build a function that will transform an arabic name on another word that we can exploit later by a simple matching with the result of the same function executed on the searched for name.

behind sentences
We'll build function f
for each name of our database
 f(name) = name' stored somewhere

select from database rows with condition ; f(searchedForName) = name'

 f(name) = name' stored somewhere ??? why??
storing the result will be very useful because the result is always the same for records stored in our database, we win a time and money by ding that until the change of our function f we must re-execute
the function on our population.

function f(name):
Considering our parameter name which is a String, an intelligent algorithm will consider that string a char sequence, other ways we will be in the case **.We'll transform that char sequence to another one which we will respect our universal rules, and unlike ** the cardinality of  rules set is an infinitesimal (x 10) in front of arabic words set count (12 000 000)
Our algorithm will take a decision and return a string that can be blank if needed for all incoming letters in our world: Typical recursive behavior, the normalized name will be the concatenation of results of recursive call on the word.

We remark also that the pseudo strings generated during recursive call, needs some extra information:
specially previous char 'in consonant case (double char) or other cases' end sometimes we need the next char if it exists.


ALGORITHM String getArabicPhoneticEquivalent (String name , Int depth) RETURN String

DECLARE
   String toReturn;
   char nextChar,currentChar;
BEGIN

IF StringLength(name) == depth THEN //Condition to break recursivity
    return "";
END IF;

toReturn =""; // Must be set to empty string

IF depth == 0 THEN
     name =  StringLowerCase(name);//Affects lowercase to input
     name =  cleanSpecialChars(name); //Transfom some unsupported letters
     toReturn  = getSpecialNames(name);// Tests for special names
END IF;


IF toReturn != "" THEN // Case we have special name, no need to continue
   return toReturn;
END IF;

currentChar = name[depth];

IF StringLength(name) > depth THEN
     nextChar = name[depth+1];
ELSE
     nextChar = ' ';
END IF;
depth = depth + 1;
IF nextChar == currentChar THEN //Double letter simulated to one
    return  getArabicPhoneticEquivalent (name , depth);
END IF;

IF consonant(name[depth]) THEN
   
    IF name[depth] == 'h' THEN //Skip h after a consonant
         IF depth > 1 AND consonant(name[depth-1]) THEN
              return  getArabicPhoneticEquivalent (name , depth);
         END IF;
     END IF;
     return StringConcat(getConsonantEquivalent(name[depth],nextChar) , getArabicPhoneticEquivalent (name , depth));
END IF;

IF vowel(name[depth]) THEN
       return StringConcat(getVowelEquivalent(name[depth],nextChar) , getArabicPhoneticEquivalent (name , depth));
END IF;

END ALGORITHM;    

ALGORITHM skipSpecialChars(String name) RETURN String
BEGIN
  name = StringReplaceAllSequences("w","ou");
  name = StringReplaceAllSequences("ï","i");
  name = StringReplaceAllSequences("î","i");
  name = StringReplaceAllSequences("ô","o");
  name = StringReplaceAllSequences("é","e");
  name = StringReplaceAllSequences("è","e");
  name = StringReplaceAllSequences("ê","e");
  name = StringReplaceAllSequences("à","a");
  name = StringReplaceAllSequences("ç","c");
  return name;
END ALGORITHM;

ALGORITHM getSpecialNames(String name) RETURN String
BEGIN
   IF name == "med" OR name =="mohd" THEN
       return 'mouhamed';
   END IF;

   return "";
END ALGORITHM;

ALGORITHM getConsonantEquivalent(char currentChar, char nextChar) RETURN String
BEGIN
IF currentChar == 'c' THEN
    IF  consonant(nextChar)THEN
          return "k";
    ELSEIF vowel(nextChar) THEN
          return "s"
    END IF;
END IF;
return currentChar+"";
END ALGORITHM

ALGORITHM getVowelEquivalent(char currentChar, char nextChar) RETURN String
BEGIN
IF currentChar == 'y' THEN
     return "i";
END IF;
IF currentChar == 'e' THEN
     return "a";
END IF;
return currentChar+"";
END ALGORITHM;

Note that we can make this algorithm more performant by adding additional controls
such as:
The abreviation of ben 'b'
The 'el' similar to 'al'

In the PLSQL code below i've added these controls and some others
'Code may be more up te date than algorithm ( no worry the spirit is kept)'

 
create or replace 
package body PKG_SEARCH is
  -------------------------------------------------------------
  -- Teste les voyelles
  -- @return boolean
  -------------------------------------------------------------
  function f_is_vowel(c in char) return boolean is
  begin
     if c in ('a','e','i','o','y','u') then 
        return true;
     else
        return false;
     end if;   
  end;
    -------------------------------------------------------------
  -- Teste les consonnes
  -- @return boolean
  -------------------------------------------------------------
  function f_is_consonent(c in char) return boolean is
  begin
     if c in ('b','c','d','f','g','h','j','k','l','m','n','p','q','r','s','t','v','w','x','z') then      
        return true;
     else
        return false;
     end if;     
  end;
  -------------------------------------------------------------
  -- Teste les consonnes
  -- @return boolean
  -------------------------------------------------------------
  function  f_special_chars(a_name in out varchar) return varchar is
  begin    
    a_name := replace(a_name,'ï','i');
    a_name := replace(a_name,'î','i');
    a_name := replace(a_name,'ô','o');
    a_name := replace(a_name,'é','e');
    a_name := replace(a_name,'è','e');
    a_name := replace(a_name,'ê','e');
    a_name := replace(a_name,'à','a');
    a_name := replace(a_name,'ç','c');    
    a_name := replace(a_name,'w','o');    
    a_name := replace(a_name,'u','o');   
    a_name := replace(a_name,'y','i');   
    a_name := replace(a_name,' b ','ben');   
    a_name := replace(a_name,' b','ben');   
    a_name := replace(a_name,' al ',' al');   
    if (length(a_name) >1 and substr(a_name,1,2) = 'b ') or (length(a_name) >3 and substr(a_name,1,2) = 'ben ')  then
          a_name := 'ben '|| substr(a_name,2);
    end if;
    if length(a_name) >2 and substr(a_name,1,2) = 'el' then
          a_name := 'al'|| substr(a_name,3);
    end if;
    return a_name;  
  end;
  -------------------------------------------------------------
  -- Traite les noms speciaux
  -- @return boolean
  -------------------------------------------------------------
  function f_special_names(a_name in varchar) return  varchar is
  begin
     if a_name = 'med' or a_name ='mohd' then
       return 'mouhamed';
     end if;  
     return '';
  end;
  -------------------------------------------------------------
  -- Retourne la chaine de caractère qui correspond à la consonne en question
  -- @return boolean
  -------------------------------------------------------------
function f_consonant_equivalent(currentChar in char, nextChar in char) return  varchar is
  begin
  if currentChar = 'c' THEN
      if  f_is_consonent(nextChar)THEN 
            return 'k';
      elsif f_is_vowel(nextChar) THEN
            return 's';
      end if;
  end if;
  if currentChar = 'd' THEN
        if  f_is_consonent(nextChar)THEN
          return '';
        end if;
  end if;  
  return currentChar;
end;
  -------------------------------------------------------------
  -- Retourne la chaine de caractère qui correspond à la voyelle en question
  -- @return boolean
  -------------------------------------------------------------
function f_vowel_equivalent(currentChar in char, nextChar in char) return varchar is
begin  
  if currentChar = 'e' then
      if  (nextChar=' ') then
          return '';
      else    
          return 'a';
      end if;
  end if;    
  return currentChar;
end; 

  -------------------------------------------------------------
  -- Retourne l'equivalent phonetic
  -- Main function 
  -- @return boolean
  -------------------------------------------------------------
function f_arabic_phonetic_aquivalent (a_name in out varchar, depth in out number) return varchar is
   toReturn varchar(256);
   nextChar char;
   currentChar char;
   nextDepth number;
BEGIN

IF depth = 1 THEN
     a_name :=  lower(a_name);
     a_name :=  f_special_chars(a_name);  
END IF;

toReturn  := f_special_names(a_name);
IF toReturn <> '' THEN 
   return toReturn;
END IF;

IF length(a_name) < depth THEN 
    return '';
END IF;

toReturn :=''; 
nextDepth := depth + 1;

currentChar := substr(a_name,depth,1);
IF currentChar = ' ' THEN
    return  ' '||f_arabic_phonetic_aquivalent (a_name , nextDepth);
END IF;
IF length(a_name) > depth THEN
     nextChar := substr(a_name,nextDepth,1);      
ELSE
     nextChar := ' ';
END IF;

IF nextChar = currentChar THEN 
    return  f_arabic_phonetic_aquivalent (a_name , nextDepth);
END IF;

IF f_is_consonent(substr(a_name,depth,1)) THEN    
    IF substr(a_name,depth,1) = 'h' THEN 
         IF depth > 1 AND f_is_consonent(substr(a_name,depth-1,1)) THEN
              return  f_arabic_phonetic_aquivalent (a_name , nextDepth);
         END IF;
     END IF;
     return concat(f_consonant_equivalent(substr(a_name,depth,1),nextChar) , f_arabic_phonetic_aquivalent (a_name ,nextDepth));
END IF;

IF f_is_vowel(substr(a_name,depth,1)) THEN
       return concat(f_vowel_equivalent(substr(a_name,depth,1),nextChar) , f_arabic_phonetic_aquivalent (a_name , nextDepth));
END IF;
return NULL;
END ; 
----------------------------------------------------------------
function f_pkg_runner (a_name in out varchar) return varchar is
toReturn varchar2(256);
depth number;
begin
   depth :=1;
   toReturn := f_arabic_phonetic_aquivalent (a_name, depth);
   toReturn := replace(toReturn,' mohd ','mouhamad');
   toReturn := replace(toReturn,' med ','mouhamad');
   if toReturn = 'mohd' or toReturn = 'med'then
      return 'mouhamad';
   end if;   
   return toReturn;
end;
----------------------------------------------------------------
function f_pkg_tester() return varchar is
sampleSurname varchar(256);

begin
      sampleSurname  := 'wassim';
      sampleSurname   := PKG_SEARCH .f_pkg_runner(sampleSurname);
      dbms_output.put_line(sampleSurname);
      return sampleSurname;
 
end;
end PKG_SEARCH ;
This will output oasim