li3_docs / branches / master / extensions / adapter / g11n / catalog / Docs.php

history
<?php
/**
 * Lithium: the most rad php framework
 *
 * @copyright     Copyright 2011, Union of RAD (http://union-of-rad.org)
 * @license       http://opensource.org/licenses/bsd-license.php The BSD License
 */

namespace li3_docs\extensions\adapter\g11n\catalog;

use Exception;
use RecursiveIteratorIterator;
use RecursiveDirectoryIterator;
use lithium\core\Libraries;
use lithium\analysis\Inspector;
use lithium\analysis\Docblock;
use lithium\util\Set;

class Docs extends \lithium\g11n\catalog\Adapter {

	/**
	 * Constructor.
	 *
	 * @param array $config Available configuration options are:
	 *        - `'library'`
	 *        - `'scope'`: Scope to use.
	 * @return void
	 */
	public function __construct($config = array()) {
		$defaults = array('library' => null, 'scope' => null);
		parent::__construct($config + $defaults);
	}

	/**
	 * Initializer.  Checks if the configured path exists.
	 *
	 * @return void
	 * @throws \Exception
	 */
	protected function _init() {
		parent::_init();

		if (!Libraries::get($this->_config['library'])) {
			throw new Exception("Library `{$this->_config['library']}` is not configured");
		}
	}

	/**
	 * Extracts data from files within configured path recursively.
	 *
	 * @param string $category Dot-delimited category.
	 * @param string $locale A locale identifier.
	 * @param string $scope The scope for the current operation.
	 * @return mixed
	 */
	public function read($category, $locale, $scope) {
		if ($scope != $this->_config['scope']) {
			return null;
		}
		$library = Libraries::get($this->_config['library']);
		$data = array();

		$classes = Libraries::find($this->_config['library'], array(
			'recursive' => true,
			'exclude' => '/\w+Test$|Mock+\w|webroot|index$|^app\\\\config|^\w+\\\\views\/|\./'
		));
		foreach ($classes as $class) {
			if (preg_match('/\\\(libraries|plugins)\\\/', $class)) {
				continue;
			}
			$data += $this->_parseClass($class);
		}
		return $data;
	}

	public function _parseClass($class) {
		$data = array();

		// $methods = Inspector::methods($class, null, array('public' => false));
		$methods = get_class_methods($class);
		$properties = array_keys(get_class_vars($class));

		$ident = $class;
		$info = Inspector::info($ident);
		$info = Docblock::comment($info['comment']);
		$data = $this->_merge($data, array(
			'id' => $info['description'],
			'comments' => array($ident)
		));
		$this->_merge($data, array(
			'id' => $info['text'],
			'comments' => array($class)
		));

		foreach ($methods as $method) {
			$ident = "{$class}::{$method}()";
			$info = Inspector::info($ident);
			$info = Docblock::comment($info['comment']);

			$this->_merge($data, array(
				'id' => $info['description'],
				'comments' => array($ident)
			));
			$this->_merge($data, array(
				'id' => $info['text'],
				'comments' => array($ident)
			));

			if (isset($info['tags']['return'])) {
				$this->_merge($data, array(
					'id' => $info['tags']['return'],
					'comments' => array($ident)
				));
			}

			foreach (Set::extract($info, '/tags/params/text') as $text) {
				$this->_merge($data, array(
					'id' => $text,
					'comments' => array($ident)
				));
			}
		}
		foreach ($properties as $property) {
			$ident = "{$class}::\${$property}";
			$info = Inspector::info($ident);
			$info = Docblock::comment($info['comment']);
			$data = $this->_merge($data, array(
				'id' => $info['description'],
				'comments' => array($ident)
			));
			$data = $this->_merge($data, array(
				'id' => $info['text'],
				'comments' => array($ident)
			));
		}
		return $data;
	}

	/**
	 * Cleans and merges a message item into given data.
	 *
	 * The implementation of the `$cleanup` closure should correspond to the one
	 * used in the templates.
	 *
	 * @param array $data Data to merge item into.
	 * @param array $item Item to merge into $data.
	 * @return void
	 * @see lithium\g11n\catalog\adapter\Base::_merge()
	 */
	protected function _merge(array $data, array $item) {
		$cleanup = function($text) {
			return preg_replace('/\n\s+-\s/msi', "\n\n - ", $text);
		};
		if (isset($item['id'])) {
			$item['id'] = $cleanup($item['id']);
		}
		return parent::_merge($data, $item);
	}
}

?>