Файл: onlinepoisk.wm-scripts.ru/vendor/AR/lib/Serialization.php
Строк: 242
<?php
/**
 * @package ActiveRecord
 */
namespace ActiveRecord;
use XmlWriter;
/**
 * Base class for Model serializers.
 *
 * All serializers support the following options:
 *
 * <ul>
 * <li><b>only:</b> a string or array of attributes to be included.</li>
 * <li><b>exclude:</b> a string or array of attributes to be excluded.</li>
 * <li><b>methods:</b> a string or array of methods to invoke. The method's name will be used as a key for the final attributes array
 * along with the method's returned value</li>
 * <li><b>include:</b> a string or array of associated models to include in the final serialized product.</li>
 * <li><b>skip_instruct:</b> set to true to skip the <?xml ...?> declaration.</li>
 * </ul>
 *
 * Example usage:
 *
 * <code>
 * # include the attributes id and name
 * # run $model->encoded_description() and include its return value
 * # include the comments association
 * # include posts association with its own options (nested)
 * $model->to_json(array(
 *   'only' => array('id','name', 'encoded_description'),
 *   'methods' => array('encoded_description'),
 *   'include' => array('comments', 'posts' => array('only' => 'id'))
 * ));
 *
 * # exclude the password field from being included
 * $model->to_xml(array('exclude' => 'password')));
 * </code>
 *
 * @package ActiveRecord
 * @link http://www.phpactiverecord.org/guides/utilities#topic-serialization
 */
abstract class Serialization
{
    protected $model;
    protected $options;
    protected $attributes;
    /**
     * Set this to true if the serializer needs to create a nested array keyed
     * on the name of the included classes such as for xml serialization.
     *
     * Setting this to true will produce the following attributes array when
     * the include option was used:
     *
     * <code>
     * $user = array('id' => 1, 'name' => 'Tito',
     *   'permissions' => array(
     *     'permission' => array(
     *       array('id' => 100, 'name' => 'admin'),
     *       array('id' => 101, 'name' => 'normal')
     *     )
     *   )
     * );
     * </code>
     *
     * Setting to false will produce this:
     *
     * <code>
     * $user = array('id' => 1, 'name' => 'Tito',
     *   'permissions' => array(
     *     array('id' => 100, 'name' => 'admin'),
     *     array('id' => 101, 'name' => 'normal')
     *   )
     * );
     * </code>
     *
     * @var boolean
     */
    protected $includes_with_class_name_element = false;
    /**
     * Constructs a {@link Serialization} object.
     *
     * @param Model $model The model to serialize
     * @param array &$options Options for serialization
     * @return Serialization
     */
    public function __construct(Model $model, &$options)
    {
        $this->model = $model;
        $this->options = $options;
        $this->attributes = $model->attributes();
        $this->parse_options();
    }
    private function parse_options()
    {
        $this->check_only();
        $this->check_except();
        $this->check_methods();
        $this->check_include();
    }
    private function check_only()
    {
        if (isset($this->options['only']))
        {
            $this->options_to_a('only');
            $exclude = array_diff(array_keys($this->attributes),$this->options['only']);
            $this->attributes = array_diff_key($this->attributes,array_flip($exclude));
        }
    }
    private function check_except()
    {
        if (isset($this->options['except']) && !isset($this->options['only']))
        {
            $this->options_to_a('except');
            $this->attributes = array_diff_key($this->attributes,array_flip($this->options['except']));
        }
    }
    private function check_methods()
    {
        if (isset($this->options['methods']))
        {
            $this->options_to_a('methods');
            foreach ($this->options['methods'] as $method)
            {
                if (method_exists($this->model, $method))
                    $this->attributes[$method] = $this->model->$method();
            }
        }
    }
    private function check_include()
    {
        if (isset($this->options['include']))
        {
            $this->options_to_a('include');
            $serializer_class = get_class($this);
            foreach ($this->options['include'] as $association => $options)
            {
                if (!is_array($options))
                {
                    $association = $options;
                    $options = array();
                }
                try {
                    $assoc = $this->model->$association;
                    if (!is_array($assoc))
                    {
                        $serialized = new $serializer_class($assoc, $options);
                        $this->attributes[$association] = $serialized->to_a();;
                    }
                    else
                    {
                        $includes = array();
                        foreach ($assoc as $a)
                        {
                            $serialized = new $serializer_class($a, $options);
                            if ($this->includes_with_class_name_element)
                                $includes[strtolower(get_class($a))][] = $serialized->to_a();
                            else
                                $includes[] = $serialized->to_a();
                        }
                        $this->attributes[$association] = $includes;
                    }
                } catch (UndefinedPropertyException $e) {
                    ;//move along
                }
            }
        }
    }
    final protected function options_to_a($key)
    {
        if (!is_array($this->options[$key]))
            $this->options[$key] = array($this->options[$key]);
    }
    /**
     * Returns the attributes array.
     * @return array
     */
    final public function to_a()
    {
        $date_format = Config::instance()->get_date_format();
        foreach ($this->attributes as &$value)
        {
            if ($value instanceof DateTime)
                $value = $value->format($date_format);
        }
        return $this->attributes;
    }
    /**
     * Returns the serialized object as a string.
     * @see to_s
     * @return string
     */
    final public function __toString()
    {
        return $this->to_s();
    }
    /**
     * Performs the serialization.
     * @return string
     */
    abstract public function to_s();
};
/**
 * JSON serializer.
 *
 * @package ActiveRecord
 */
class JsonSerializer extends Serialization
{
    public static $include_root = false;
    public function to_s()
    {
        return json_encode(self::$include_root ? array(strtolower(get_class($this->model)) => $this->to_a()) : $this->to_a());
    }
}
/**
 * XML serializer.
 *
 * @package ActiveRecord
 */
class XmlSerializer extends Serialization
{
    private $writer;
    public function __construct(Model $model, &$options)
    {
        $this->includes_with_class_name_element = true;
        parent::__construct($model,$options);
    }
    public function to_s()
    {
        return $this->xml_encode();
    }
    private function xml_encode()
    {
        $this->writer = new XmlWriter();
        $this->writer->openMemory();
        $this->writer->startDocument('1.0', 'UTF-8');
        $this->writer->startElement(strtolower(denamespace(($this->model))));
        $this->write($this->to_a());
        $this->writer->endElement();
        $this->writer->endDocument();
        $xml = $this->writer->outputMemory(true);
        if (@$this->options['skip_instruct'] == true)
            $xml = preg_replace('/<?xml version.*??>/','',$xml);
        return $xml;
    }
    private function write($data, $tag=null)
    {
        foreach ($data as $attr => $value)
        {
            if ($tag != null)
                $attr = $tag;
            if (is_array($value) || is_object($value))
            {
                if (!is_int(key($value)))
                {
                    $this->writer->startElement($attr);
                    $this->write($value);
                    $this->writer->endElement();
                }
                else
                    $this->write($value, $attr);
                continue;
            }
            $this->writer->writeElement($attr, $value);
        }
    }
}
?>