/** * given a podio field object -> returns a human readable format of the field value (or app reference as array (app_id, item_id) * @param type $field should be of type PodioItemField * @return string */ public static function getFieldValue($field) { $value = ""; if ($field->type == "text" || $field->type == "number" || $field->type == "progress" || $field->type == "duration" || $field->type == "state") { if (is_string($field->values)) { // TODO refactor $value = $field->values; $value = str_ireplace('</p>', '</p><br>', $value); $value = preg_replace('/\\<br(\\s*)?\\/?\\>/i', "\n", $value); $value = strip_tags(br2nl($value)); $value = str_replace(' ', ' ', $value); $value = str_replace('&', '&', $value); } else { if (is_numeric($field->values)) { $value = $field->values; } else { echo "WARN expected string or number, but found: "; var_dump($field->values); } } return $value; } if ($field->type == "category") { $selected_categories = array(); foreach ($field->values as $category) { array_push($selected_categories, $category['text']); } return HumanFormat::implodeStrings(", ", $selected_categories); } if ($field->type == "date") { return HumanFormat::parseDate($field->values['start']) . " - " . HumanFormat::parseDate($field->values['end']); } if ($field->type == "money") { return "" . $field->values['value'] . " " . $field->values['currency']; } if ($field->type == "contact") { if (is_array($field->values) || $field->values instanceof Traversable) { foreach ($field->values as $contact) { $value .= "\nUserid: {$contact->user_id}, name: {$contact->name}, email: " . HumanFormat::implodeStrings(', ', $contact->mail) . ", phone: " . HumanFormat::implodeStrings(", ", $contact->phone); } } else { echo "WARN unexpected contact type:"; var_dump($field); } return $value; } if ($field->type == "embed") { if (is_array($field->values) || $field->values instanceof Traversable) { foreach ($field->values as $embed) { //TODO implode (general function..) $value .= "\nurl: " . $embed->original_url; } } else { echo "WARN unexpected embed type:"; var_dump($field); } return $value; } if ($field->type == "app") { if (is_array($field->values) || $field->values instanceof Traversable) { foreach ($field->values as $app) { //TODO implode (general function..) $value .= "\napp: " . $app->app->name . ", item_name: " . $app->item_name . ", title: " . $app->title; //TODO more info?! } } else { echo "WARN unexpected app type:"; var_dump($field); } return $value; } if ($field->type == "image") { $images = array(); foreach ($field->values as $image) { array_push($images, "fileid: " . $image->file_id . ", name: " . $image->name); } return HumanFormat::implodeStrings(" | ", $images); } if ($field->type == "location") { $locations = array(); foreach ($field->values as $location) { array_push($locations, $location); } return HumanFormat::implodeStrings(" | ", $locations); } echo "WARN unexpected type: "; var_dump($field); return $field->values; }
/** * Backups $app to a subfolder in $path * * @param type $app app to backup * @param type $path in this folder a subfolder for the app will be created */ function backup_app($app, $path, $downloadFiles) { $path_app = $path . '/' . fixDirName($app->config['name']); global $verbose; if ($verbose) { echo "App: " . $app->config['name'] . "\n"; echo "debug: MEMORY: " . memory_get_usage(true) . " | " . memory_get_usage(false) . "\n"; } mkdir($path_app); $appFile = ""; $appFiles = array(); $files_in_app_html = "<html><head><title>Files in app: " . $app->config['name'] . "</title></head><body>" . "<table border=1><tr><th>name</th><th>link</th><th>context</th></tr>"; try { #$appFiles = PodioFile::get_for_app($app->app_id, array('attached_to' => 'item')); $appFiles = PodioFetchAll::iterateApiCall('PodioFile::get_for_app', $app->app_id, array(), FILE_GET_FOR_APP_LIMIT); #var_dump($appFiles); PodioFetchAll::flattenObjectsArray($appFiles, PodioFetchAll::podioElements(array('file_id' => null, 'name' => null, 'link' => null, 'hosted_by' => null, 'context' => array('id' => NULL, 'type' => null, 'title' => null)))); if ($verbose) { echo "fetched information for " . sizeof($appFiles) . " files in app.\n"; } } catch (PodioError $e) { show_error($e); } try { $allitems = PodioFetchAll::iterateApiCall('PodioItem::filter', $app->app_id, array(), ITEM_FILTER_LIMIT, 'items'); echo "app contains " . sizeof($allitems) . " items.\n"; for ($i = 0; $i < sizeof($allitems); $i += ITEM_XLSX_LIMIT) { $itemFile = PodioItem::xlsx($app->app_id, array("limit" => ITEM_XLSX_LIMIT, "offset" => $i)); RateLimitChecker::preventTimeOut(); file_put_contents($path_app . '/' . $app->config['name'] . '_' . $i . '.xlsx', $itemFile); unset($itemFile); } $before = time(); gc_collect_cycles(); echo "gc took : " . (time() - $before) . " seconds.\n"; foreach ($allitems as $item) { if ($verbose) { echo " - " . $item->title . "\n"; } $folder_item = fixDirName($item->item_id . '_' . $item->title); $path_item = $path_app . '/' . $folder_item; mkdir($path_item); unset($itemFile); $itemFile = HumanFormat::toHumanReadableString($item); if ($downloadFiles) { foreach ($appFiles as $file) { if ($file->context['type'] == 'item' && $file->context['id'] == $item->item_id) { $link = downloadFileIfHostedAtPodio($path_item, $file); # $link is relative to $path_item (if downloaded): if (!preg_match("/^http/i", $link)) { $link = RelativePaths::getRelativePath($path_app, $path_item . '/' . $link); } $itemFile .= "File: {$link}\n"; $files_in_app_html .= "<tr><td>" . $file->name . "</td><td><a href=\"" . $link . "\">" . $link . "</a></td><td>" . $file->context['title'] . "</td></tr>"; } } } //TODO refactor to use less api calls: (not possible??!) if ($item->comment_count > 0) { #echo "comments.. (".$item->comment_count.")\n"; $comments = PodioComment::get_for('item', $item->item_id); RateLimitChecker::preventTimeOut(); $commentsFile = "\n\nComments\n--------\n\n"; foreach ($comments as $comment) { $commentsFile .= 'by ' . $comment->created_by->name . ' on ' . $comment->created_on->format('Y-m-d at H:i:s') . "\n----------------------------------------\n" . $comment->value . "\n\n\n"; if ($downloadFiles && isset($comment->files) && sizeof($comment->files) > 0) { foreach ($comment->files as $file) { $link = downloadFileIfHostedAtPodio($path_item, $file); # $link is relative to $path_item (if downloaded): if (!preg_match("/^http/i", $link)) { $link = RelativePaths::getRelativePath($path_app, $path_item . '/' . $link); } $commentsFile .= "File: {$link}\n"; $files_in_app_html .= "<tr><td>" . $file->name . "</td><td><a href=\"" . $link . "\">" . $link . "</a></td><td>" . $file->context['title'] . "</td></tr>"; } } } } else { $commentsFile = "\n\n[no comments]\n"; #echo "no comments.. (".$item->comment_count.")\n"; } file_put_contents($path_item . '/' . fixDirName($item->item_id . '-' . $item->title) . '.txt', $itemFile . $commentsFile); $appFile .= $itemFile . "\n\n"; } //store non item/comment files: if ($verbose) { echo "storing non item/comment files..\n"; } $app_files_folder = 'other_files'; $path_app_files = $path_app . '/' . $app_files_folder; mkdir($path_app_files); $files_in_app_html .= "<tr><td><b>App Files</b></td><td><a href={$app_files_folder}>" . $app_files_folder . "</a></td><td></td></tr>"; foreach ($appFiles as $file) { if ($file->context['type'] != 'item' && $file->context['type'] != 'comment') { echo "debug: downloading non item/comment file: {$file->name}\n"; $link = downloadFileIfHostedAtPodio($path_app_files, $file); # $link is relative to $path_item (if downloaded): if (!preg_match("/^http/i", $link)) { $link = RelativePaths::getRelativePath($path_app, $path_item . '/' . $link); } $files_in_app_html .= "<tr><td>" . $file->name . "</td><td><a href=\"" . $link . "\">" . $link . "</a></td><td>" . $file->context['title'] . "</td></tr>"; } } } catch (PodioError $e) { show_error($e); $appFile .= "\n\nPodio Error:\n" . $e; } file_put_contents($path_app . '/all_items_summary.txt', $appFile); $files_in_app_html .= "</table></body></html>"; file_put_contents($path_app . "/files_in_app.html", $files_in_app_html); unset($appFile); unset($files_in_app_html); }