/** * Does necessary preparations for saving a stream in the database. * @method beforeSave * @param {array} $modifiedFields * The array of fields * @return {array} * @throws {Exception} * If mandatory field is not set */ function beforeSave($modifiedFields) { if (empty($this->attributes)) { $this->attributes = '{}'; } if (!$this->retrieved) { // Generate a unique name for the stream if (!isset($modifiedFields['name'])) { $this->name = $modifiedFields['name'] = Streams::db()->uniqueId(Streams_Stream::table(), 'name', array('publisherId' => $this->publisherId), array('prefix' => $this->type . '/Q')); } // we don't want user to update private fields but will set initial values to them $privateFieldNames = self::getConfigField($this->type, 'private', array()); // magic fields are handled by parent method $magicFieldNames = array('insertedTime', 'updatedTime'); $privateFieldNames = array_diff($privateFieldNames, $magicFieldNames); $streamTemplate = $this->getStreamTemplate('Streams_Stream'); $fieldNames = Streams_Stream::fieldNames(); if ($streamTemplate) { // if template exists copy all non-PK and non-magic fields from template foreach (array_diff($fieldNames, $this->getPrimaryKey(), $magicFieldNames) as $field) { if (in_array($field, $privateFieldNames) || !array_key_exists($field, $modifiedFields)) { $this->{$field} = $modifiedFields[$field] = $streamTemplate->{$field}; } } } else { // otherwise (no template) set all private fields to defaults foreach ($privateFieldNames as $field) { $defaults = self::getConfigField($this->type, 'defaults', Streams_Stream::$DEFAULTS); $this->{$field} = $modifiedFields[$field] = Q::ifset($defaults, $field, null); } } // Assign default values to fields that haven't been set yet foreach (array_diff($fieldNames, $magicFieldNames) as $field) { if (!array_key_exists($field, $this->fields) and !array_key_exists($field, $modifiedFields)) { $defaults = self::getConfigField($this->type, 'defaults', Streams_Stream::$DEFAULTS); $this->{$field} = $modifiedFields[$field] = Q::ifset($defaults, $field, null); } } // Get all access templates and save corresponding access $type = true; $accessTemplates = $this->getStreamTemplate('Streams_Access', $type); for ($i = 1; $i <= 3; ++$i) { foreach ($accessTemplates[$i] as $template) { $access = new Streams_Access(); $access->copyFrom($template->toArray()); $access->publisherId = $this->publisherId; $access->streamName = $this->name; if (!$access->save(true)) { return false; // JUNK: this leaves junk in the database, but preserves consistency } } } } /** * @event Streams/Stream/save/$streamType {before} * @param {Streams_Stream} stream * @return {false} To cancel further processing */ $params = array('stream' => $this, 'modifiedFields' => $modifiedFields); if (false === Q::event("Streams/Stream/save/{$this->type}", $params, 'before')) { return false; } foreach ($this->fields as $name => $value) { if (!empty($this->fieldsModified[$name])) { $modifiedFields[$name] = $value; } } $this->beforeSaveExtended($modifiedFields); $result = parent::beforeSave($modifiedFields); // Assume that the stream's name is not being changed $fields = array('Streams/user/firstName' => false, 'Streams/user/lastName' => false, 'Streams/user/username' => 'username', 'Streams/user/icon' => 'icon'); if (!isset($fields[$this->name])) { return $result; } $field = $this->name === 'Streams/user/icon' ? 'icon' : 'content'; $wasModified = !empty($this->fieldsModified[$field]) or !empty($this->fieldsModified['readLevel']); if (!$wasModified) { return $result; } if ($publicField = $fields[$this->name] and !Q::eventStack('Db/Row/Users_User/saveExecute')) { Streams::$beingSaved[$publicField] = $this; try { $user = Users_User::fetch($this->publisherId, true); $user->{$publicField} = $modifiedFields[$field]; $user->save(); } catch (Exception $e) { Streams::$beingSaved[$publicField] = array(); throw $e; } Streams::$beingSaved[$publicField] = array(); return Streams::$beingSavedQuery; } if ($this->retrieved and !$publicField) { // Update all avatars corresponding to access rows for this stream $taintedAccess = Streams_Access::select('*')->where(array('publisherId' => $this->publisherId, 'streamName' => $this->name))->fetchDbRows(); Streams::updateAvatars($this->publisherId, $taintedAccess, $this, true); } return $result; }
/** * Creates a new stream in the system * @method create * @static * @param {string} $asUserId The user who is attempting to create the stream. * @param {string} $publisherId The id of the user to publish the stream. * @param {string} $type The type of the stream to create. * @param {array} $fields Use this to set additional fields for the stream: * @param {string} [$fields.title=null] You can set the stream's title * @param {string} [$fields.icon=null] You can set the stream's icon * @param {string} [$fields.title=null] You can set the stream's content * @param {string} [$fields.attributes=null] You can set the stream's attributes directly as a JSON string * @param {string|integer} [$fields.readLevel=null] You can set the stream's read access level, see Streams::$READ_LEVEL * @param {string|integer} [$fields.writeLevel=null] You can set the stream's write access level, see Streams::$WRITE_LEVEL * @param {string|integer} [$fields.adminLevel=null] You can set the stream's admin access level, see Streams::$ADMIN_LEVEL * @param {string} [$fields.name=null] Here you can specify an exact name for the stream to be created. Otherwise a unique one is generated automatically. * @param {boolean} [$fields.skipAccess=false] Skip all access checks when creating and relating the stream. * @param {array} [$relate=array()] * The user would also be authorized if the stream would be related to * an existing category stream, in which the user has a writeLevel of at least "relate", * and the user that would be publishing this new stream has a template for this stream type * that is related to either the category stream or a template matching the category stream. * To test for this, pass an array with the following keys: * @param {string} $relate.publisherId The id of the user publishing that stream, defaults to $publisherId * @param {string} $relate.streamName The name of the stream to which the new stream would be related * @param {string} [$relate.type] The type of relation, defaults to "" * @param {string} [$relate.weight] To set the weight for the relation * @return {Streams_Stream|boolean} Returns the stream that was created. * @throws {Users_Exception_NotAuthorized} */ static function create($asUserId, $publisherId, $type, $fields = array(), $relate = null) { $skipAccess = Q::ifset($fields, 'skipAccess', false); if (!isset($asUserId)) { $asUserId = Users::loggedInUser(); if (!$asUserId) { $asUserId = ""; } } if ($asUserId instanceof Users_User) { $asUserId = $asUserId->id; } if ($publisherId instanceof Users_User) { $publisherId = $publisherId->id; } $authorized = self::isAuthorizedToCreate($asUserId, $publisherId, $type, $relate); if (!$authorized and !$skipAccess) { throw new Users_Exception_NotAuthorized(); } // OK we are good to go! $stream = new Streams_Stream(); $stream->publisherId = $publisherId; if (!empty($fields['name'])) { $p = new Q_Tree(); $p->load(STREAMS_PLUGIN_CONFIG_DIR . DS . 'streams.json'); $p->load(APP_CONFIG_DIR . DS . 'streams.json'); if ($info = $p->get($fields['name'], array())) { foreach (Base_Streams_Stream::fieldNames() as $f) { if (isset($info[$f])) { $stream->{$f} = $info[$f]; } } } } if (!isset($stream->type)) { $stream->type = $type; } // prepare attributes field if (isset($fields['attributes']) and is_array($fields['attributes'])) { $fields['attributes'] = json_encode($fields['attributes']); } // extend with any config defaults for this stream type $fieldNames = Streams::getExtendFieldNames($type); $fieldNames[] = 'name'; $defaults = Q_Config::get('Streams', 'types', $type, 'defaults', array()); foreach ($fieldNames as $f) { if (isset($fields[$f])) { $stream->{$f} = $fields[$f]; } else { if (array_key_exists($f, $defaults)) { $stream->{$f} = $defaults[$f]; } } } // ready to persist this stream to the database if ($relate['streamName']) { $rs = Streams::fetchOne($asUserId, $relate['publisherId'], $relate['streamName']); if ($rs and $rs->inheritAccess) { // inherit from the same stream $rs does $inherit = $rs->inheritAccess; } else { // inherit from $rs $json = Q::json_encode(array(array($relate['publisherId'], $relate['streamName']))); } $stream->inheritAccess = $json; } $stream->save(); $stream->post($asUserId, array('type' => 'Streams/created', 'content' => '', 'instructions' => Q::json_encode($stream->toArray())), true); // relate the stream to category stream, if any if ($relate['streamName']) { $result = Streams::relate($asUserId, $relate['publisherId'], $relate['streamName'], $relate['type'], $stream->publisherId, $stream->name, array('weight' => isset($relate['weight']) ? $relate['weight'] : null, 'skipAccess' => $skipAccess)); Q_Response::setSlot('messageTo', $result['messageTo']->exportArray()); } self::$fetch[$asUserId][$publisherId][$stream->name] = array('*' => $stream); return $stream; }
/** * Gets a row that extends the stream, or a field of the stream. * Example: $stream->Websites_Article, $stream->title or $stream->article * @method __get * @param {string} $name * @return {mixed} */ function __get($name) { if (isset($this->rows[$name])) { return $this->rows[$name]; } return parent::__get($name); }
/** * The setUp() method is called the first time * an object of this class is constructed. */ function setUp() { parent::setUp(); // INSERT YOUR CODE HERE // e.g. $this->hasMany(...) and stuff like that. }
/** * Method is called before setting the field and verifies that, if it is a string, * it contains a JSON array. * @method beforeSet_permissions * @param {string} $value * @return {array} An array of field name and value * @throws {Exception} An exception is thrown if $value is not string or is exceedingly long */ function beforeSet_permissions($value) { if (is_string($value)) { $decoded = Q::json_decode($value, true); if (!is_array($decoded) or Q::isAssociative($decoded)) { throw new Q_Exception_WrongValue(array('field' => 'permissions', 'range' => 'JSON array')); } } return parent::beforeSet_permissions($value); }