<commit_before><?php
namespace Orpheus\EntityDescriptor;

use Orpheus\Cache\FSCache;
use Orpheus\Config\YAML\YAML;
use Orpheus\Publisher\Exception\InvalidFieldException;
use \Exception;
use Orpheus\Publisher\Util\SlugGenerator;

/** A class to describe an entity
 * 
 * @author <NAME>
 * 
 * This class uses a YAML configuration file to describe the entity.
 * Thus you can easily update your database using dev_entities module and it validate the input data for you.
 */
class EntityDescriptor {

	protected $class;
	protected $name;
	protected $version;
    /* @var $fields Field[] */
	protected $fields	= array();
	protected $indexes	= array();
	protected $abstract	= false;
	
	const FLAG_ABSTRACT	= 'abstract';
	
	const DESCRIPTORCLASS	= 'EntityDescriptor';
	const IDFIELD			= 'id';
	const VERSION			= 4;

	/**
	 * Get all available entity descriptor
	 * 
	 * @return EntityDescriptor[]
	 */
	public static function getAllEntityDescriptors() {
		$entities	= array();
		foreach( static::getAllEntities() as $entity ) {
			$entities[$entity] = EntityDescriptor::load($entity);
		}
		return $entities;
	}

	/**
	 * Get all available entities
	 *
	 * @return string[]
	 */
	public static function getAllEntities() {
		$entities	= cleanscandir(pathOf(CONFDIR.ENTITY_DESCRIPTOR_CONFIG_PATH));
		foreach( $entities as $i => &$filename ) {
			$pi	= pathinfo($filename);
			if( $pi['extension'] != 'yaml' ) {
				unset($entities[$i]);
				continue;
			}
			$filename	= $pi['filename'];
		}
		return $entities;
	}
	
