Creación con la API de Twitter: Administración de listas
Spanish (Español) translation by Eva Collados Pascual (you can also view the original English article)



Esta es la segunda parte de nuestro tutorial sobre la API de Lista de Twitter dentro de nuestra más amplia serie sobre la API de Twitter. En este tutorial, revisaremos la creación de características para listas con la API. Los ejemplos de códigod de este tutorial se proporcionan en el repositorio de Github. Aquí se describen con más detalle las instrucciones de instalación (asegúrate de utilizar el repositorio proporcionado en este tutorial y no el repositorio Birdcage inicial que aparece en esa página).
Descripción general de la API de Lista de Twitter
Una vez más, hay aproximadamente 19 APIs para listas de Twitter, divididas en tres áreas principales:
Comencemos con la integración de algunas de las características básicas del desarrollo de la API de Listas.
Creación de una lista
Cuando cargues Birdcage, verás la página Manage Lists (Administrar listas). Haz clic en la opción Create a List (crear una lista) en el menú de la barra lateral derecha.



Se mostrará el formulario Create a List (crear una lista). Voy a crear una lista para rastrear a los periodistas de Seattle en Twitter:



Aquí tienes el código Create en TwitterlistController.php. Controla el código para mostrar el formulario y, después de que se publique el formulario, el código para el procesamiento:
1 |
public function actionCreate() |
2 |
{
|
3 |
$model=new TwitterList; |
4 |
$this->performAjaxValidation($model); |
5 |
if(!isset($_POST['TwitterList'])) { |
6 |
// initial load
|
7 |
// load the current selected account as a default
|
8 |
$model->account_id = Yii::app()->session['account_id']; |
9 |
// display form
|
10 |
$this->render('create',array( |
11 |
'model'=>$model, |
12 |
));
|
13 |
} else { |
14 |
// POSTed - process form
|
15 |
$model->attributes=$_POST['TwitterList']; |
16 |
// load the account selected
|
17 |
$account = Account::model()->findByPK($model->account_id); |
18 |
// connect to twitter
|
19 |
$twitter = Yii::app()->twitter->getTwitterTokened($account['oauth_token'], $account['oauth_token_secret']); |
20 |
// create remotely at Twitter
|
21 |
$new_list= $twitter->post("lists/create",array('name'=>$model->name,'description'=>$model->description,'mode'=>$model->getModeString($model->mode))); |
22 |
if (TwitterList::model()->isError($new_list)) { |
23 |
// to do - set flash error
|
24 |
var_dump($new_list); |
25 |
yexit(); |
26 |
} else { |
27 |
$model->owner_id =$account->twitter_id; |
28 |
$model->list_id =$new_list->id_str; |
29 |
$model->slug=$new_list->slug; |
30 |
$model->full_name=$new_list->full_name; |
31 |
$model->created_at = date( 'Y-m-d H:i:s', strtotime($new_list->created_at) ); |
32 |
$model->modified_at =new CDbExpression('NOW()'); |
33 |
if($model->save()) |
34 |
$this->redirect(array('admin')); |
35 |
}
|
36 |
}
|
37 |
}
|
Puede leer la documentación de la API de Listas de Twitter/Crear aquí.
Una vez enviado el formulario, verás algo como esto:



Importación de miembros a una lista
Una de las limitaciones más frustrantes de la interfaz de usuario de las listas de Twitter es lo difícil que resulta añadir nuevos miembros. Tienes que visitar el perfil de cada miembro y añadirlos individualmente a tus listas: el proceso es muy complicado y lento.
Vamos a implementar una función para suscribir un listado separado por comas de una serie de cuentas de Twitter.
En la vista de lista, si haces clic en el icono Administrar lista a la derecha de Journalists Seattle, verás la página Ver lista:



Haz clic sobre Importar miembros en el menú de la barra lateral derecha. A continuación, escribe la lista de cuentas de Twitter que desees añadir a este listado:



