forked from extern/egroupware
472 lines
14 KiB
PHP
472 lines
14 KiB
PHP
<?php
|
|
/**
|
|
* EGroupware - addressbook
|
|
*
|
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
|
* @package addressbook
|
|
* @subpackage importexport
|
|
* @link http://www.egroupware.org
|
|
* @author Cornelius Weiss <nelius@cwtech.de>
|
|
* @copyright Cornelius Weiss <nelius@cwtech.de>
|
|
* @version $Id$
|
|
*/
|
|
|
|
use EGroupware\Api;
|
|
use EGroupware\Api\Acl;
|
|
|
|
/**
|
|
* export plugin of addressbook
|
|
*/
|
|
class addressbook_export_contacts_csv implements importexport_iface_export_plugin
|
|
{
|
|
/**
|
|
* Constants used for exploding categories & multi-selectboxes into seperate fields
|
|
*/
|
|
const NO_EXPLODE = False;
|
|
const MAIN_CATS = 'main_cats'; // Only the top-level categories get their own field
|
|
const EACH_CAT = 'each_cat'; // Every category gets its own field
|
|
const EXPLODE = 'explode'; // For [custom] multi-selects, each option gets its own field
|
|
|
|
public function __construct()
|
|
{
|
|
$this->ui= new addressbook_ui();
|
|
$this->get_selects();
|
|
|
|
// Override types so we can specify owner 0 = 'Accounts'
|
|
$this->types = addressbook_egw_record::$types;
|
|
$this->types['select-account'] = array_diff($this->types['select-account'], ['owner']);
|
|
$this->types['select'][] = 'owner';
|
|
}
|
|
|
|
/**
|
|
* Exports records as defined in $_definition
|
|
*
|
|
* @param egw_record $_definition
|
|
*/
|
|
public function export( $_stream, importexport_definition $_definition) {
|
|
|
|
$options = $_definition->plugin_options;
|
|
$this->export_object = $export_object = new importexport_export_csv($_stream, (array)$options);
|
|
|
|
$selection = array();
|
|
|
|
// Addressbook defines its own export imits
|
|
$limit_exception = Api\Storage\Merge::is_export_limit_excepted();
|
|
$export_limit = Api\Storage\Merge::getExportLimit($app='addressbook');
|
|
if (!$limit_exception) $export_object->export_limit = $export_limit; // we may not need that after all
|
|
if($export_limit == 'no' && !$limit_exception) {
|
|
return;
|
|
}
|
|
|
|
// Need to switch the app to get the same results
|
|
$old_app = $GLOBALS['egw_info']['flags']['currentapp'];
|
|
$GLOBALS['egw_info']['flags']['currentapp'] = 'addressbook';
|
|
|
|
if ($options['selection'] == 'search') {
|
|
// uicontacts selection with checkbox 'use_all'
|
|
$query = Api\Cache::getSession('addressbook', 'index');
|
|
$query['num_rows'] = -1; // all
|
|
$query['csv_export'] = true; // so get_rows method _can_ produce different content or not store state in the session
|
|
$query['order'] = 'contact_id';
|
|
if(!array_key_exists('filter',$query)) $query['filter'] = $GLOBALS['egw_info']['user']['account_id'];
|
|
$readonlys = null;
|
|
$this->ui->get_rows($query,$selection,$readonlys, true); // only return the ids
|
|
}
|
|
elseif ( $options['selection'] == 'all' ) {
|
|
if ($GLOBALS['egw_info']['user']['preferences']['addressbook']['hide_accounts'] === '1') {
|
|
$col_filter['account_id'] = null;
|
|
}
|
|
$selection = ExecMethod2('addressbook.addressbook_bo.search', array(), true, '', '','',false,'AND',false,$col_filter);
|
|
//$uicontacts->get_rows($query,$selection,$readonlys,true);
|
|
}
|
|
elseif ($options['selection'] == 'filter')
|
|
{
|
|
$filter = $_definition->filter;
|
|
$query = array();
|
|
|
|
// Handle ranges
|
|
foreach($filter as $field => $value)
|
|
{
|
|
if($field == 'cat_id')
|
|
{
|
|
$query['col_filter'][$field] = implode(',',$value);
|
|
continue;
|
|
}
|
|
|
|
// Birthdays in addressbook are formatted Y-m-d
|
|
if($field == 'bday')
|
|
{
|
|
if($value['from'])
|
|
{
|
|
$query['col_filter'][] = "contact_bday >= " . $GLOBALS['egw']->db->quote(date('Y-m-d', (int)$value['from']));
|
|
}
|
|
if($value['to'])
|
|
{
|
|
$query['col_filter'][] = "contact_bday <= " . $GLOBALS['egw']->db->quote(date('Y-m-d', (int)$value['to']));
|
|
}
|
|
continue;
|
|
}
|
|
// Custom fields & listed exceptions are not filtered with contact_ prefix
|
|
if(strpos($field, '#') !== 0 && !in_array($field, array('tid','owner')))
|
|
{
|
|
$field = 'contact_'.$field;
|
|
}
|
|
$query['col_filter'][$field] = $value;
|
|
if(!is_array($value) || (!$value['from'] && !$value['to'])) continue;
|
|
|
|
// Ranges are inclusive, so should be provided that way (from 2 to 10 includes 2 and 10)
|
|
if($value['from']) $query['col_filter'][] = "$field >= " . (int)$value['from'];
|
|
if($value['to']) $query['col_filter'][] = "$field <= " . (int)$value['to'];
|
|
unset($query['col_filter'][$field]);
|
|
}
|
|
$selection = ExecMethod2('addressbook.addressbook_bo.search', array(), true, '', '','',false,'AND',false,$query['col_filter']);
|
|
}
|
|
else
|
|
{
|
|
$selection = explode(',',$options['selection']);
|
|
}
|
|
if(!is_array($selection))
|
|
{
|
|
$selection = array();
|
|
}
|
|
$GLOBALS['egw_info']['flags']['currentapp'] = $old_app;
|
|
|
|
if(Api\Storage\Merge::hasExportLimit($export_limit) && !$limit_exception) {
|
|
$selection = array_slice($selection, 0, $export_limit);
|
|
}
|
|
|
|
if($options['explode_multiselects']) {
|
|
$customfields = Api\Storage\Customfields::get('addressbook');
|
|
$additional_fields = array();
|
|
$cat_obj = new Api\Categories('', 'addressbook');
|
|
foreach($options['explode_multiselects'] as $field => $explode) {
|
|
switch($explode['explode']) {
|
|
case self::MAIN_CATS:
|
|
$cats = $cat_obj->return_array('mains', 0, false,'','ASC','',true);
|
|
foreach($cats as $settings) {
|
|
$additional_fields[$field][$settings['id']] = array(
|
|
'count' => 0,
|
|
'label' => $settings['name'],
|
|
'subs' => array(),
|
|
);
|
|
$subs = $cat_obj->return_sorted_array(0, False, '', 'ASC', 'cat_name', True, $settings['id']);
|
|
foreach($subs as $sub) {
|
|
$name = $sub['name'];
|
|
$path = $sub;
|
|
while($path['parent'] != $settings['id']) {
|
|
$path = $cat_obj->read($path['parent']);
|
|
$name = $path['name'] . '/' . $name;
|
|
}
|
|
$additional_fields[$field][$settings['id']]['subs'][$sub['id']] = $name;
|
|
}
|
|
}
|
|
break;
|
|
case self::EACH_CAT:
|
|
$cats = $cat_obj->return_array('all', 0, false,'','ASC','',true);
|
|
foreach($cats as $settings) {
|
|
$name = $settings['name'];
|
|
$path = $settings;
|
|
while($path['level'] != 0) {
|
|
$path = $cat_obj->read($path['parent']);
|
|
$name = $path['name'] . '/' . $name;
|
|
}
|
|
$additional_fields[$field][$settings['id']] = array(
|
|
'count' => 0,
|
|
'label' => $name
|
|
);
|
|
}
|
|
break;
|
|
case self::EXPLODE:
|
|
// Only works for custom fields
|
|
$index = substr($field, 1);
|
|
foreach($customfields[$index]['values'] as $key => $value) {
|
|
$additional_fields[$field][$key] = array(
|
|
'count' => 0,
|
|
'label' => $customfields[$index]['label'] . ': ' . $value,
|
|
);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Check records to see if additional fields are actually used
|
|
foreach ($selection as $_contact) {
|
|
if(is_array($_contact) && array_key_exists('photo', $_contact)) {
|
|
unset($_contact['photo']);
|
|
}
|
|
if(is_array($_contact) && count($_contact) == 1 && $_contact['id']) {
|
|
$_contact = $_contact['id'];
|
|
}
|
|
if(is_array($_contact) && $_contact['id']) {
|
|
$contact = new addressbook_egw_record();
|
|
$contact->set_record($_contact);
|
|
} else {
|
|
$contact = new addressbook_egw_record($_contact);
|
|
}
|
|
foreach($additional_fields as $field => &$values) {
|
|
if(!$contact->$field) continue;
|
|
foreach($values as $value => &$settings) {
|
|
if(!is_array($contact->$field)) {
|
|
$contact->$field = explode(',', $contact->$field);
|
|
}
|
|
if(is_array($contact->$field) && in_array($value, $contact->$field)) {
|
|
$settings['count']++;
|
|
} elseif($contact->$field == $value) {
|
|
$settings['count']++;
|
|
} elseif($options['explode_multiselects'][$field]['explode'] == self::MAIN_CATS && array_intersect($contact->$field, array_keys($settings['subs']))) {
|
|
$settings['count']++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
unset($field);
|
|
unset($value);
|
|
unset($settings);
|
|
|
|
// Add additional columns
|
|
foreach($additional_fields as $field => $additional_values) {
|
|
// Remove original
|
|
unset($options['mapping'][$field]);
|
|
// Add exploded
|
|
$field_count = 0;
|
|
foreach($additional_values as $value => $settings) {
|
|
if($settings['count'] > 0) {
|
|
$field_count += $settings['count'];
|
|
$options['mapping'][$field.'-'.$value] = $settings['label'];
|
|
}
|
|
}
|
|
if($field_count > 0) {
|
|
// Set some options for converting
|
|
$options['explode_multiselects'][$field]['values'] = $additional_values;
|
|
} else {
|
|
// Don't need this anymore
|
|
unset($options['explode_multiselects'][$field]);
|
|
}
|
|
}
|
|
}
|
|
|
|
$export_object->set_mapping($options['mapping']);
|
|
|
|
// Add in last/next event, if needed
|
|
if($options['mapping']['last_date'] || $options['mapping']['next_date'])
|
|
{
|
|
$contact_ids = array();
|
|
foreach($selection as $_contact)
|
|
{
|
|
if(is_array($_contact) && $_contact['id'])
|
|
{
|
|
$contact_ids[] = $_contact['account_id'] ? $_contact['account_id'] : 'c'.$_contact['id'];
|
|
}
|
|
else
|
|
{
|
|
$contact_ids[] = 'c'.$_contact;
|
|
}
|
|
}
|
|
$events = $this->ui->read_calendar($contact_ids, false);
|
|
}
|
|
|
|
// $options['selection'] is array of identifiers as this plugin doesn't
|
|
// support other selectors atm.
|
|
foreach ($selection as $_contact) {
|
|
if(is_array($_contact) && array_key_exists('photo', $_contact)) {
|
|
unset($_contact['photo']);
|
|
}
|
|
if(is_array($_contact) && count($_contact) == 1 && $_contact['id']) {
|
|
$_contact = $_contact['id'];
|
|
}
|
|
if(is_array($_contact) && $_contact['id']) {
|
|
$contact = new addressbook_egw_record();
|
|
$contact->set_record($_contact);
|
|
} else {
|
|
$contact = new addressbook_egw_record($_contact);
|
|
}
|
|
|
|
if($events && $events[$contact->id])
|
|
{
|
|
// NB: last_date and next_date are used instead of last_event & next_event
|
|
// to avoid automatic conversion - we want to export link title, not date-time
|
|
$contact->last_date = $events[$contact->id]['last_link']['title'];
|
|
$contact->next_date = $events[$contact->id]['next_link']['title'];
|
|
}
|
|
// Some conversion
|
|
$this->convert($contact, $options);
|
|
if($options['convert']) {
|
|
importexport_export_csv::convert($contact, $this->types, 'addressbook',$this->selects);
|
|
} else {
|
|
// Implode arrays, so they don't say 'Array'
|
|
foreach($contact->get_record_array() as $key => $value) {
|
|
if(is_array($value)) $contact->$key = implode(',', $value);
|
|
}
|
|
}
|
|
|
|
$export_object->export_record($contact);
|
|
unset($contact);
|
|
}
|
|
return $export_object;
|
|
}
|
|
|
|
/**
|
|
* returns translated name of plugin
|
|
*
|
|
* @return string name
|
|
*/
|
|
public static function get_name() {
|
|
return lang('Addressbook CSV export');
|
|
}
|
|
|
|
/**
|
|
* returns translated (user) description of plugin
|
|
*
|
|
* @return string descriprion
|
|
*/
|
|
public static function get_description() {
|
|
return lang("Exports contacts from your Addressbook into a CSV File.");
|
|
}
|
|
|
|
/**
|
|
* retruns file suffix for exported file
|
|
*
|
|
* @return string suffix
|
|
*/
|
|
public static function get_filesuffix() {
|
|
return 'csv';
|
|
}
|
|
|
|
public static function get_mimetype() {
|
|
return 'text/csv';
|
|
}
|
|
|
|
/**
|
|
* Suggest a file name for the downloaded file
|
|
* No suffix
|
|
*/
|
|
public function get_filename()
|
|
{
|
|
if(is_object($this->export_object) && $this->export_object->get_num_of_records() == 1)
|
|
{
|
|
return $this->export_object->record->get_title();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* return html for options.
|
|
* this way the plugin has all opertunities for options tab
|
|
*
|
|
* @param $definition Specific definition
|
|
*
|
|
* @return array (
|
|
* name => string,
|
|
* content => array,
|
|
* sel_options => array,
|
|
* readonlys => array,
|
|
* preserv => array,
|
|
* )
|
|
*/
|
|
public function get_options_etpl(importexport_definition &$definition = NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* returns slectors of this plugin via xajax
|
|
*
|
|
*/
|
|
public function get_selectors_etpl() {
|
|
return array(
|
|
'name' => 'importexport.export_csv_selectors',
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Convert some internal data to something with more meaning
|
|
*
|
|
* Dates, times, user IDs, category IDs
|
|
*/
|
|
public static function convert(addressbook_egw_record &$record, $options) {
|
|
|
|
if ($record->tel_prefer) {
|
|
$field = $record->tel_prefer;
|
|
$record->tel_prefer = $record->$field;
|
|
}
|
|
|
|
if(!is_array($options['explode_multiselects']))
|
|
{
|
|
return;
|
|
}
|
|
foreach((array)$options['explode_multiselects'] as $field => $explode_settings) {
|
|
if(!is_array($record->$field)) $record->$field = explode(',', $record->$field);
|
|
foreach((array)$explode_settings['values'] as $value => $settings) {
|
|
$field_name = "$field-$value";
|
|
$record->$field_name = array();
|
|
if(is_array($record->$field) && in_array($value, $record->$field) || $record->$field == $value) {
|
|
if($explode_settings['explode'] != self::MAIN_CATS) {
|
|
$record->$field_name = $options['convert'] ? lang('Yes') : true;
|
|
} elseif($options['convert']) {
|
|
// 3 part assign due to magic get method
|
|
$record_value = $record->$field_name;
|
|
$record_value[] = $settings['label'];
|
|
$record->$field_name = $record_value;
|
|
} else {
|
|
$record->$field_name = $value;
|
|
}
|
|
}
|
|
if($explode_settings['explode'] == self::MAIN_CATS && count(array_intersect($record->$field, array_keys($settings['subs'])))) {
|
|
// 3 part assign due to magic get method
|
|
$record_value = $record->$field_name;
|
|
if(!is_array($record_value)) $record_value = array($record_value);
|
|
foreach(array_intersect($record->$field, array_keys($settings['subs'])) as $sub_id) {
|
|
$record_value[] = $options['convert'] ? $settings['subs'][$sub_id] : $sub_id;
|
|
}
|
|
$record->$field_name = $record_value;
|
|
}
|
|
if(is_array($record->$field_name)) $record->$field_name = implode(($options['convert'] ? ', ' : ','), $record->$field_name);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
protected function get_selects()
|
|
{
|
|
$this->selects = array(
|
|
'tid' => array('n' => 'Contact'),
|
|
'owner' => $this->ui->get_addressbooks(Api\Acl::READ)
|
|
);
|
|
foreach($this->ui->content_types as $tid => $data)
|
|
{
|
|
$this->selects['tid'][$tid] = $data['name'];
|
|
}
|
|
}
|
|
/**
|
|
* Get the class name for the egw_record to use while exporting
|
|
*
|
|
* @return string;
|
|
*/
|
|
public static function get_egw_record_class()
|
|
{
|
|
return 'addressbook_egw_record';
|
|
}
|
|
|
|
/**
|
|
* Adjust automatically generated filter fields
|
|
*/
|
|
public function get_filter_fields(Array &$filters)
|
|
{
|
|
unset($filters['last_event']);
|
|
unset($filters['next_event']);
|
|
foreach($filters as $field_name => &$settings)
|
|
{
|
|
if($this->selects[$field_name]) $settings['values'] = $this->selects[$field_name];
|
|
}
|
|
$filters['owner'] = array(
|
|
'name' => 'owner',
|
|
'label' => lang('addressbook'),
|
|
'type' => 'select',
|
|
'rows' => 5,
|
|
'tags' => true,
|
|
'values' => $this->ui->get_addressbooks(Acl::READ)
|
|
);
|
|
}
|
|
}
|