	/** Load an entity descriptor from configuraiton file
	 * @param string $name
	 * @param string $class
	 * @throws Exception
	 * @return EntityDescriptor
	 */
	public static function load($name, $class=null) {
		$descriptorPath = ENTITY_DESCRIPTOR_CONFIG_PATH.$name;
		$cache = new FSCache(self::DESCRIPTORCLASS, $name, filemtime(YAML::getFilePath($descriptorPath)));
		
		// Comment when editing class and entity field types
		$descriptor	= null;
		try {
			if( !defined('ENTITY_ALWAYS_RELOAD')
					&& $cache->get($descriptor)
					&& isset($descriptor->version)
					&& $descriptor->version==self::VERSION ) {
				return $descriptor;
			}
		} catch( Exception $e ) {
			// If file is corrupted (version mismatch ?)
			$cache->reset();
		}

		$conf = YAML::build($descriptorPath, true);
// 		debug('Fields conf of '.$name, $conf->fields);
		if( empty($conf->fields) ) {
			throw new \Exception('Descriptor file for "'.$name.'" is corrupted, empty or not found, there is no field.');
		}
		// Build descriptor
		//    Parse Config file
		//      Fields
		$fields	= array();
		if( !empty($conf->parent) ) {
			if( !is_array($conf->parent) ) {
				$conf->parent = array($conf->parent);
			}
			foreach( $conf->parent as $p ) {
				$p	= static::load($p);
				if( !empty($p) ) {
					$fields	= array_merge($fields, $p->getFields());
				}
			}
		}
		$IDField	= $class ? $class::getIDField() : self::IDFIELD;
// 		$fields[$IDField]	= (object) array('name'=>$IDField, 'type'=>'ref', 'args'=>(object)array('decimals'=>0, 'min'=>0, 'max'=>4294967295), 'writable'=>false, 'nullable'=>false);
		$fields[$IDField]	= FieldDescriptor::buildIDField($IDField);
		foreach( $conf->fields as $fieldName => $fieldInfos ) {
			$fields[$fieldName]	= FieldDescriptor::parseType($fieldName, $fieldInfos);<commit_msg>comment<commit_after><?php
namespace Orpheus\EntityDescriptor;

use Orpheus\Cache\FSCache;
use Orpheus\Config\YAML\YAML;
use Orpheus\Publisher\Exception\InvalidFieldException;
use \Exception;
use Orpheus\Publisher\Util\SlugGenerator;

/** A class to describe an entity
 * 
 * @author <NAME>
 * 
 * This class uses a YAML configuration file to describe the entity.
 * Thus you can easily update your database using dev_entities module and it validate the input data for you.
 */
class EntityDescriptor {

	protected $class;
	protected $name;
	protected $version;
    /* @var $fields Field[] */
	protected $fields	= array();
	protected $indexes	= array();
	protected $abstract	= false;
	
	const FLAG_ABSTRACT	= 'abstract';
	
	const DESCRIPTORCLASS	= 'EntityDescriptor';
	const IDFIELD			= 'id';
	const VERSION			= 4;

	/**
	 * Get all available entity descriptor
	 * 
	 * @return EntityDescriptor[]
	 */
	public static function getAllEntityDescriptors() {
		$entities	= array();
		foreach( static::getAllEntities() as $entity ) {
			$entities[$entity] = EntityDescriptor::load($entity);
		}
		return $entities;
	}

	/**
	 * Get all available entities
	 *
	 * @return string[]
	 */
	public static function getAllEntities() {
		$entities	= cleanscandir(pathOf(CONFDIR.ENTITY_DESCRIPTOR_CONFIG_PATH));
		foreach( $entities as $i => &$filename ) {
			$pi	= pathinfo($filename);
			if( $pi['extension'] != 'yaml' ) {
				unset($entities[$i]);
				continue;
			}
			$filename	= $pi['filename'];
		}
		return $entities;
	}
	
	/** Load an entity descriptor from configuraiton file
	 * @param string $name
	 * @param string $class
	 * @throws Exception
	 * @return EntityDescriptor
	 */
	public static function load($name, $class=null) {
		$descriptorPath = ENTITY_DESCRIPTOR_CONFIG_PATH.$name;
		$cache = new FSCache(self::DESCRIPTORCLASS, $name, filemtime(YAML::getFilePath($descriptorPath)));
		
		// Comment when editing class and entity field types
		$descriptor	= null;
		try {
			if( !defined('ENTITY_ALWAYS_RELOAD')
					&& $cache->get($descriptor)
					&& isset($descriptor->version)
					&& $descriptor->version==self::VERSION ) {
				return $descriptor;
			}
		} catch( Exception $e ) {
			// If file is corrupted (version mismatch ?)
			$cache->reset();
		}
		// Unable to get from cache, building new one
		
		$conf = YAML::build($descriptorPath, true);
// 		debug('Fields conf of '.$name, $conf->fields);
		if( empty($conf->fields) ) {
			throw new \Exception('Descriptor file for "'.$name.'" is corrupted, empty or not found, there is no field.');
		}
		// Build descriptor
		//    Parse Config file
		//      Fields
		$fields	= array();
		if( !empty($conf->parent) ) {
			if( !is_array($conf->parent) ) {
				$conf->parent = array($conf->parent);
			}
			foreach( $conf->parent as $p ) {
				$p	= static::load($p);
				if( !empty($p) ) {
					$fields	= array_merge($fields, $p->getFields());
				}
			}
		}
		$IDField	= $class ? $class::getIDField() : self::IDFIELD;
// 		$fields[$IDField]	= (object) array('name'=>$IDField, 'type'=>'ref', 'args'=>(object)array('decimals'=>0, 'min'=>0, 'max'=>4294967295), 'writable'=>false, 'nullable'=>false);
		$fields[$IDField]	= FieldDescriptor::buildIDField($IDField);
		foreach( $conf->fields as $fieldName => $fieldInfos ) {
			$fields[$fieldName]	= FieldDescriptor::parseType($fieldName, $fieldInfos);
{'fraction_non_alphanumeric': 0.15764953411481816, 'fraction_numerical': 0.003907424105801022, 'mean_word_length': 3.981287425149701, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4999818', 'n_tokens_mistral': 2423, 'n_tokens_neox': 2136, 'n_words': 531}