Revisemos el código que sube los miembros a Twitter. El código para mostrar el formulario anterior comienza en ListMemberController.php:
1 |
/**
|
2 |
* Import members to a list
|
3 |
*/
|
4 |
public function actionImport($id) |
5 |
{
|
6 |
$model = new Import(); |
7 |
$model->list_id = $id; |
8 |
// Uncomment the following line if AJAX validation is needed
|
9 |
$this->performAjaxValidation($model); |
10 |
if(isset($_POST['Import'])) |
11 |
{
|
12 |
if($model->save()) { |
13 |
$result = ListMember::model()->import($id,$_POST['Import']['member_list']); |
14 |
Yii::app()->user->setFlash('import_success','Thank you! Your members have been added.'); |
15 |
$this->redirect(array('/twitterlist/view','id'=>$id)); |
16 |
} // end if save |
17 |
// end if post
|
18 |
} else { |
19 |
$this->render('import',array( |
20 |
'model'=>$model,'list_id'=>$id, |
21 |
));
|
22 |
}
|
23 |
}
|
En el modelo ListMember.php, el código de importación tiene el siguiente aspecto. Usamos preg_split para convertir la lista de cuentas en una matriz. Luego, para cada cuenta, obtenemos información sobre la cuenta en Users/Show y publicamos el ID de Twitter en Lists Member Create (Listas de creación de miembros).
1 |
public function import($id,$import_list) { |
2 |
// retrieve account
|
3 |
$tl = TwitterList::model()->findByAttributes(array('id'=>$id)); |
4 |
$list_id = $tl['list_id']; |
5 |
$account = Account::model()->findByPk($tl->account_id); |
6 |
// retrieve members and add to list
|
7 |
$twitter = Yii::app()->twitter->getTwitterTokened($account['oauth_token'], $account['oauth_token_secret']); |
8 |
// convert post rows to array
|
9 |
$add_list = preg_split ("(\r|\n|,)", $import_list, -1, PREG_SPLIT_NO_EMPTY); |
10 |
$max_count = 0; |
11 |
foreach ($add_list as $item) { |
12 |
$item = trim($item); |
13 |
$user_info= $twitter->get("users/show",array('screen_name'=>$item)); |
14 |
if (ErrorLog::model()->isError('getUserInfo', $account['id'], $user_info)) { |
15 |
continue; |
16 |
}
|
17 |
if (ErrorLog::model()->isRateLimited($user_info)) { |
18 |
continue; |
19 |
}
|
20 |
// add remotely to list
|
21 |
$people= $twitter->post("lists/members/create",array('list_id'=>$list_id,'screen_name'=>$item)); |
22 |
// add locally to db
|
23 |
$this->remote_add($list_id,$user_info->id_str,$item); |
24 |
$max_count+=1; |
25 |
if ($max_count>=99) break; |
26 |
}
|
27 |
}
|
28 |
|
29 |
public function remote_add($list_id,$member_id,$screen_name = 'tbd') { |
30 |
TwitterUser::model()->setPlaceholder($member_id,$screen_name); |
31 |
$lm = ListMember::model()->findByAttributes(array('list_id'=>$list_id,'member_id'=>$member_id)); |
32 |
if (empty($lm)) { |
33 |
$lm = new ListMember; |
34 |
$lm->list_id=$list_id; |
35 |
$lm->member_id=$member_id; |
36 |
$lm->save(); |
37 |
}
|
38 |
}
|
Después de enviar los miembros, verás algo como esto:



El tbd representa un usuario que aún no está en nuestra base de datos; la información del perfil se obtendrá (hidratará) en segundo plano más adelante.
En Twitter, verás algo como esto:



Sincronización de listas
Ahora que hemos creado una lista, vamos a buscar las listas que ya existen en nuestra cuenta para poder administrarlas desde nuestra consola. De nuevo, en el menú Administrar listas, haz clic en Sincronizar listas.



