예제 #1
0
 /**
  * to create a token from source
  * @param string $source
  * @return fx_template_token
  */
 public static function create($source)
 {
     if (!preg_match('~^\\{~', $source)) {
         $type = 'single';
         $name = 'code';
         $props['value'] = $source;
         return new Token($name, $type, $props);
     }
     $props = array();
     $source = trim($source, '{}');
     //preg_replace("~^\{|\}$~", '', $source);
     $is_close = preg_match('~^\\/~', $source);
     $source = ltrim($source, '/');
     $first_char = substr($source, 0, 1);
     $is_var = in_array($first_char, array('$', '%'));
     $is_param = false;
     if ($is_var && !$is_close) {
         $ep = new ExpressionParser();
         $name = $ep->findVarName(trim($source, '/ '));
     } elseif ($first_char === '@') {
         $name = 'param';
         $source = preg_replace_callback("~^@([^\\s]+)~", function ($m) use(&$props) {
             $props['name'] = $m[1];
             return '';
         }, $source);
         $source = trim($source);
         $is_param = true;
     } else {
         preg_match("~^[^\\s\\/\\|}]+~", $source, $name);
         $name = $name[0];
     }
     if (!$is_param) {
         $source = substr($source, strlen($name));
     }
     if ($name == 'apply') {
         $name = 'call';
         $props['apply'] = true;
     } elseif ($name == 'default') {
         $name = 'set';
         $props['default'] = 'true';
     }
     if ($name == 'wtf') {
         $name = 'help';
     }
     $type_info = self::getTokenInfo($name);
     $token_close_type = isset($type_info['type']) ? $type_info['type'] : null;
     //if (preg_match("~^[\\\$%]~", $name, $var_marker)) {
     if ($is_var) {
         $props['id'] = preg_replace("~^[\\\$%]~", '', $name);
         $props['var_type'] = $first_char == '%' ? 'visual' : 'data';
         $name = 'var';
     }
     if ($name == 'with-each') {
         $name = 'with_each';
     }
     if (preg_match("~\\/\$~", $source)) {
         $type = 'single';
         $source = preg_replace("~/\$~", '', $source);
     } elseif ($is_close) {
         $type = 'close';
     } elseif ($token_close_type == 'single') {
         $type = 'single';
     } elseif ($token_close_type == 'double') {
         $type = 'open';
     } else {
         $type = 'unknown';
     }
     if ($name === 'preset' && $type !== 'close' && !preg_match("~id\\s*?=~", $source)) {
         $source = preg_replace_callback("~([a-z0-9\\.\\_\\-\\:]+)\\#?([a-z0-9_-]+)?~", function ($m) {
             return 'template="' . trim($m[1]) . '" id="' . trim($m[2]) . '"';
         }, $source, 1);
     }
     if (($name == 'if' || $name == 'elseif') && $type != 'close' && !preg_match('~test=~', $source)) {
         $props['test'] = $source;
     } elseif ($name == 'call' && $type != 'close' && !preg_match('~id=~', $source)) {
         $source = trim($source);
         $parts = preg_split("~\\s+(with|each)\\s+~", $source, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
         $props['id'] = array_shift($parts);
         foreach ($parts as $prop_num => $prop) {
             if ($prop_num % 2 == 0 && isset($parts[$prop_num + 1])) {
                 $props[$prop] = $parts[$prop_num + 1];
             }
         }
     } elseif (($name == 'each' || $name == 'with_each') && $type != 'close' && !preg_match('~select=~', $source)) {
         $props['select'] = trim($source);
     } elseif ($name == 'set') {
         $parts = explode("=", $source, 2);
         $props['var'] = trim($parts[0]);
         if (isset($parts[1])) {
             $props['value'] = trim($parts[1]);
         }
     } elseif ($name == 'with' && !preg_match("~select=~", $source)) {
         $props['select'] = trim($source);
     } else {
         $props = array_merge($props, TokenAttParser::getAtts($source));
         if ($name == 'var' && preg_match("~^\\s*\\|~", $source)) {
             $props['modifiers'] = self::getVarModifiers($source);
         } elseif (isset($props['modifiers']) && is_string($props['modifiers'])) {
             $props['modifiers'] = json_decode($props['modifiers'], true);
         }
     }
     if ($name == 'each' || $name == 'with_each') {
         $arr_id_parts = null;
         $item_key = null;
         $item_alias = null;
         $arr_id = isset($props['select']) ? $props['select'] : null;
         if (preg_match("~(.+?)\\sas\\s(.+)\$~", $arr_id, $arr_id_parts)) {
             $arr_id = trim($arr_id_parts[1]);
             $as_parts = explode("=>", $arr_id_parts[2]);
             if (count($as_parts) == 2) {
                 $item_key = trim($as_parts[0]);
                 $item_alias = trim($as_parts[1]);
             } else {
                 $item_alias = trim($as_parts[0]);
             }
         }
         $props['select'] = $arr_id;
         $props['as'] = $item_alias;
         $props['key'] = $item_key;
     }
     return new self($name, $type, $props);
 }
예제 #2
0
파일: Html.php 프로젝트: floxim/floxim
 public function transformToFloxim()
 {
     $tokens = $this->tokenize();
     $tree = $this->makeTree($tokens);
     $unnamed_replaces = array();
     $tree->apply(function (HtmlToken $n) use(&$unnamed_replaces) {
         if ($n->name == 'text') {
             return;
         }
         if (preg_match('~\\{[\\%|\\$]~', $n->source)) {
             $n->source = Html::parseFloximVarsInAtts($n->source);
         }
         $subroot = $n->hasAttribute('fx:omit') ? '' : ' subroot="true"';
         if (($n->name == 'script' || $n->name == 'style') && !$n->hasAttribute('fx:raw')) {
             $n->setAttribute('fx:raw', 'true');
         }
         if ($n->hasAttribute('fx:raw')) {
             $raw_value = $n->getAttribute('fx:raw');
             if ($raw_value != 'false') {
                 $n->addChildFirst(HtmlToken::create('{raw}'));
                 $n->addChild(HtmlToken::create('{/raw}'));
             }
             $n->removeAttribute('fx:raw');
         }
         if ($n->name == 'meta' && ($layout_id = $n->getAttribute('fx:layout'))) {
             $layout_name = $n->getAttribute('fx:name');
             $tpl_tag = '{template id="' . $layout_id . '" name="' . $layout_name . '" of="layout:show"}';
             $tpl_tag .= '{apply id="_layout_body"}';
             $content = $n->getAttribute('content');
             $vars = explode(",", $content);
             foreach ($vars as $var) {
                 $var = trim($var);
                 $negative = false;
                 if (preg_match("~^!~", $var)) {
                     $negative = true;
                     $var = preg_replace("~^!~", '', $var);
                 }
                 $tpl_tag .= '{$' . $var . ' select="' . ($negative ? 'false' : 'true') . '" /}';
             }
             $tpl_tag .= '{/call}{/template}';
             $n->parent->addChildBefore(HtmlToken::create($tpl_tag), $n);
             $n->remove();
             return;
         }
         if ($fx_replace = $n->getAttribute('fx:replace')) {
             $replace_atts = explode(",", $fx_replace);
             foreach ($replace_atts as $replace_att) {
                 if (!isset($unnamed_replaces[$replace_att])) {
                     $unnamed_replaces[$replace_att] = 0;
                 }
                 $var_name = 'replace_' . $replace_att . '_' . $unnamed_replaces[$replace_att];
                 $unnamed_replaces[$replace_att]++;
                 $default_val = $n->getAttribute($replace_att);
                 switch ($replace_att) {
                     case 'src':
                         $var_title = fx::alang('Picture', 'system');
                         break;
                     case 'href':
                         $var_title = fx::alang('Link', 'system');
                         break;
                     default:
                         $var_title = $replace_att;
                         break;
                 }
                 $n->setAttribute($replace_att, '{%' . $var_name . ' title="' . $var_title . '"}' . $default_val . '{/%' . $var_name . '}');
                 $n->removeAttribute('fx:replace');
             }
         }
         if ($var_name = $n->getAttribute('fx:var')) {
             if (!preg_match("~^[\$\\%]~", $var_name)) {
                 $var_name = '%' . $var_name;
             }
             $n->addChildFirst(HtmlToken::create('{' . $var_name . '}'));
             $n->addChild(HtmlToken::create('{/' . $var_name . '}'));
             $n->removeAttribute('fx:var');
         }
         $tpl_id = $n->getAttribute('fx:template');
         $macro_id = $n->getAttribute('fx:macro');
         if ($tpl_id || $macro_id) {
             if ($macro_id) {
                 $tpl_id = $macro_id;
             }
             if (preg_match("~\\[(.+?)\\]~s", $tpl_id, $tpl_test)) {
                 $tpl_test = preg_replace("~[\r\n]~", ' ', $tpl_test[1]);
                 $tpl_id = preg_replace("~\\[.+?\\]~s", '', $tpl_id);
             }
             $tpl_macro_tag = '{template id="' . $tpl_id . '" ';
             if ($macro_id) {
                 $tpl_macro_tag .= ' is_macro="true" ';
             }
             $tpl_macro_tag .= $subroot;
             if ($n->hasAttribute('fx:abstract')) {
                 $tpl_macro_tag .= ' is_abstract="true" ';
                 $n->removeAttribute('fx:abstract');
             }
             if ($tpl_for = $n->getAttribute('fx:of')) {
                 $tpl_macro_tag .= ' of="' . $tpl_for . '"';
                 $n->removeAttribute('fx:of');
             }
             if ($tpl_test || ($tpl_test = $n->getAttribute('fx:test'))) {
                 $tpl_macro_tag .= ' test="' . $tpl_test . '" ';
                 $n->removeAttribute('fx:test');
             }
             if ($tpl_name = $n->getAttribute('fx:name')) {
                 $tpl_macro_tag .= ' name="' . $tpl_name . '"';
                 $n->removeAttribute('fx:name');
             }
             if ($n->offset && $n->end_offset) {
                 $tpl_macro_tag .= ' offset="' . $n->offset[0] . ',' . $n->end_offset[1] . '" ';
             }
             if ($tpl_size = $n->getAttribute('fx:size')) {
                 $tpl_macro_tag .= ' size="' . $tpl_size . '" ';
                 $n->removeAttribute('fx:size');
             }
             if ($tpl_suit = $n->getAttribute('fx:suit')) {
                 $tpl_macro_tag .= ' suit="' . $tpl_suit . '"';
                 $n->removeAttribute('fx:suit');
             }
             if ($n->hasAttribute('fx:priority')) {
                 $tpl_priority = $n->getAttribute('fx:priority');
                 $tpl_macro_tag .= ' priority="' . $tpl_priority . '" ';
                 $n->removeAttribute('fx:priority');
             }
             $tpl_macro_tag .= '}';
             $n->wrap($tpl_macro_tag, '{/template}');
             $n->removeAttribute('fx:template');
             $n->removeAttribute('fx:macro');
         }
         if ($n->hasAttribute('fx:each')) {
             $each_id = $n->getAttribute('fx:each');
             $each_id = trim($each_id, '{}');
             $each_id = str_replace('"', '\\"', $each_id);
             $each_macro_tag = '{each ';
             $each_macro_tag .= $subroot;
             $each_macro_tag .= ' select="' . $each_id . '"';
             if ($each_as = $n->getAttribute('fx:as')) {
                 $each_macro_tag .= ' as="' . $each_as . '"';
                 $n->removeAttribute('fx:as');
             }
             if ($each_key = $n->getAttribute('fx:key')) {
                 $each_macro_tag .= ' key="' . $each_key . '"';
                 $n->removeAttribute('fx:key');
             }
             if ($prefix = $n->getAttribute('fx:prefix')) {
                 $each_macro_tag .= ' prefix="' . $prefix . '"';
                 $n->removeAttribute('fx:prefix');
             }
             if ($extract = $n->getAttribute('fx:extract')) {
                 $each_macro_tag .= ' extract="' . $extract . '"';
                 $n->removeAttribute('fx:extract');
             }
             if ($separator = $n->getAttribute('fx:separator')) {
                 $each_macro_tag .= ' separator="' . $separator . '"';
                 $n->removeAttribute('fx:separator');
             }
             $each_macro_tag .= '}';
             $n->wrap($each_macro_tag, '{/each}');
             $n->removeAttribute('fx:each');
         }
         if ($area_id = $n->getAttribute('fx:area')) {
             $n->removeAttribute('fx:area');
             $area = '{area id="' . $area_id . '" ';
             if ($area_size = $n->getAttribute('fx:size')) {
                 $area .= 'size="' . $area_size . '" ';
                 $n->removeAttribute('fx:size');
             } elseif ($area_size = $n->getAttribute('fx:area-size')) {
                 // use when fx:area and fx:template are placed on the same node
                 $area .= 'size="' . $area_size . '" ';
                 $n->removeAttribute('fx:area-size');
             }
             if ($area_suit = $n->getAttribute('fx:suit')) {
                 $area .= 'suit="' . $area_suit . '" ';
                 $n->removeAttribute('fx:suit');
             }
             if ($area_render = $n->getAttribute('fx:area-render')) {
                 $area .= 'render="' . $area_render . '" ';
                 $n->removeAttribute('fx:area-render');
             }
             if ($area_name = $n->getAttribute('fx:area-name')) {
                 $area .= 'name="' . $area_name . '" ';
                 $n->removeAttribute('fx:area-name');
             }
             $area .= '}';
             $n->addChildFirst(HtmlToken::create($area));
             $n->addChild(HtmlToken::create('{/area}'));
         }
         if ($n->hasAttribute('fx:item')) {
             $item_att = $n->getAttribute('fx:item');
             $n->removeAttribute('fx:item');
             $n->wrap('{item' . ($item_att ? ' test="' . $item_att . '"' : '') . $subroot . '}', '{/item}');
         }
         if ($n->hasAttribute('fx:aif')) {
             $if_test = $n->getAttribute('fx:aif');
             $ep = new ExpressionParser();
             $empty_cond = $ep->build($if_test);
             $class_code = '<?php echo (' . $empty_cond . ' ? "" : " fx_view_hidden ");?>';
             $n->addClass($class_code);
             $n->removeAttribute('fx:aif');
             $if_test .= ' || $_is_admin';
             $n->wrap('{if test="' . $if_test . '"}', '{/if}');
         }
         if ($n->hasAttribute('fx:if')) {
             $if_test = $n->getAttribute('fx:if');
             $n->removeAttribute('fx:if');
             $n->wrap('{if test="' . $if_test . '"}', '{/if}');
         }
         if ($with_each = $n->getAttribute('fx:with-each')) {
             $n->removeAttribute('fx:with-each');
             $weach_macro_tag = '{with-each ' . $with_each . '}';
             if ($separator = $n->getAttribute('fx:separator')) {
                 $weach_macro_tag .= '{separator}' . $separator . '{/separator}';
                 $n->removeAttribute('fx:separator');
             }
             $n->wrap($weach_macro_tag, '{/with-each}');
         }
         if ($with = $n->getAttribute('fx:with')) {
             $n->removeAttribute('fx:with');
             $n->wrap('{with select="' . $with . '" ' . $subroot . '}', '{/with}');
         }
         if ($n->hasAttribute('fx:separator')) {
             $n->wrap('{separator}', '{/separator}');
             $n->removeAttribute('fx:separator');
         }
         if ($elseif_test = $n->getAttribute('fx:elseif')) {
             $n->removeAttribute('fx:elseif');
             $n->wrap('{elseif test="' . $elseif_test . '"}', '{/elseif}');
         }
         if ($n->hasAttribute('fx:else')) {
             $n->removeAttribute('fx:else');
             $n->wrap('{else}', '{/else}');
         }
         if ($n->hasAttribute('fx:add')) {
             $add_mode = $n->getAttribute('fx:add');
             $n->removeAttribute('fx:add');
             $n->wrap('<?php $this->pushMode("add", "' . $add_mode . '"); ?>', '<?php $this->popMode("add"); ?>');
         }
         if ($n->hasAttribute('fx:omit')) {
             $omit = $n->getAttribute('fx:omit');
             if (empty($omit) || $omit == 'true') {
                 $omit = true;
             } else {
                 $ep = new ExpressionParser();
                 $omit = $ep->compile($ep->parse($omit));
             }
             $n->omit = $omit;
             $n->removeAttribute('fx:omit');
         }
         if ($n->hasAttribute('fx:e')) {
             $e_value = $n->getAttribute('fx:e');
             $n->addClass('{bem_element}' . $e_value . '{/bem_element}');
             $n->removeAttribute('fx:e');
         }
         if ($n->hasAttribute('fx:b')) {
             $b_value = $n->getAttribute('fx:b');
             $n->addClass('{bem_block}' . $b_value . '{/bem_block}');
             $n->removeAttribute('fx:b');
             $n->parent->addChildAfter(HtmlToken::create('<?php $this->bemStopBlock(); ?>'), $n);
         }
     });
     $res = $tree->serialize();
     //fx::log($res);
     return $res;
 }
예제 #3
0
파일: Compiler.php 프로젝트: floxim/floxim
 protected function tokenCallToCode(Token $token)
 {
     $each = $token->getProp('each');
     if ($each) {
         $each_token = Token::create('{each}');
         $each_token->setProp('select', $each);
         $item = '$' . $this->varialize($each) . '_item';
         $each_token->setProp('as', $item);
         $token->setProp('each', '');
         $each_token->addChild($token);
         return $this->tokenEachToCode($each_token);
     }
     $code = "<?php\n";
     $is_apply = $token->getProp('apply');
     $tpl_name = $token->getProp('id');
     $tpl = '$tpl_' . $this->varialize($tpl_name);
     $call_children = $token->getChildren();
     /*
      * Converted:
      * {call id="wrap"}<div>Something</div>{/call}
      * like this:
      * {call id="wrap"}{var id="content"}<div>Something</div>{/var}{/call}
      */
     $has_content_param = false;
     foreach ($call_children as $call_child) {
         if ($call_child->name == 'code' && $call_child->isEmpty()) {
             continue;
         }
         if ($call_child->name != 'var') {
             $has_content_param = true;
             break;
         }
     }
     if ($has_content_param) {
         $token->clearChildren();
         $var_token = new Token('var', 'single', array('id' => 'content'));
         foreach ($call_children as $call_child) {
             $var_token->addChild($call_child);
         }
         $token->addChild($var_token);
     }
     $with_expr = $token->getProp('with');
     if ($with_expr) {
         $ep = new ExpressionParser();
         $with_expr = $ep->parseWith($with_expr);
     }
     $switch_context = is_array($with_expr) && isset($with_expr['$']);
     // && !$is_apply;
     if ($switch_context) {
         $new_context_expression = $this->parseExpression($with_expr['$']);
     }
     $passed_vars = array();
     if (is_array($with_expr)) {
         foreach ($with_expr as $alias => $var) {
             if ($alias == '$') {
                 continue;
             }
             $passed_vars[trim($alias, '$')] = array('string', $this->parseExpression($var));
         }
     }
     foreach ($token->getChildren() as $param_var_token) {
         // internal call only handle var
         if ($param_var_token->name != 'var') {
             continue;
         }
         $value_to_set = '';
         if ($param_var_token->hasChildren()) {
             // pass the inner html code
             $value_to_set .= "ob_start();\n";
             $value_to_set .= $this->childrenToCode($param_var_token);
             $value_to_set .= "\n";
             $passed_value_type = 'buffer';
         } elseif ($select_att = $param_var_token->getProp('select')) {
             // pass the result of executing the php code
             $value_to_set = self::parseExpression($select_att);
             $passed_value_type = 'string';
         }
         $passed_vars[$param_var_token->getProp('id')] = array($passed_value_type, $value_to_set);
     }
     $switch_context_local = $switch_context && count($passed_vars) > 0;
     if ($is_apply) {
         $context_var = '$context';
     } else {
         if (count($passed_vars) > 0 || $switch_context) {
             $context_var = $tpl . '_context';
             $code .= $context_var . " = new \\Floxim\\Floxim\\Template\\" . fx::config('templates.context_class') . "();\n";
         } else {
             $context_var = 'new \\Floxim\\Floxim\\Template\\' . fx::config('templates.context_class') . '()';
         }
     }
     // switch context to calculate passed vars inside it
     if ($switch_context_local) {
         $code .= '$context->push(' . $new_context_expression . ");\n";
     }
     if (count($passed_vars) > 0) {
         $tpl_passed = $tpl . "_passed";
         $code .= $tpl_passed . " = array();\n";
         foreach ($passed_vars as $passed_var_key => $passed_var) {
             switch ($passed_var[0]) {
                 case 'string':
                 default:
                     $code .= $tpl_passed . "['" . $passed_var_key . "'] = " . $passed_var[1] . ";\n";
                     break;
                 case 'buffer':
                     $code .= $passed_var[1];
                     $code .= $tpl_passed . "['" . $passed_var_key . "'] = ob_get_clean();\n";
             }
         }
         // passed vars calculated, clear context
         if ($switch_context_local) {
             $code .= "\$context->pop();\n";
         }
     }
     if ($switch_context) {
         $code .= $context_var . "->push(" . $new_context_expression . ");\n";
     }
     if (isset($tpl_passed)) {
         $code .= $context_var . "->push(" . $tpl_passed . ", array('transparent' => true));\n";
     }
     // ------------
     $tpl_name_is_expression = !preg_match("~^[a-z0-9_\\,\\.\\:\\@\\#]+\$~", $tpl_name);
     $loader = "\\Floxim\\Floxim\\Template\\Loader";
     // not a plain name
     if ($tpl_name_is_expression) {
         $tpl_name = self::parseExpression($tpl_name);
         $pn = $tpl . '_parsed';
         $code .= $pn . ' = ' . $loader . '::parseTemplateName(' . $tpl_name . ', ' . var_export($this->template_set_name, 1) . ', ' . var_export($this->is_aliased, 1) . ");\n";
         $code .= $tpl . " = ";
         $code .= $loader . "::loadTemplateVariant(" . $pn . '["group"], ' . $pn . '["action"], ' . $context_var . ', ' . $pn . '["forced_group"], ' . $pn . '["tags"]); ' . "\n";
     } else {
         $parsed_name = \Floxim\Floxim\Template\Loader::parseTemplateName($tpl_name, $this->template_set_name, $this->is_aliased);
         foreach ($parsed_name as &$v) {
             $v = var_export($v, 1);
         }
         $code .= $tpl . " = ";
         $code .= $loader . "::loadTemplateVariant(" . $parsed_name['group'] . ", " . $parsed_name['action'] . ", " . $context_var . ", " . $parsed_name['forced_group'] . ', ' . $parsed_name['tags'] . ");\n";
     }
     /*
     if (!preg_match("~[\:\@]~", $tpl_name)) {
        $tpl_name = $this->template_set_name . ":" . $tpl_name;
     }
     
     $tpl_at_parts = explode("@", $tpl_name);
     if (count($tpl_at_parts) === 1) {
         $forced_group = 'null';
         list($set_name, $action_name) = explode(":", $tpl_name);
         // save @ for named ("aliased") template groups (like "@admin")
         if ($set_name === $this->template_set_name && $this->is_aliased) {
             $set_name = '@'.$set_name;
         }
     } else {
         $forced_group = !empty($tpl_at_parts[0]) ? $tpl_at_parts[0] : $this->template_set_name;
         $action_parts = explode(":", $tpl_at_parts[1]);
         if (count($action_parts) === 1) {
                 array_unshift($action_parts, $forced_group);
         }
         list($set_name, $action_name) = $action_parts;
         $forced_group = "'".$forced_group."'";
     }
     $tag_parts = explode("#", $action_name);
     if (count($tag_parts) > 1) {
         $action_name = $tag_parts[0];
         $tags = "array('".join("', '", explode(",", $tag_parts[1]))."')";
     } else {
         $tags = 'null';
     }
     */
     $code .= "if ( " . $tpl . " ) {\n";
     $code .= "echo " . $tpl . "->setParent(\$this)->render();\n";
     if ($subroot_var = $token->getProp('extract_subroot')) {
         $code .= $subroot_var . " = " . $tpl . "->is_subroot;\n";
     }
     $code .= "}\n";
     // ------------
     // clear vars passed into child template from current context
     if ($is_apply && count($passed_vars) > 0) {
         $code .= "\$context->pop();\n";
     }
     // clear context object
     if ($is_apply && $switch_context) {
         $code .= "\$context->pop();\n";
     }
     $code .= "\n?>";
     return $code;
 }