/** * * Limits the number of words in a string. * @param string $string * @param uint $word_limit * number of words to return * @param optional array * if $options['append_ellipsis'] is set, append that string to the end * of strings that have been truncated * if $options['characters'] is true, limit by characters rather than words * (a single API call for both is convenient when this is wrapped by other calls) * Whitespace will be collapsed to single spaces. UTF8-aware where supported * @return string * new string containing only words up to the word limit. */ public static function limitWords($string, $word_limit, $options = array()) { $regexp = '/\\s+/'; if (function_exists('mb_strtolower')) { $regexp .= 'u'; } $words = preg_split($regexp, $string, $word_limit + 1); $num_words = count($words); if (isset($options['characters']) && $options['characters']) { // Call limitCharacters, but only after ensuring the same space-folding behavior return aString::limitCharacters(implode(' ', $words), $word_limit, $options); } # TBB: if there are $word_limit words or less, this check is necessary # to prevent the last word from being lost. if ($num_words > $word_limit) { array_pop($words); } $string = implode(' ', $words); $append_ellipsis = false; if (isset($options['append_ellipsis'])) { $append_ellipsis = $options['append_ellipsis']; } if ($append_ellipsis == true && $num_words > $word_limit) { $string .= '…'; } return $string; }
public function newAreaVersion($name, $action, $params = false) { $diff = ''; if ($params === false) { $params = array(); } $this->begin(); // We use the slots already queried as a basis for the new version, // because that makes rollback easy to implement etc. But we // MUST fetch the latest copy of the area object to make sure // we don't create duplicate versions. // When we're adding a new slot to an area we need to make sure it // it is first in the hash so it gets ranked first if ($action === 'add') { $diff = '<strong>' . aString::limitCharacters($params['slot']->getSearchText(), 20) . "</strong>"; $newSlots = $this->getArea($name, $params['slot'], true); } else { $newSlots = $this->getArea($name); } $area = aAreaTable::retrieveOrCreateByPageIdAndName($this->id, $name); if (!$area->id) { // We need an ID established $area->save(); } $areaVersion = new aAreaVersion(); $areaVersion->area_id = $area->id; $areaVersion->version = $area->latest_version + 1; // Don't crash on an anon edit, it's odd but you could authorize it with the 'edit' option if (sfContext::getInstance() && sfContext::getInstance()->getUser()->getGuardUser()) { $areaVersion->author_id = sfContext::getInstance()->getUser()->getGuardUser()->getId(); } if ($action === 'delete') { if (isset($newSlots[$params['permid']])) { $diff = '<strike>' . aString::limitCharacters($newSlots[$params['permid']]->getSearchText(), 20) . '</strike>'; unset($newSlots[$params['permid']]); } } elseif ($action === 'update') { $oldText = ''; if (isset($newSlots[$params['permid']])) { $oldText = $newSlots[$params['permid']]->getSearchText(); } $newText = $params['slot']->getSearchText(); $fullDiff = aString::diff($oldText, $newText); $diff = ''; if (!empty($fullDiff['onlyin1'])) { $diff .= '<strike>' . aString::limitCharacters($fullDiff['onlyin1'][0], 20) . '</strike>'; } if (!empty($fullDiff['onlyin2'])) { $diff .= '<strong>' . aString::limitCharacters($fullDiff['onlyin2'][0], 20) . '</strong>'; } $newSlots[$params['permid']] = $params['slot']; } elseif ($action === 'variant') { $newSlot = $newSlots[$params['permid']]->copy(); if (!$newSlot) { throw new sfException('Slot does not exist'); } $variants = sfConfig::get('app_a_slot_variants'); if (!isset($variants[$newSlot->type][$params['variant']])) { throw new sfException('Variant not defined for this slot type'); } $newSlot->variant = $params['variant']; // Must have an id before we can make an AreaVersionSlot referencing it $newSlot->save(); $newSlots[$params['permid']] = $newSlot; $diff = $newSlot->variant; } elseif ($action === 'add') { // We took care of this in the getArea call } elseif ($action === 'sort') { $diff = '[Reordered slots]'; $newerSlots = array(); foreach ($params['permids'] as $permid) { $newerSlots[$permid] = $newSlots[$permid]; } $newSlots = $newerSlots; } elseif ($action === 'revert') { // TODO: actually represent the changes carried out by the reversion // in the diff. That's rather expensive because many slots in the area // may have changed all at once. $diff = '[Reverted to older version]'; # We just want whatever is in the slot cache copied to a new version } $areaVersion->diff = $diff; $areaVersion->save(); $rank = 1; foreach ($newSlots as $permid => $slot) { // After unset, foreach shows keys but has null values if (!$slot) { continue; } $areaVersionSlot = new aAreaVersionSlot(); $areaVersionSlot->slot_id = $slot->id; $areaVersionSlot->permid = $permid; $areaVersionSlot->area_version_id = $areaVersion->id; $areaVersionSlot->rank = $rank++; $areaVersionSlot->save(); } $area->latest_version++; $area->save(); if (sfConfig::get('app_a_defer_search_updates', false)) { // Deferred updates are sometimes nice for performance... aLuceneUpdateTable::requestUpdate($this); } else { // ... But the average developer hates cron. // Without this the changes we just made aren't visible to getSearchText, // we need to trigger a thorough recaching aPageTable::retrieveByIdWithSlots($this->id); $this->updateLuceneIndex(); } $this->end(); }
/** * SAVE ANY CHANGES to the actual page object FIRST before you call this method. * @param mixed $name * @param mixed $action * @param mixed $params */ public function newAreaVersion($name, $action, $params = false) { // Lock this page while adding a new version to it. This prevents race conditions with the // assignment of new permids and ranks (fixes #306) aTools::lock('page_' . $this->id); $diff = ''; if ($params === false) { $params = array(); } $this->begin(); // We use the slots already queried as a basis for the new version, // because that makes rollback easy to implement etc. But we // MUST fetch the latest copy of the area object to make sure // we don't create duplicate versions. // When we're adding a new slot to an area we need to make sure it // it is first in the hash so it gets ranked first if ($action === 'add') { // New: support for specifying whether the new slot is at top or bottom of the area $top = !isset($params['top']) || $params['top']; $diff = isset($params['slot']) ? "<strong>" . aString::limitCharacters($params['slot']->getSearchText(), 20) . "</strong>" : ''; $newSlots = $this->getSlotsByAreaName($name, $params['slot'], $top); } else { $newSlots = $this->getSlotsByAreaName($name); } $area = aAreaTable::retrieveOrCreateByPageIdAndName($this->id, $name); if (!$area->id) { // We need an ID established $area->save(); } $areaVersion = new aAreaVersion(); $areaVersion->area_id = $area->id; $areaVersion->version = $area->latest_version + 1; // Don't crash on an anon edit, such as an edit made by a task if (sfContext::hasInstance() && sfContext::getInstance()->getUser()->getGuardUser()) { $areaVersion->author_id = sfContext::getInstance()->getUser()->getGuardUser()->getId(); } if ($action === 'delete') { if (isset($newSlots[$params['permid']])) { $diff = '<strike>' . aString::limitCharacters($newSlots[$params['permid']]->getSearchText(), 20) . '</strike>'; unset($newSlots[$params['permid']]); } } elseif ($action === 'update') { $oldText = ''; if (isset($newSlots[$params['permid']])) { $oldText = $newSlots[$params['permid']]->getSearchText(); } $newText = isset($params['slot']) ? $params['slot']->getSearchText() : ''; $fullDiff = aString::diff($oldText, $newText); $diff = ''; if (!empty($fullDiff['onlyin1'])) { $diff .= '<strike>' . aString::limitCharacters($fullDiff['onlyin1'][0], 20) . '</strike>'; } if (!empty($fullDiff['onlyin2'])) { $diff .= '<strong>' . aString::limitCharacters($fullDiff['onlyin2'][0], 20) . '</strong>'; } $newSlots[$params['permid']] = $params['slot']; } elseif ($action === 'variant') { $newSlot = $newSlots[$params['permid']]->copy(); if (!$newSlot) { throw new sfException('Slot does not exist'); } $variants = sfConfig::get('app_a_slot_variants'); if (!isset($variants[$newSlot->type][$params['variant']])) { throw new sfException('Variant not defined for this slot type'); } $newSlot->variant = $params['variant']; // Must have an id before we can make an AreaVersionSlot referencing it $newSlot->save(); $newSlots[$params['permid']] = $newSlot; $diff = $newSlot->variant; } elseif ($action === 'add') { // We took care of this in the getArea call } elseif ($action === 'sort') { $diff = '[Reordered slots]'; $newerSlots = array(); foreach ($params['permids'] as $permid) { $newerSlots[$permid] = $newSlots[$permid]; } $newSlots = $newerSlots; } elseif ($action === 'revert') { // TODO: actually represent the changes carried out by the reversion // in the diff. That's rather expensive because many slots in the area // may have changed all at once. $diff = '[Reverted to older version]'; # We just want whatever is in the slot cache copied to a new version } $areaVersion->diff = $diff; $areaVersion->save(); $rank = 1; foreach ($newSlots as $permid => $slot) { // After unset, foreach shows keys but has null values if (!$slot) { continue; } $areaVersionSlot = new aAreaVersionSlot(); $areaVersionSlot->slot_id = $slot->id; $areaVersionSlot->permid = $permid; $areaVersionSlot->area_version_id = $areaVersion->id; $areaVersionSlot->rank = $rank++; $areaVersionSlot->save(); } $area->latest_version++; $area->save(); $this->requestSearchUpdate(); $this->end(); aTools::unlock(); }