diff --git a/core/lib/Thelia/Core/Bundle/ModelBundle.php b/core/lib/Thelia/Core/Bundle/ModelBundle.php new file mode 100644 index 000000000..a488a722c --- /dev/null +++ b/core/lib/Thelia/Core/Bundle/ModelBundle.php @@ -0,0 +1,40 @@ + + */ + +class ModelBundle extends Bundle +{ + /** + * + * Construct the depency injection builder + * + * Reference all Model in the Container here + * + * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container + */ + + public function build(ContainerBuilder $container) + { + foreach(DIGenerator::genDiModel(realpath(THELIA_ROOT . "core/lib/Thelia/Model"), array('Base')) as $name => $class) + { + $container->register('model.'.$name, $class) + ->addArgument(new Reference("database")); + } + } +} diff --git a/core/lib/Thelia/Core/Bundle/NotORMBundle.php b/core/lib/Thelia/Core/Bundle/NotORMBundle.php new file mode 100644 index 000000000..bf58c5351 --- /dev/null +++ b/core/lib/Thelia/Core/Bundle/NotORMBundle.php @@ -0,0 +1,93 @@ + + */ + +class NotORMBundle extends Bundle +{ + /** + * + * Construct the depency injection builder + * + * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container + */ + + public function build(ContainerBuilder $container) + { + $config = array(); + + $kernel = $container->get('kernel'); + + $pdo = new \PDO(THELIA_DB_DSN,THELIA_DB_USER, THELIA_DB_PASSWORD, $config); + + $pdo->exec("SET NAMES UTF8"); + + $container->register('database','\Thelia\Database\NotORM') + ->addArgument($pdo); + + if(defined('THELIA_DB_CACHE') && !$kernel->isDebug()) + { + switch(THELIA_DB_CACHE) + { + case 'file': + $container->register('database_cache','\NotORM_Cache_File') + ->addArgument($kernel->getCacheDir().'/database.php'); + break; + case 'include': + $container->register('database_cache','\NotORM_Cache_Include') + ->addArgument($kernel->getCacheDir().'/database_include.php'); + break; + case 'apc': + if (extension_loaded('apc')) + { + $container->register('database_cache','\NotORM_Cache_APC'); + } + break; + case 'session': + $container->register('database_cache','\NotORM_Cache_Session'); + break; + case 'memcache': + if(class_exists('Memcache')) + { + $container->register('database_cache','\NotORM_Cache_Memcache') + ->addArgument(new \Memcache()); + } + break; + + } + + if($container->hasDefinition('database_cache')) + { + $container->getDefinition('database') + ->addMethodCall('setCache', array(new Reference('database_cache'))); + } + } + + if($kernel->isDebug()) + { + $debug = function ($query, $parameters) + { + echo $query."
"; + }; + + $container->getDefinition('database') + ->addMethodCall('setDebug', array($debug)); + } + + + } +} diff --git a/core/lib/Thelia/Core/Bundle/TheliaBundle.php b/core/lib/Thelia/Core/Bundle/TheliaBundle.php new file mode 100644 index 000000000..2e2900fec --- /dev/null +++ b/core/lib/Thelia/Core/Bundle/TheliaBundle.php @@ -0,0 +1,98 @@ + + */ + +class TheliaBundle extends Bundle +{ + /** + * + * Construct the depency injection builder + * + * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container + */ + + public function build(ContainerBuilder $container) + { + $container->addScope( new Scope('request')); + + $container->register('request', 'Symfony\Component\HttpFoundation\Request') + ->setSynthetic(true); + + $container->register('controller.default','Thelia\Controller\DefaultController'); + $container->register('matcher.default','Thelia\Routing\Matcher\DefaultMatcher') + ->addArgument(new Reference('controller.default')); + + $container->register('matcher','Thelia\Routing\Matcher\theliaMatcherCollection') + ->addMethodCall('add', array(new Reference('matcher.default'), -255)) + //->addMethodCall('add','a matcher class (instance or class name) + + ; + + $container->register('resolver', 'Symfony\Component\HttpKernel\Controller\ControllerResolver'); + + $container->register('parser','Thelia\Core\Template\Parser') + ->addArgument(new Reference('service_container')) + ; + +// $container->setParameter("logger.class", "\Thelia\Log\Tlog"); +// $container->register("logger","%logger.class%"); + /** + * RouterListener implements EventSubscriberInterface and listen for kernel.request event + */ + $container->register('listener.router', 'Symfony\Component\HttpKernel\EventListener\RouterListener') + ->setArguments(array(new Reference('matcher'))) + ; + + /** + * @TODO add an other listener on kernel.request for checking some params Like check if User is log in, set the language and other. + * + * $container->register() + * + * + * $container->register('listener.request', 'Thelia\Core\EventListener\RequestListener') + * ->addArgument(new Reference(''); + * ; + */ + + $container->register('thelia.listener.view','Thelia\Core\EventListener\ViewListener') + ->addArgument(new Reference('parser')) + ; + + + + $container->register('dispatcher','Symfony\Component\EventDispatcher\EventDispatcher') + ->addArgument(new Reference('service_container')) + ->addMethodCall('addSubscriber', array(new Reference('listener.router'))) + ->addMethodCall('addSubscriber', array(new Reference('thelia.listener.view'))) + ; + + $container->register('http_kernel','Thelia\Core\TheliaHttpKernel') + ->addArgument(new Reference('dispatcher')) + ->addArgument(new Reference('service_container')) + ->addArgument(new Reference('resolver')) + ; + + // DEFINE DEFAULT PARAMETER LIKE + + /** + * @TODO learn about container compilation + */ + + } +} diff --git a/core/lib/Thelia/Core/Template/Parser.php b/core/lib/Thelia/Core/Template/Parser.php index a35d7d242..d6ef0f9fe 100644 --- a/core/lib/Thelia/Core/Template/Parser.php +++ b/core/lib/Thelia/Core/Template/Parser.php @@ -58,8 +58,8 @@ class Parser implements ParserInterface $this->content = $request->get("test"); - var_dump($this->container->get("database")); - + $config = $this->container->get("model.config"); + return $this->content; } diff --git a/core/lib/Thelia/Database/NotORM.php b/core/lib/Thelia/Database/NotORM.php new file mode 100644 index 000000000..db87484c0 --- /dev/null +++ b/core/lib/Thelia/Database/NotORM.php @@ -0,0 +1,22 @@ +cache = $cache; + } + + public function setDebug($debug) + { + if(is_callable($debug)) + { + $this->debug = $debug; + } else { + $this->debug = true; + } + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Log/Tlog.php b/core/lib/Thelia/Log/Tlog.php new file mode 100644 index 000000000..177f1484f --- /dev/null +++ b/core/lib/Thelia/Log/Tlog.php @@ -0,0 +1,377 @@ +init(); + } + + return self::$instance; + } + + protected function init() { + $niveau = Config::read(self::VAR_NIVEAU, self::DEFAUT_NIVEAU); + + $this->set_niveau($niveau); + + $this->dir_destinations = array( + __DIR__.'/tlog/destinations' + //, __DIR__.'/../client/tlog/destinations' + ); + + $this->set_prefixe(Config::read(self::VAR_PREFIXE, self::DEFAUT_PREFIXE)); + $this->set_files(Config::read(self::VAR_FILES, self::DEFAUT_FILES)); + $this->set_ip(Config::read(self::VAR_IP, self::DEFAUT_IP)); + $this->set_destinations(Config::read(self::VAR_DESTINATIONS, self::DEFAUT_DESTINATIONS)); + $this->set_show_redirect(Config::read(self::VAR_SHOW_REDIRECT, self::DEFAUT_SHOW_REDIRECT)); + + // Au cas ou il y aurait un exit() quelque part dans le code. + register_shutdown_function(array($this, 'ecrire_si_exit')); + } + + // Configuration + // ------------- + + public function set_destinations($destinations) { + if (! empty($destinations)) { + + $this->destinations = array(); + + $classes_destinations = explode(';', $destinations); + $this->charger_classes_destinations($this->destinations, $classes_destinations); + } + } + + public function set_niveau($niveau) { + $this->niveau = $niveau; + } + + public function set_prefixe($prefixe) { + + $this->prefixe = $prefixe; + } + + public function set_files($files) { + $this->files = explode(";", $files); + + $this->all_files = in_array('*', $this->files); + } + + public function set_ip($ips) { + if (! empty($ips) && ! in_array($_SERVER['REMOTE_ADDR'], explode(";", $ips))) $this->niveau = self::MUET; + } + + public function set_show_redirect($bool) { + $this->show_redirect = $bool; + } + + // Configuration d'une destination + public function set_config($destination, $param, $valeur) { + + if (isset($this->destinations[$destination])) { + $this->destinations[$destination]->set_config($param, $valeur); + } + } + + // Configuration d'une destination + public function get_config($destination, $param) { + + if (isset($this->destinations[$destination])) { + return $this->destinations[$destination]->get_config($param); + } + + return false; + } + + // Methodes d'accès aux traces + // --------------------------- + + public static function trace() { + if (Tlog::instance()->niveau > self::TRACE) + return; + + $args = func_get_args(); + + Tlog::instance()->out("TRACE", $args); + } + + public static function debug() { + if (Tlog::instance()->niveau > self::DEBUG) + return; + + $args = func_get_args(); + + Tlog::instance()->out("DEBUG", $args); + } + + public static function info() { + if (Tlog::instance()->niveau > self::INFO) + return; + + $args = func_get_args(); + + Tlog::instance()->out("INFO", $args); + } + + public static function warning() { + if (Tlog::instance()->niveau > self::WARNING) + return; + + $args = func_get_args(); + + Tlog::instance()->out("WARNING", $args); + } + + public static function error() { + if (Tlog::instance()->niveau > self::ERROR) + return; + + $args = func_get_args(); + + Tlog::instance()->out("ERREUR", $args); + } + + public static function fatal() { + if (Tlog::instance()->niveau > self::FATAL) + return; + + $args = func_get_args(); + + Tlog::instance()->out("FATAL", $args); + } + + // Mode back office + public static function mode_back_office($booleen) { + + foreach(Tlog::instance()->destinations as $dest) { + $dest->mode_back_office($booleen); + } + } + + // Ecriture finale + public static function ecrire(&$res) { + + self::$ecrire_effectue = true; + + // Muet ? On ne fait rien + if (Tlog::instance()->niveau == self::MUET) return; + + foreach(Tlog::instance()->destinations as $dest) { + $dest->ecrire($res); + } + } + + public static function ecrire_si_exit() { + // Si les infos de debug n'ont pas été ecrites, le faire maintenant + if (self::$ecrire_effectue === false) { + + $res = ""; + + self::ecrire($res); + + echo $res; + } + } + + public function afficher_redirections($url) { + + if ($this->niveau != self::MUET && $this->show_redirect) { + echo " + +Redirection... + + Redirection vers $url + + + "; + + return true; + } + else { + return false; + } + } + + // Permet de déterminer si la trace est active, en prenant en compte + // le niveau et le filtrage par fichier + public function active($niveau) { + + if ($this->niveau <= $niveau) { + + $origine = $this->trouver_origine(); + + $file = basename($origine['file']); + + if ($this->is_file_active($file)) { + return true; + } + } + + return false; + } + + public function is_file_active($file) { + return ($this->all_files || in_array($file, $this->files)) && ! in_array("!$file", $this->files); + } + + /* -- Methodes privees ---------------------------------------- */ + + // Adapté de LoggerLoginEvent dans log4php + private function trouver_origine() { + + $origine = array(); + + if(function_exists('debug_backtrace')) { + + $trace = debug_backtrace(); + $prevHop = null; + // make a downsearch to identify the caller + $hop = array_pop($trace); + + while($hop !== null) { + if(isset($hop['class'])) { + // we are sometimes in functions = no class available: avoid php warning here + $className = strtolower($hop['class']); + + if (! empty($className) and ($className == 'tlog' or strtolower(get_parent_class($className)) == 'tlog')) { + $origine['line'] = $hop['line']; + $origine['file'] = $hop['file']; + break; + } + } + $prevHop = $hop; + $hop = array_pop($trace); + } + + $origine['class'] = isset($prevHop['class']) ? $prevHop['class'] : 'main'; + + if(isset($prevHop['function']) and + $prevHop['function'] !== 'include' and + $prevHop['function'] !== 'include_once' and + $prevHop['function'] !== 'require' and + $prevHop['function'] !== 'require_once') { + + $origine['function'] = $prevHop['function']; + } else { + $origine['function'] = 'main'; + } + } + + return $origine; + } + + private function out($level, $tabargs) { + + $text = ''; + + foreach ($tabargs as $arg) { + $text .= is_scalar($arg) ? $arg : print_r($arg, true); + } + + $origine = $this->trouver_origine(); + + $file = basename($origine['file']); + + if ($this->is_file_active($file)) { + + $function = $origine['function']; + $line = $origine['line']; + + $prefixe = str_replace( + array("#NUM", "#NIVEAU", "#FICHIER", "#FONCTION", "#LIGNE", "#DATE", "#HEURE"), + array(1+$this->linecount, $level, $file, $function, $line, date("Y-m-d"), date("G:i:s")), + $this->prefixe + ); + + $trace = $prefixe . $text; + + foreach($this->destinations as $dest) { + $dest->ajouter($trace); + } + + $this->linecount++; + } + } + + protected function charger_classes_destinations(&$destinations, $actives = false) { + + foreach($this->dir_destinations as $dir) { + $classes = array(); + + if ($dh = @opendir($dir)) { + + while ($file = readdir($dh)) { + + if ($file == '.' || $file == '..') continue; + + $matches = array(); + + if (preg_match("/([^\.]+)\.class\.php/", $file, $matches)) { + $classname = $matches[1]; + + if ( ($actives === false || in_array($classname, $actives)) && ! isset($destinations[$classname])) { + include_once("$dir/$file"); + + $destinations[$classname] = new $classname(); + } + } + } + + @closedir($dh); + } + } + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Model/Base.php b/core/lib/Thelia/Model/Base.php new file mode 100644 index 000000000..05613d385 --- /dev/null +++ b/core/lib/Thelia/Model/Base.php @@ -0,0 +1,48 @@ +db = $NotORM; + $this->table = $this->getTableName(); + } + + protected function getTableName() + { + return $this->underscore(__CLASS__); + } + + protected function underscore($camel_cased_word) + { + $tmp = $camel_cased_word; + $tmp = str_replace('::', '/', $tmp); + $tmp = self::pregtr($tmp, array('/([A-Z]+)([A-Z][a-z])/' => '\\1_\\2', + '/([a-z\d])([A-Z])/' => '\\1_\\2')); + return strtolower($tmp); + } + + public static function pregtr($search, $replacePairs) + { + return preg_replace(array_keys($replacePairs), array_values($replacePairs), $search); + } +} diff --git a/core/lib/Thelia/Model/Config.php b/core/lib/Thelia/Model/Config.php index 119539266..275e1b5c9 100644 --- a/core/lib/Thelia/Model/Config.php +++ b/core/lib/Thelia/Model/Config.php @@ -6,4 +6,9 @@ use Thelia\Model\Base; class Config extends Base { + + public function read($search, $default) + { + return $this->db->config()->where("name",$search)->fetch()?:$default; + } } diff --git a/core/lib/Thelia/Tools/DIGenerator.php b/core/lib/Thelia/Tools/DIGenerator.php new file mode 100644 index 000000000..c92547167 --- /dev/null +++ b/core/lib/Thelia/Tools/DIGenerator.php @@ -0,0 +1,118 @@ +isFile()) continue; + + $filePath = $file->getRealPath(); + + $classes = self::findClasses($filePath); + + foreach($classes as $class) + { + $classInfo = new \ReflectionClass($class); + $shortName = $classInfo->getShortName(); + if(!in_array($shortName, $exclude)) + { + $results[$shortName] = $class; + } + } + } + + return $results; + + } + + /** + * Extract the classes in the given file + * + * copied from Composer\Autoload\GenerateClassMap::findClasses() + * + * @param string $path The file to check + * + * @return array The found classes + */ + private static function findClasses($path) + { + $traits = version_compare(PHP_VERSION, '5.4', '<') ? '' : '|trait'; + + try { + $contents = php_strip_whitespace($path); + } catch (\Exception $e) { + throw new \RuntimeException('Could not scan for classes inside '.$path.": \n".$e->getMessage(), 0, $e); + } + + // return early if there is no chance of matching anything in this file + if (!preg_match('{\b(?:class|interface'.$traits.')\b}i', $contents)) { + return array(); + } + + // strip heredocs/nowdocs + $contents = preg_replace('{<<<\'?(\w+)\'?(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r)\\1(?=\r\n|\n|\r|;)}s', 'null', $contents); + // strip strings + $contents = preg_replace('{"[^"\\\\]*(\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(\\\\.[^\'\\\\]*)*\'}', 'null', $contents); + // strip leading non-php code if needed + if (substr($contents, 0, 2) !== '.+<\?}s', '?>'); + if (false !== $pos && false === strpos(substr($contents, $pos), '])(?Pclass|interface'.$traits.') \s+ (?P[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*) + | \b(?])(?Pnamespace) (?P\s+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(?:\s*\\\\\s*[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*)? \s*[\{;] + ) + }ix', $contents, $matches); + + $classes = array(); + $namespace = ''; + + for ($i = 0, $len = count($matches['type']); $i < $len; $i++) { + if (!empty($matches['ns'][$i])) { + $namespace = str_replace(array(' ', "\t", "\r", "\n"), '', $matches['nsname'][$i]) . '\\'; + } else { + $classes[] = ltrim($namespace . $matches['name'][$i], '\\'); + } + } + + return $classes; + } + +} \ No newline at end of file