La acción de sincronización está codificada en TwitterlistController.php:
1 |
public function actionSync() |
2 |
{
|
3 |
TwitterList::model()->sync(); |
4 |
$this->redirect(array('admin')); |
5 |
}
|
La operación de sincronización del modelo TwitterList.php es relativamente sofisticada, como se muestra a continuación. En primer lugar, el modelo de sincronización recorre todas las cuentas que hayas configurado y llama a la cuenta syncOne para las listas.
SyncOne llama a fetch Lists/Ownerships en la API para buscar todas las listas propiedad de cada cuenta.
1 |
public function sync() { |
2 |
$users = User::model()->findAll(); |
3 |
foreach ($users as $user) { |
4 |
$user_id = $user['id']; |
5 |
$accounts = Account::model()->findAllByAttributes(array('user_id'=>$user_id)); |
6 |
// loop through Twitter accounts (may be multiple)
|
7 |
foreach ($accounts as $account) { |
8 |
$this->syncOne($account['id']); |
9 |
} // end account loop |
10 |
} // end user loop |
11 |
}
|
12 |
|
13 |
public function syncOne($account_id) { |
14 |
$account=Account::model()->findByPk($account_id); |
15 |
$twitter = Yii::app()->twitter->getTwitterTokened($account['oauth_token'], $account['oauth_token_secret']); |
16 |
// fetch lists owned by this account
|
17 |
$twitter_lists= $twitter->get("lists/ownerships",array('count'=>100,'cursor'=>-1)); |
18 |
//print_r($twitter_lists);
|
19 |
if (count($twitter_lists->lists)==0) return; |
20 |
foreach ($twitter_lists->lists as $tl) { |
21 |
//echo $tl->id_str.' '.$tl->slug.' '.$tl->member_count;lb();
|
22 |
$this->remote_add($account_id,$tl); |
23 |
// spawn action to get list members
|
24 |
$this->addMembershipAction($account_id,$tl->id_str); |
25 |
} // end loop of lists |
26 |
}
|
Sin embargo, en lugar de intentar capturar los miembros de la lista en tiempo real, lo que probablemente agotaría el tiempo de espera, crea una acción en segundo plano para capturar los miembros de una lista determinada.
1 |
public function addMembershipAction($account_id,$item_id) { |
2 |
// adds a background task action to retrieve memberships for a list id
|
3 |
$check_dup = Action::model()->findByAttributes(array('account_id'=>$account_id,'action'=>Action::ACTION_MEMBERSHIPS,'status'=>Action::STATUS_ACTIVE,'item_id'=>$item_id)); |
4 |
if (empty($check_dup)) { |
5 |
$a = new Action(); |
6 |
$a->account_id = $account_id; |
7 |
$a->action = Action::ACTION_MEMBERSHIPS; |
8 |
$a->item_id = $item_id; |
9 |
$a->last_tweet_id = 0; // set cursor |
10 |
$a->status = Action::STATUS_ACTIVE; |
11 |
$a->created_at =new CDbExpression('NOW()'); |
12 |
$a->modified_at =new CDbExpression('NOW()'); |
13 |
$a->save(); |
14 |
}
|
15 |
}
|
La tarea cron en segundo plano invoca el modelo Action.php que llama a getListMembership para una lista cada vez.
1 |
public function getListMembership($action,$limit = 50) { |
2 |
// collect next $limit members of list
|
3 |
$account = Account::model()->findByPk($action->account_id); |
4 |
// last_tweet_id is the cursor
|
5 |
$cursor = $action->last_tweet_id; |
6 |
if ($cursor ==0 ) $cursor =-1; // since last_tweet_id is unsigned, can't store -1 start |
7 |
$result = TwitterList::model()->getMemberships($account, $action->item_id, $cursor , $limit); |
8 |
$a = Action::model()->findByPk($action->id); |
9 |
if ($result->rateLimit) { |
10 |
return false; |
11 |
} else if ($result->complete) { |
12 |
$a->status=self::STATUS_COMPLETE; |
13 |
$a->save(); |
14 |
} else { |
15 |
// set lowest cursor
|
16 |
$a->last_tweet_id = $result->cursor; |
17 |
$a->save(); |
18 |
}
|
19 |
}
|
Cuando se ejecuta la tarea, invoca el método getMemberships del modelo TwitterList.php. Este método utiliza la cursorización para paginar a través de los registros de miembro sin agotar el tiempo de espera o alcanzar los límites de velocidad. El último cursor se almacena en la tabla Action para que la siguiente invocación en segundo plano pueda continuar añadiendo miembros donde lo dejó anteriormente.
1 |
public function getMemberships($account,$list_id, $cursor =-1,$limit = 200) { |
2 |
echo 'entering getMemberships: account_id:'.$account['id'].' list_id:'.$list_id.' cursor: '.$cursor;lb(); |
3 |
$result = new StdClass; |
4 |
$result->cursor = -1; |
5 |
$result->count =0; |
6 |
$result->error =false; |
7 |
$result->complete = false; |
8 |
$result->rateLimit = false; |
9 |
$count_people = 0; |
10 |
// retrieve members and add to list
|
11 |
$twitter = Yii::app()->twitter->getTwitterTokened($account['oauth_token'], $account['oauth_token_secret']); |
12 |
echo 'here'.$cursor;lb(); |
13 |
while ($cursor <>0 ) { |
14 |
echo 'inside';lb(); |
15 |
$people= $twitter->get("lists/members",array('list_id'=>$list_id,'cursor'=>$cursor,'skip_status'=>true,'include_entities'=>false)); |
16 |
if (ErrorLog::model()->isError('getMemberships', $account['id'], $people)) { |
17 |
$result->error =false; |
18 |
return $result; |
19 |
}
|
20 |
if (ErrorLog::model()->isRateLimited($people)) { |
21 |
$result->rateLimit = true; |
22 |
return $result; |
23 |
}
|
24 |
if (isset($people->next_cursor)) |
25 |
$cursor = $people->next_cursor; |
26 |
else
|
27 |
$cursor = 0; |
28 |
$result->cursor = $cursor; |
29 |
$count_people+=count($people->users); |
30 |
echo 'Count people: '.count($people->users);lb(); |
31 |
foreach ($people->users as $u) { |
32 |
//var_dump($u);lb();
|
33 |
echo 'Member:'.$u->screen_name;lb(); |
34 |
if (isset($u->screen_name)) |
35 |
$screen_name = $u->screen_name; |
36 |
else
|
37 |
$screen_name = 'tbd'; |
38 |
ListMember::model()->remote_add($list_id,$u->id_str,$screen_name); |
39 |
}
|
40 |
if (count($people->users)==0 or $cursor==0) { |
41 |
$result->complete = true; |
42 |
return $result; |
43 |
}
|
44 |
} // end while loop |
45 |
echo 'exiting getMemberships';lb(); |
46 |
return $result; |
47 |
}
|
Cuando se complete la operación deberías ver algo como esto:



Una vez completadas las tareas en segundo plano, verás miembros para cada lista como en la siguiente imagen:



¿Qué viene a continuación?
Espero que hayas disfrutado de esta serie sobre la API List de Twitter hasta ahora. Me gustaría escuchar tus sugerencias sobre tus escenarios de uso de la API favoritos y solicitudes de características; por favor, publícalos a través de la sección de comentarios.
Si tienes alguna pregunta o sugerencia, por favor publícala a través de un comentario. Si deseas mantenerte al día sobre mis próximos tutoriales y otras series en Tuts+, por favor visita mi página de instructor o sígueme en Twitter, @reifman.



