├── .modman ├── .basedir └── Hackathon_React │ ├── src │ └── app │ │ ├── etc │ │ └── modules │ │ │ └── Hackathon_React.xml │ │ ├── code │ │ ├── community │ │ │ └── Hackathon │ │ │ │ └── React │ │ │ │ ├── Block │ │ │ │ └── Catalog │ │ │ │ │ └── Product │ │ │ │ │ └── List.php │ │ │ │ └── etc │ │ │ │ └── config.xml │ │ └── local │ │ │ └── Mage │ │ │ └── Core │ │ │ └── Block │ │ │ └── Template.php │ │ └── design │ │ └── frontend │ │ └── base │ │ └── default │ │ └── layout │ │ └── react.xml │ └── modman ├── .gitignore ├── frontend ├── Paypal.js ├── index.js ├── Header.js ├── Product.js └── ProductList.js ├── .editorconfig ├── README.md ├── docker-compose.yml ├── config └── docker │ ├── Dockerfile │ └── bin │ └── set-base-url ├── package.json ├── webpack.config.js ├── composer.json ├── Makefile └── composer.lock /.modman/.basedir: -------------------------------------------------------------------------------- 1 | htdocs/ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | htdocs 3 | .idea 4 | Magento-react.iml 5 | node_modules 6 | npm-debug.log -------------------------------------------------------------------------------- /frontend/Paypal.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | class Paypal extends React.Component { 4 | render() { 5 | return ( 6 |
Salut {this.props.name}
7 | ) 8 | } 9 | } 10 | 11 | export default Paypal; -------------------------------------------------------------------------------- /frontend/index.js: -------------------------------------------------------------------------------- 1 | require("expose?React!react"); 2 | import Paypal from './Paypal'; 3 | import Header from './Header'; 4 | import ProductList from './ProductList'; 5 | 6 | module.exports = { 7 | Paypal: Paypal, 8 | Header: Header, 9 | ProductList: ProductList 10 | }; 11 | -------------------------------------------------------------------------------- /frontend/Header.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { Component } from 'react'; 4 | 5 | export default class Header extends Component { 6 | render() { 7 | return ( 8 |
9 | {this.props.welcome} 10 | {this.props.logoAlt} 11 |
12 | ); 13 | } 14 | } -------------------------------------------------------------------------------- /.modman/Hackathon_React/src/app/etc/modules/Hackathon_React.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true 6 | community 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.modman/Hackathon_React/modman: -------------------------------------------------------------------------------- 1 | src/app/code/community/Hackathon/React app/code/community/Hackathon/React 2 | src/app/code/local/Mage/Core/Block/Template.php app/code/local/Mage/Core/Block/Template.php 3 | src/app/design/frontend/base/default/layout/react.xml app/design/frontend/base/default/layout/react.xml 4 | src/app/etc/modules/* app/etc/modules/ 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | ; This file is for unifying the coding style for different editors and IDEs. 2 | ; More information at http://editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 4 9 | end_of_line = lf 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | 13 | [*.js] 14 | indent_style = space 15 | indent_size = 2 16 | 17 | [Makefile] 18 | indent_style=tab -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #Magento-React 2 | 3 | Use React components as rendering library for Magento 4 | 5 | ## Installation 6 | * Get [Composer](https://getcomposer.org/) 7 | * Get [Docker](https://docs.docker.com/) 8 | * Get [docker-compose](https://docs.docker.com/compose/) 9 | * Get [npm](https://www.npmjs.com/) 10 | * then 11 | ``` 12 | make install 13 | ``` 14 | 15 | ## Helpers 16 | * Launch docker containers 17 | ``` 18 | make docker_run 19 | ``` 20 | * Install composer dependencies 21 | ``` 22 | make composer_install 23 | ``` 24 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | web: 2 | build: ./config/docker 3 | ports: 4 | - "80" 5 | - "443" 6 | links: 7 | - db 8 | - mail 9 | volumes: 10 | - ".:/var/www" 11 | 12 | db: 13 | image: mysql 14 | ports: 15 | - 3306 16 | environment: 17 | MYSQL_ROOT_PASSWORD: "root" 18 | MYSQL_DATABASE: "magento" 19 | 20 | phpmyadmin: 21 | image: maxexcloo/phpmyadmin 22 | ports: 23 | - 80 24 | links: 25 | - db:mariadb 26 | 27 | mail: 28 | image: chadrien/mailcatcher:0.5.12 29 | ports: 30 | - 1080 -------------------------------------------------------------------------------- /frontend/Product.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | export default class Product extends Component { 4 | render() { 5 | console.error(this.props.product.price_html); 6 | return ( 7 |
  • 8 | 9 | {this.props.product.name} 10 | 11 |
    12 | 13 |
  • 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /frontend/ProductList.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import Product from './Product' 3 | 4 | export default class ProductList extends Component { 5 | render() { 6 | const list = this.props.products.map((product) => { 7 | return ( 8 | 9 | ); 10 | }); 11 | return ( 12 |
    13 | 16 |
    17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /config/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM occitech/magento:php5.4-apache 2 | 3 | MAINTAINER occitech 4 | 5 | COPY ./bin/set-base-url /usr/local/bin/set-base-url 6 | 7 | RUN curl -sS http://getcomposer.org/installer | php -- --install-dir=/usr/local/bin/ --filename=composer 8 | 9 | RUN apt-get update && \ 10 | apt-get install -y libv8-dev g++&& \ 11 | rm -rf /var/lib/apt/lists/* 12 | 13 | RUN pecl install v8js-0.1.3 \ 14 | && echo "extension=v8js.so" > /usr/local/etc/php/conf.d/ext-v8js.ini 15 | RUN pecl install zip \ 16 | && echo "extension=zip.so" > /usr/local/etc/php/conf.d/ext-zip.ini -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "magento-react", 3 | "version": "0.0.1", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "webpack", 8 | "watch": "webpack --progress --colors --inline --watch" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "babel-core": "^5.5.8", 14 | "babel-loader": "^5.1.4", 15 | "expose-loader": "^0.7.0", 16 | "react": "^0.13.3" 17 | }, 18 | "devDependencies": { 19 | "node-libs-browser": "^0.5.2", 20 | "webpack": "^1.9.11", 21 | "webpack-dev-server": "^1.9.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.modman/Hackathon_React/src/app/code/community/Hackathon/React/Block/Catalog/Product/List.php: -------------------------------------------------------------------------------- 1 | _getProductCollection() as $product) { 8 | $product->setImage($this->helper('catalog/image')->init($product, 'small_image')->keepFrame(false)->resize(200)->__toString()); 9 | $product->setPriceHtml($this->getPriceHtml($product)); 10 | $products[] = $product->getData(); 11 | } 12 | return $products; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | var node_modules = path.resolve(__dirname, 'node_modules'); 4 | 5 | module.exports = { 6 | entry: { 7 | app: ['./frontend/index.js'], 8 | vendor: ['react'] 9 | }, 10 | output: { 11 | path: "./htdocs/js", 12 | library: 'FooApp', 13 | filename: "bundle.js" 14 | }, 15 | plugins: [ 16 | new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.bundle.js") 17 | ], 18 | module: { 19 | loaders: [ 20 | { test: /\.jsx?$/, exclude: node_modules, loader: "babel-loader" } 21 | ] 22 | }, 23 | devServer: { 24 | contentBase: "./htdocs" 25 | } 26 | }; -------------------------------------------------------------------------------- /config/docker/bin/set-base-url: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if test -z "$1"; then 4 | echo "You must provide a port" 5 | exit 1 6 | fi 7 | 8 | BASE_URL="http://127.0.0.1:$1/" 9 | if test -z "$2"; then 10 | SECURE_BASE_URL=$BASE_URL 11 | else 12 | SECURE_BASE_URL="http://127.0.0.1:$2/" 13 | fi 14 | 15 | while getopts "c" option; do 16 | case $option in 17 | c) 18 | shift 19 | BASE_URL="$1" 20 | ;; 21 | esac 22 | done 23 | 24 | n98-magerun --root-dir=/var/www/html config:set web/unsecure/base_url $BASE_URL >/dev/null 2>&1 25 | n98-magerun --root-dir=/var/www/html config:set web/secure/base_url $BASE_URL >/dev/null 2>&1 26 | 27 | echo "Base URL set to ${BASE_URL}" 28 | echo "Secure base URL set to ${SECURE_BASE_URL}" -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "root/magento3", 3 | "minimum-stability": "dev", 4 | "authors": [ 5 | { 6 | "name": "Adrien Louis-Rossignol", 7 | "email": "adrien.louis.r@gmail.com" 8 | } 9 | ], 10 | "repositories": [ 11 | { 12 | "type": "composer", 13 | "url": "http://packages.firegento.com" 14 | } 15 | ], 16 | "require": { 17 | "bragento/magento-composer-installer": "~1", 18 | "magento/core": "1.9.1.*", 19 | "colinmollenhour/modman": "*", 20 | "reactjs/react-php-v8js": "dev-master" 21 | }, 22 | "scripts": { 23 | "modman": "vendor/bin/modman deploy-all --force" 24 | }, 25 | "extra": { 26 | "magento-root-dir": "htdocs", 27 | "magento-force": 1, 28 | "magento-deploystrategy": "copy" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.modman/Hackathon_React/src/app/code/community/Hackathon/React/etc/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 1.0.0 6 | 7 | 8 | 9 | 10 | 11 | Hackathon_React_Model 12 | 13 | 14 | 15 | 16 | 17 | Hackathon_React_Block_Catalog_Product_List 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | react.xml 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /.modman/Hackathon_React/src/app/design/frontend/base/default/layout/react.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vendor.bundle.js 6 | bundle.js 7 | 8 | 9 | 10 | FooApp.Navbar 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | FooApp.ProductList 19 | 20 | 21 | products 22 | productsForReactComponent 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL = /bin/bash 2 | 3 | MAGERUN = docker-compose run --rm web n98-magerun 4 | COMPOSER = docker-compose run --rm web composer -d="../" 5 | 6 | dev_setup: mage_symlinks modman_deploy 7 | 8 | install: 9 | @if [ ! -d "htdocs/app/etc/" ]; then mkdir -p htdocs/app/etc/; fi 10 | @docker-compose up -d 11 | @sleep 5 12 | @make composer_install 13 | @npm install 14 | @make mage_local_xml 15 | @make mage_base_url 16 | @make open_web 17 | 18 | composer_install: 19 | @${COMPOSER} install --prefer-dist -n 20 | @make modman_deploy 21 | 22 | modman_deploy: 23 | @${COMPOSER} modman 24 | 25 | open_web: 26 | @make open container=web port=80 27 | 28 | open: 29 | @URL="http://127.0.0.1"$$(docker-compose port $(container) $(port) 2>/dev/null | sed s/0.0.0.0//); \ 30 | $$(if [ $$(uname) != 'Darwin' ]; then echo 'xdg-'; fi)open $$URL 31 | 32 | mage_symlinks: 33 | @docker-compose run --rm web n98-magerun dev:symlinks --on --global 34 | 35 | mage_local_xml: 36 | @if test -f htdocs/app/etc/local.xml; then rm htdocs/app/etc/local.xml; fi 37 | @docker-compose run --rm web /bin/bash -c 'n98-magerun local-config:generate $${DB_1_PORT_3306_TCP_ADDR} root $${DB_1_ENV_MYSQL_ROOT_PASSWORD} magento files admin'; 38 | 39 | mage_base_url: 40 | @docker-compose run --rm web set-base-url $$(docker-compose port web 80 2>/dev/null | sed s/0.0.0.0://) $$(docker-compose port web 443 2>/dev/null | sed s/0.0.0.0://); 41 | 42 | docker_run: 43 | @docker-compose up -d 44 | @sleep 5 45 | @make mage_local_xml 46 | @make mage_base_url 47 | @make open_web 48 | @npm run watch -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "hash": "41b9d5c3ebb56ec6103c12de71f657d8", 8 | "packages": [ 9 | { 10 | "name": "bragento/magento-composer-installer", 11 | "version": "1.1.1", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/bragento/bragento-composer-installer.git", 15 | "reference": "e185d188425238a2d078bd79f9116a3926a75673" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/bragento/bragento-composer-installer/zipball/e185d188425238a2d078bd79f9116a3926a75673", 20 | "reference": "e185d188425238a2d078bd79f9116a3926a75673", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "composer-plugin-api": "~1", 25 | "symfony/filesystem": "~2" 26 | }, 27 | "replace": { 28 | "magento-hackathon/magento-composer-installer": "*" 29 | }, 30 | "require-dev": { 31 | "codeclimate/php-test-reporter": "*", 32 | "composer/composer": "*@dev", 33 | "mikey179/vfsstream": "*", 34 | "phpunit/phpunit": "*" 35 | }, 36 | "type": "composer-plugin", 37 | "extra": { 38 | "class": "Bragento\\Magento\\Composer\\Installer\\Plugin", 39 | "branch-alias": { 40 | "dev-develop": "1.2.x-dev" 41 | } 42 | }, 43 | "autoload": { 44 | "psr-4": { 45 | "Bragento\\Magento\\Composer\\Installer\\": "src" 46 | } 47 | }, 48 | "notification-url": "https://packagist.org/downloads/", 49 | "license": [ 50 | "OSL-3.0" 51 | ], 52 | "authors": [ 53 | { 54 | "name": "David Verholen", 55 | "email": "david.verholen@brandung.de", 56 | "homepage": "http://www.agentur-brandung.de" 57 | } 58 | ], 59 | "description": "Composer installer for Magento modules", 60 | "homepage": "https://github.com/bragento/bragento-composer-installer", 61 | "keywords": [ 62 | "bragento", 63 | "brandung", 64 | "composer", 65 | "installer", 66 | "magento" 67 | ], 68 | "time": "2015-02-28 14:42:03" 69 | }, 70 | { 71 | "name": "colinmollenhour/modman", 72 | "version": "1.10", 73 | "source": { 74 | "type": "git", 75 | "url": "https://github.com/colinmollenhour/modman.git", 76 | "reference": "df531dd29f10e9b0611763eb6d96a8417eef43d2" 77 | }, 78 | "dist": { 79 | "type": "zip", 80 | "url": "https://api.github.com/repos/colinmollenhour/modman/zipball/df531dd29f10e9b0611763eb6d96a8417eef43d2", 81 | "reference": "df531dd29f10e9b0611763eb6d96a8417eef43d2", 82 | "shasum": "" 83 | }, 84 | "bin": [ 85 | "modman" 86 | ], 87 | "type": "library", 88 | "license": [ 89 | "Apache-2.0" 90 | ], 91 | "authors": [ 92 | { 93 | "name": "Colin Mollenhour" 94 | } 95 | ], 96 | "description": "Module Manager", 97 | "homepage": "https://github.com/colinmollenhour/modman", 98 | "support": { 99 | "source": "https://github.com/colinmollenhour/modman/tree/1.10", 100 | "issues": "https://github.com/colinmollenhour/modman/issues" 101 | }, 102 | "time": "2014-12-29 22:16:51" 103 | }, 104 | { 105 | "name": "magento/core", 106 | "version": "1.9.1.1-patch1", 107 | "source": { 108 | "type": "git", 109 | "url": "https://github.com/bragento/magento-core.git", 110 | "reference": "6c31124a7acdf3f0c1e20d5ffe5ce5fcc4f205fb" 111 | }, 112 | "dist": { 113 | "type": "zip", 114 | "url": "https://api.github.com/repos/bragento/magento-core/zipball/6c31124a7acdf3f0c1e20d5ffe5ce5fcc4f205fb", 115 | "reference": "6c31124a7acdf3f0c1e20d5ffe5ce5fcc4f205fb", 116 | "shasum": "" 117 | }, 118 | "type": "magento-core", 119 | "extra": { 120 | "map": [ 121 | [ 122 | "app", 123 | "app" 124 | ], 125 | [ 126 | "downloader", 127 | "downloader" 128 | ], 129 | [ 130 | "errors", 131 | "errors" 132 | ], 133 | [ 134 | "includes", 135 | "includes" 136 | ], 137 | [ 138 | "js", 139 | "js" 140 | ], 141 | [ 142 | "lib", 143 | "lib" 144 | ], 145 | [ 146 | "media", 147 | "media" 148 | ], 149 | [ 150 | "pkginfo", 151 | "pkginfo" 152 | ], 153 | [ 154 | "shell", 155 | "shell" 156 | ], 157 | [ 158 | "skin", 159 | "skin" 160 | ], 161 | [ 162 | "var", 163 | "var" 164 | ], 165 | [ 166 | ".htaccess", 167 | ".htaccess" 168 | ], 169 | [ 170 | "api.php", 171 | "api.php" 172 | ], 173 | [ 174 | "cron.php", 175 | "cron.php" 176 | ], 177 | [ 178 | "cron.sh", 179 | "cron.sh" 180 | ], 181 | [ 182 | "favicon.ico", 183 | "favicon.ico" 184 | ], 185 | [ 186 | "get.php", 187 | "get.php" 188 | ], 189 | [ 190 | "index.php", 191 | "index.php" 192 | ], 193 | [ 194 | "install.php", 195 | "install.php" 196 | ], 197 | [ 198 | "mage", 199 | "mage" 200 | ] 201 | ] 202 | }, 203 | "license": [ 204 | "OSL-3.0" 205 | ], 206 | "description": "Magento Core", 207 | "homepage": "http://www.magentocommerce.com", 208 | "support": { 209 | "source": "https://github.com/bragento/magento-core/tree/1.9.1.1-patch1", 210 | "issues": "https://github.com/bragento/magento-core/issues" 211 | }, 212 | "time": "2015-05-15 08:14:35" 213 | }, 214 | { 215 | "name": "reactjs/react-php-v8js", 216 | "version": "dev-master", 217 | "source": { 218 | "type": "git", 219 | "url": "https://github.com/reactjs/react-php-v8js.git", 220 | "reference": "6bfbf166cdca7c6ef640ceb450d8ecc59ed2aeba" 221 | }, 222 | "dist": { 223 | "type": "zip", 224 | "url": "https://api.github.com/repos/reactjs/react-php-v8js/zipball/6bfbf166cdca7c6ef640ceb450d8ecc59ed2aeba", 225 | "reference": "6bfbf166cdca7c6ef640ceb450d8ecc59ed2aeba", 226 | "shasum": "" 227 | }, 228 | "require": { 229 | "ext-v8js": ">=0.1.3" 230 | }, 231 | "type": "library", 232 | "autoload": { 233 | "classmap": [ 234 | "ReactJS.php" 235 | ] 236 | }, 237 | "notification-url": "https://packagist.org/downloads/", 238 | "license": [ 239 | "BSD-3-Clause" 240 | ], 241 | "description": "PHP library that renders React components on the server", 242 | "time": "2015-05-26 17:55:07" 243 | }, 244 | { 245 | "name": "symfony/filesystem", 246 | "version": "v2.7.0", 247 | "source": { 248 | "type": "git", 249 | "url": "https://github.com/symfony/Filesystem.git", 250 | "reference": "ae4551fd6d4d4f51f2e7390fbc902fbd67f3b7ba" 251 | }, 252 | "dist": { 253 | "type": "zip", 254 | "url": "https://api.github.com/repos/symfony/Filesystem/zipball/ae4551fd6d4d4f51f2e7390fbc902fbd67f3b7ba", 255 | "reference": "ae4551fd6d4d4f51f2e7390fbc902fbd67f3b7ba", 256 | "shasum": "" 257 | }, 258 | "require": { 259 | "php": ">=5.3.9" 260 | }, 261 | "require-dev": { 262 | "symfony/phpunit-bridge": "~2.7" 263 | }, 264 | "type": "library", 265 | "extra": { 266 | "branch-alias": { 267 | "dev-master": "2.7-dev" 268 | } 269 | }, 270 | "autoload": { 271 | "psr-4": { 272 | "Symfony\\Component\\Filesystem\\": "" 273 | } 274 | }, 275 | "notification-url": "https://packagist.org/downloads/", 276 | "license": [ 277 | "MIT" 278 | ], 279 | "authors": [ 280 | { 281 | "name": "Fabien Potencier", 282 | "email": "fabien@symfony.com" 283 | }, 284 | { 285 | "name": "Symfony Community", 286 | "homepage": "https://symfony.com/contributors" 287 | } 288 | ], 289 | "description": "Symfony Filesystem Component", 290 | "homepage": "https://symfony.com", 291 | "time": "2015-05-15 13:33:16" 292 | } 293 | ], 294 | "packages-dev": [], 295 | "aliases": [], 296 | "minimum-stability": "dev", 297 | "stability-flags": { 298 | "reactjs/react-php-v8js": 20 299 | }, 300 | "prefer-stable": false, 301 | "prefer-lowest": false, 302 | "platform": [], 303 | "platform-dev": [] 304 | } 305 | -------------------------------------------------------------------------------- /.modman/Hackathon_React/src/app/code/local/Mage/Core/Block/Template.php: -------------------------------------------------------------------------------- 1 | 35 | */ 36 | class Mage_Core_Block_Template extends Mage_Core_Block_Abstract 37 | { 38 | const XML_PATH_DEBUG_TEMPLATE_HINTS = 'dev/debug/template_hints'; 39 | const XML_PATH_DEBUG_TEMPLATE_HINTS_BLOCKS = 'dev/debug/template_hints_blocks'; 40 | const XML_PATH_TEMPLATE_ALLOW_SYMLINK = 'dev/template/allow_symlink'; 41 | 42 | private $_dynamicValues = []; 43 | 44 | /** 45 | * View scripts directory 46 | * 47 | * @var string 48 | */ 49 | protected $_viewDir = ''; 50 | 51 | /** 52 | * Assigned variables for view 53 | * 54 | * @var array 55 | */ 56 | protected $_viewVars = array(); 57 | 58 | protected $_baseUrl; 59 | 60 | protected $_jsUrl; 61 | 62 | /** 63 | * Is allowed symlinks flag 64 | * 65 | * @var bool 66 | */ 67 | protected $_allowSymlinks = null; 68 | 69 | protected static $_showTemplateHints; 70 | protected static $_showTemplateHintsBlocks; 71 | 72 | /** 73 | * Path to template file in theme. 74 | * 75 | * @var string 76 | */ 77 | protected $_template; 78 | 79 | /** 80 | * Internal constructor, that is called from real constructor 81 | * 82 | */ 83 | protected function _construct() 84 | { 85 | parent::_construct(); 86 | 87 | /* 88 | * In case template was passed through constructor 89 | * we assign it to block's property _template 90 | * Mainly for those cases when block created 91 | * not via Mage_Core_Model_Layout::addBlock() 92 | */ 93 | if ($this->hasData('template')) { 94 | $this->setTemplate($this->getData('template')); 95 | } 96 | } 97 | 98 | /** 99 | * Get relevant path to template 100 | * 101 | * @return string 102 | */ 103 | public function getTemplate() 104 | { 105 | return $this->_template; 106 | } 107 | 108 | /** 109 | * Set path to template used for generating block's output. 110 | * 111 | * @param string $template 112 | * @return Mage_Core_Block_Template 113 | */ 114 | public function setTemplate($template) 115 | { 116 | $this->_template = $template; 117 | return $this; 118 | } 119 | 120 | /** 121 | * Get absolute path to template 122 | * 123 | * @return string 124 | */ 125 | public function getTemplateFile() 126 | { 127 | $params = array('_relative'=>true); 128 | $area = $this->getArea(); 129 | if ($area) { 130 | $params['_area'] = $area; 131 | } 132 | $templateName = Mage::getDesign()->getTemplateFilename($this->getTemplate(), $params); 133 | return $templateName; 134 | } 135 | 136 | /** 137 | * Get design area 138 | * @return string 139 | */ 140 | public function getArea() 141 | { 142 | return $this->_getData('area'); 143 | } 144 | 145 | /** 146 | * Assign variable 147 | * 148 | * @param string|array $key 149 | * @param mixed $value 150 | * @return Mage_Core_Block_Template 151 | */ 152 | public function assign($key, $value=null) 153 | { 154 | if (is_array($key)) { 155 | foreach ($key as $k=>$v) { 156 | $this->assign($k, $v); 157 | } 158 | } 159 | else { 160 | $this->_viewVars[$key] = $value; 161 | } 162 | return $this; 163 | } 164 | 165 | public function addDynamicValue($key, $method, $args=[]) 166 | { 167 | $this->_dynamicValues[$key] = new Varien_Object(compact('method', 'args')); 168 | } 169 | 170 | protected function assignDynamicValue() 171 | { 172 | foreach($this->_dynamicValues as $key => $valueGenerator) { 173 | $this->assign($key, call_user_func_array( 174 | [$this, $valueGenerator->getMethod()], 175 | $valueGenerator->getArgs() 176 | ) 177 | ); 178 | } 179 | } 180 | 181 | /** 182 | * Set template location directory 183 | * 184 | * @param string $dir 185 | * @return Mage_Core_Block_Template 186 | */ 187 | public function setScriptPath($dir) 188 | { 189 | $scriptPath = realpath($dir); 190 | if (strpos($scriptPath, realpath(Mage::getBaseDir('design'))) === 0 || $this->_getAllowSymlinks()) { 191 | $this->_viewDir = $dir; 192 | } else { 193 | Mage::log('Not valid script path:' . $dir, Zend_Log::CRIT, null, null, true); 194 | } 195 | return $this; 196 | } 197 | 198 | /** 199 | * Check if direct output is allowed for block 200 | * 201 | * @return bool 202 | */ 203 | public function getDirectOutput() 204 | { 205 | if ($this->getLayout()) { 206 | return $this->getLayout()->getDirectOutput(); 207 | } 208 | return false; 209 | } 210 | 211 | public function getShowTemplateHints() 212 | { 213 | if (is_null(self::$_showTemplateHints)) { 214 | self::$_showTemplateHints = Mage::getStoreConfig(self::XML_PATH_DEBUG_TEMPLATE_HINTS) 215 | && Mage::helper('core')->isDevAllowed(); 216 | self::$_showTemplateHintsBlocks = Mage::getStoreConfig(self::XML_PATH_DEBUG_TEMPLATE_HINTS_BLOCKS) 217 | && Mage::helper('core')->isDevAllowed(); 218 | } 219 | return self::$_showTemplateHints; 220 | } 221 | 222 | /** 223 | * Retrieve block view from file (template) 224 | * 225 | * @param string $fileName 226 | * @return string 227 | */ 228 | public function fetchView($fileName) 229 | { 230 | Varien_Profiler::start($fileName); 231 | 232 | $this->assignDynamicValue(); 233 | // EXTR_SKIP protects from overriding 234 | // already defined variables 235 | extract ($this->_viewVars, EXTR_SKIP); 236 | $do = $this->getDirectOutput(); 237 | 238 | if (!$do) { 239 | ob_start(); 240 | } 241 | if ($this->getShowTemplateHints()) { 242 | echo << 244 |
    {$fileName}
    247 | HTML; 248 | if (self::$_showTemplateHintsBlocks) { 249 | $thisClass = get_class($this); 250 | echo <<{$thisClass} 254 | HTML; 255 | } 256 | } 257 | 258 | try { 259 | if ($component = $this->getReactComponent()) { 260 | echo $this->fetchReactComponent($component, $this->_viewVars); 261 | } else { 262 | $includeFilePath = realpath($this->_viewDir . DS . $fileName); 263 | if (strpos($includeFilePath, realpath($this->_viewDir)) === 0 || $this->_getAllowSymlinks()) { 264 | include $includeFilePath; 265 | } else { 266 | Mage::log('Not valid template file:'.$fileName, Zend_Log::CRIT, null, null, true); 267 | } 268 | } 269 | } catch (Exception $e) { 270 | ob_get_clean(); 271 | throw $e; 272 | } 273 | 274 | if ($this->getShowTemplateHints()) { 275 | echo ''; 276 | } 277 | 278 | if (!$do) { 279 | $html = ob_get_clean(); 280 | } else { 281 | $html = ''; 282 | } 283 | Varien_Profiler::stop($fileName); 284 | return $html; 285 | } 286 | 287 | protected function fetchReactComponent($componentName, $props) 288 | { 289 | $bundle_source = file_get_contents(BP . DS . 'js/bundle.js'); 290 | $react_source = file_get_contents(BP . DS . 'js/vendor.bundle.js'); 291 | $rjs = new ReactJS($react_source, $bundle_source); 292 | $rjs->setComponent($componentName, $props); 293 | echo '
    ' . $rjs->getMarkup() . '
    '; 294 | printf('', $rjs->getJS('#' . $componentName)); 295 | } 296 | /** 297 | * Render block 298 | * 299 | * @return string 300 | */ 301 | public function renderView() 302 | { 303 | $this->setScriptPath(Mage::getBaseDir('design')); 304 | $html = $this->fetchView($this->getTemplateFile()); 305 | return $html; 306 | } 307 | 308 | /** 309 | * Render block HTML 310 | * 311 | * @return string 312 | */ 313 | protected function _toHtml() 314 | { 315 | if (!$this->getTemplate()) { 316 | return ''; 317 | } 318 | $html = $this->renderView(); 319 | return $html; 320 | } 321 | 322 | /** 323 | * Get base url of the application 324 | * 325 | * @return string 326 | */ 327 | public function getBaseUrl() 328 | { 329 | if (!$this->_baseUrl) { 330 | $this->_baseUrl = Mage::getBaseUrl(); 331 | } 332 | return $this->_baseUrl; 333 | } 334 | 335 | /** 336 | * Get url of base javascript file 337 | * 338 | * To get url of skin javascript file use getSkinUrl() 339 | * 340 | * @param string $fileName 341 | * @return string 342 | */ 343 | public function getJsUrl($fileName='') 344 | { 345 | if (!$this->_jsUrl) { 346 | $this->_jsUrl = Mage::getBaseUrl('js'); 347 | } 348 | return $this->_jsUrl.$fileName; 349 | } 350 | 351 | /** 352 | * Get data from specified object 353 | * 354 | * @param Varien_Object $object 355 | * @param string $key 356 | * @return mixed 357 | */ 358 | public function getObjectData(Varien_Object $object, $key) 359 | { 360 | return $object->getDataUsingMethod((string)$key); 361 | } 362 | 363 | /** 364 | * Get cache key informative items 365 | * 366 | * @return array 367 | */ 368 | public function getCacheKeyInfo() 369 | { 370 | return array( 371 | 'BLOCK_TPL', 372 | Mage::app()->getStore()->getCode(), 373 | $this->getTemplateFile(), 374 | 'template' => $this->getTemplate() 375 | ); 376 | } 377 | 378 | /** 379 | * Get is allowed symliks flag 380 | * 381 | * @return bool 382 | */ 383 | protected function _getAllowSymlinks() 384 | { 385 | if (is_null($this->_allowSymlinks)) { 386 | $this->_allowSymlinks = Mage::getStoreConfigFlag(self::XML_PATH_TEMPLATE_ALLOW_SYMLINK); 387 | } 388 | return $this->_allowSymlinks; 389 | } 390 | } 391 | --------------------------------------------------------------------------------