我正在使用Zend Framework和MySQL。我的应用程序的用户将能够存储任意数量的数据,结构如表。问题是,我不会事先知道“列”。因此,我无法创建现成的表或现成的Zend Framework模型。
在以前版本的应用程序中,自动从数据生成表模式。这很好用。这次的问题是我不知道如何创建Zend框架模型来表示任意数据源。有谁知道我的案例最好的策略是什么?不,重新考虑我的申请要求不是一个选择:)。
顺便说一句:在应用程序的更旧版本中,数据存储为JSON。这种方法很慢。
答案 0 :(得分:5)
如果您不能使用NoSQL,请查看实体属性值(EAV)模型。它通过一种元数据模型允许灵活的属性。
如果您拥有大量数据,它可能无法正常运行,并且维护与完全关系模式相比可能会有点痛苦。我不推荐它作为第一个选项,但如果你真的不能预先了解架构,那么你可以采用一种方式。
答案 1 :(得分:0)
自从我提供答案后,我感到很受鼓舞......我掀起了一个小小的课程,为你做这个......
kick_ass_data_t
CREATE TABLE `kick_ass_data_t` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`key_text` varchar(1024) NOT NULL,
`value_text` mediumtext,
`create_date` datetime NOT NULL,
`lmod_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB
<?php
/**
* Property Bag
*/
class KickAssProps
{
/**
* gets a property from a database bag.
* If $remove is true, item is deleted after retrieved.
* @param string $key
* @param mixed $defaultValue
* @param bool $remove
* @return mixed
*/
public function getProperty( $key, $defaultValue = null, $remove = false )
{
$_result = $defaultValue;
// Lookup key
if ( null === ( $_model = $this->_loadProperty( $key ) ) )
{
$_model = new KickAssData();
$_model->key_text = $key;
$_model->value_text = self::_serialize( $_result );
$_model->create_date = date( 'Y-m-d H:i:s' );
if ( ! $_model->save() )
{
// bitch alot...
}
}
else
$_result = self::_unserialize( $_model->value_text );
if ( $remove )
{
if ( ! $_model->delete() )
{
// bitch alot...
}
}
return $_result;
}
/**
* sets a property in a database bag.
* @param string $key
* @param mixed $value
* @return \KickAssProps $this
*/
public function setProperty( $key, $value = null )
{
// Lookup key
if ( null === ( $_model = $this->_loadProperty( $key ) ) )
{
$_model = new KickAssData();
$_model->key_text = $key;
$_model->create_date = date( 'Y-m-d H:i:s' );
}
$_model->value_text = self::_serialize( $value );
if ( ! $_model->save() )
{
// bitch alot...
}
// Allow chaining...
return $this;
}
/**
* Retrieves a property from the database bag
* @param string $key
* @return KickAssData
*/
protected function _loadProperty( $key )
{
// Example sql
// $_sql = 'select * from kick_ass_data_t where key_text = :key_text';
// read row from database however you want... this is how I'd do it in Yii (http://www.yiiframework.com)
$_model = KickAssData::model()->find(
'key_text = :key_text',
array(
':key_text' => $key
)
);
return $_model;
}
/**
* Serializer that can handle SimpleXmlElement objects
* @param mixed $value
* @return mixed
*/
protected static function _serialize( $value )
{
try
{
if ( $value instanceof SimpleXMLElement )
return $value->asXML();
if ( is_object( $value ) )
return serialize( $value );
}
catch ( Exception $_ex )
{
}
return $value;
}
/**
* Unserializer that can handle SimpleXmlElement objects
* @param mixed $value
* @return mixed
*/
protected static function _unserialize( $value )
{
try
{
if ( self::_isSerialized( $value ) )
{
if ( $value instanceof SimpleXMLElement )
return simplexml_load_string( $value );
return @unserialize( $value );
}
}
catch ( Exception $_ex )
{
}
return $value;
}
/**
* Tests if a value needs unserialization by unserializing the value then
* re-serializing. If both are successful then it's cool. I know this is
* slower but it guarantees data integrity in my database.
* @param mixed $value
* @return boolean
*/
protected static function _isSerialized( $value )
{
return !( false === @unserialize( $value ) && $value != @serialize( false ) );
}
}