CakePHP - 保存一个会话变量会删除另一个变量

4
我正在使用CakePHP的会话变量来存储我的用户与Twitter和Facebook有关的数据。当用户登录时,如果他已经链接了他的Twitter和FB账户,则此信息将保存在会话变量中,紧挨着我的用户数据。
我有一个屏幕,用户可以链接和取消链接社交网络数据。但问题是:
假设我连接了这两个社交网络,现在我决定断开Facebook的链接,那么Facebook的会话变量就被删除了。 现在我希望重新连接到Facebook,于是我点击连接按钮,Facebook的数据被保存了,但由于某种原因,Twitter的变量也被删除了。
我的流程如下:
1. 用户点击连接按钮。 2. 用户被引导到社交网络认证页面。 3. 用户被引导到一个函数,该函数获取所需的数据,将其保存在名为NetworkData的会话变量中,并返回到用户之前点击按钮的页面。 4. NetworkData被提取,在会话中设置为相应的社交网络(Facebook或Twitter),然后从会话中删除。
代码如下:
以下是用户在Twitter或FB登录后被引导的函数:
function retrieve_network($page) {
      $networkData = null;
      $this->autoRender = false;
      $this->layout = 'ajax';
      if(isset($_GET['oauth_token'])) {
        $token = $this->TwitterHelper->setOAuthToken($_GET['oauth_token']);
        $userinfo = $this->TwitterHelper->getTwitterUserInfo();
        $networkData = array(
          'TwitterData' => array(
            'username' => $userinfo['username'],
            'name' => $userinfo['name'],
            'token' => $token->oauth_token,
            'token_secret' => $token->oauth_token_secret
          )
        );
      } else if (isset($_GET['code'])) {
        $token = $this->FacebookHelper->facebook->getAccessToken();
        $userinfo = $this->FacebookHelper->getUserInfo();
        $networkData = array(
          'FacebookData' => array(
            'username' => $userinfo['username'],
            'name' => $userinfo['name'],
            'email' => $userinfo['email'],
            'token' => $token,
            'link' => $userinfo['link'],
          )
        );
      }

      $this->Session->write('NetworkData', $networkData);

      if($page == 'settings') {
        $this->redirect(array('controller' => 'fonykers', 'action' => 'settings/networks'));
      }
    }

这是一个用于检索网络数据并将其设置为会话的函数:
function settings($tab) {
      $this->layout = 'frontend';  
      $this->Fonyker->recursive = -1;
      $this->TwitterData->recursive = -1;
      $this->FacebookData->recursive = -1;

      if(!$this->checkSessionCookie()) {
        $this->redirect(array('controller' => 'pages', 'action' => 'home'));
      }

      $fields = array(
        'Fonyker.id',
        'Fonyker.username',
        'Fonyker.name',
        'Fonyker.email',
        'Fonyker.gender',
        'Fonyker.birthdate',
        'Fonyker.image_url'
      );

      $fonyker = $this->Fonyker->find('first', array(
        'conditions' => array(
          'Fonyker.fonykid' => $this->Session->read('Fonyker.Fonyker.fonykid')
        ),
        'fields' => $fields
      ));


      $this->Fonyker->set($fonyker);

      $this->data = $fonyker;

      if($this->Session->read('NetworkData')) {
        $networkData = $this->Session->read('NetworkData');
        $this->Session->delete('NetworkData');  

        if($networkData['TwitterData']) {
          $networkData['TwitterData']['fonyker_id'] = $fonyker['Fonyker']['id']; 
          if($this->TwitterData->save($networkData)) {
            $this->Session->write('TwitterData', $networkData['TwitterData']);
          }
        } else if($networkData['FacebookData']) {
          $networkData['FacebookData']['fonyker_id'] = $fonyker['Fonyker']['id']; 
          if($this->FacebookData->save($networkData)) {
            $this->Session->write('FacebookData', $networkData['FacebookData']);
          }
        }
      }

      pr($this->Session->read());

      if(!$this->Session->read('TwitterData')) {
        $this->TwitterHelper->setTwitterObj();
        $this->set('twitterUrl', $this->TwitterHelper->twitterObj->getAuthorizeUrl(null, array('oauth_callback' => 'http://127.0.0.1/fonykweb/pages/retrieve_network/settings')));
      } else {
        $this->set('twitterUrl', '#');
      }


      if(!$this->Session->read('FacebookData')) {
        $this->set('facebookUrl', $this->FacebookHelper->facebook->getLoginUrl(array('redirect_uri' => 'http://localhost/fonykweb/pages/retrieve_network/settings','scope' => 'email,user_birthday,publish_stream,offline_access')));
      } else {
        $this->set('facebookUrl', '#');
      } 

      $this->set('tab', $tab);
    }

以下是删除网络的功能,如果用户希望删除:

function remove_network($network) {
      $this->autoRender = false;
      $this->Fonyker->recursive = -1;
      $this->TwitterData->recursive = -1;
      $this->FacebookData->recursive = -1;
      $response = null;

      if($network == 'twitter') {
        $twitterData = $this->TwitterData->find('first', array(
          'conditions' => array(
            'TwitterData.fonyker_id' => $this->Session->read('TwitterData.fonyker_id')
          )
        ));

        if($this->TwitterData->delete($twitterData['TwitterData']['id'], false)) {
          $this->TwitterHelper->setTwitterObj();
          $twitterUrl = $this->TwitterHelper->twitterObj->getAuthorizeUrl(null, array('oauth_callback' => 'http://127.0.0.1/fonykweb/pages/retrieve_network/settings'));
          $this->Session->delete('TwitterData');
          $response = json_encode(array('ok' => true, 'url' => $twitterUrl));
        } else {
          $response = json_encode(array('ok' => false)); 
        }
      }

      if($network == 'facebook') {
        $facebookData = $this->FacebookData->find('first', array(
          'conditions' => array(
            'FacebookData.fonyker_id' => $this->Session->read('FacebookData.fonyker_id')
          )
        ));

        if($this->FacebookData->delete($facebookData['FacebookData']['id'], false)) {
          $facebookUrl = $this->FacebookHelper->facebook->getLoginUrl(array('redirect_uri' => 'http://localhost/fonykweb/pages/retrieve_network/settings','scope' => 'email,user_birthday,publish_stream,offline_access'));
          $this->Session->delete('FacebookData');
          $response = json_encode(array('ok' => true, 'url' => $facebookUrl));
        } else {
          $response = json_encode(array('ok' => false)); 
        }

      }

  echo $response; 
}

查看代码:

<script type="text/javascript">
  $(document).ready(function() {
    var splitUrl = window.location.href.split('/');
    $('#' + splitUrl[splitUrl.length - 1] + '-tab').addClass('active-tab');
    $('#' + splitUrl[splitUrl.length - 1] + '-tab').children().addClass('active-tab');
  });
</script>
<div class="prepend-1 prepend-top span-23">
<div class="tabs span-22">
  <ul>
    <li id="account-tab">
      <a href="<?php echo $html->url(array('controller' => 'fonykers', 'action' => 'settings'), true); ?>/account">
        Account
      </a>
    </li>
    <li id="password-tab">
      <a href="<?php echo $html->url(array('controller' => 'fonykers', 'action' => 'settings'), true); ?>/password">
        Password 
      </a>
    </li>
    <li id="notifications-tab">
      <a href="<?php echo $html->url(array('controller' => 'fonykers', 'action' => 'settings'), true); ?>/notifications">
        Notifications 
      </a>
    </li>
    <li id="networks-tab">
      <a href="<?php echo $html->url(array('controller' => 'fonykers', 'action' => 'settings'), true); ?>/networks"> 
       Social Networks 
      </a>
    </li>
  </ul>
</div>
<div class="tab-content prepend-top prepend-1">
  <?php 
    if($tab == 'account') {
      echo $this->element('settings/account');
    } else if ($tab == 'password') {
      echo $this->element('settings/password');
    } else if ($tab == 'notifications') {
      echo $this->element('settings/notifications');
    } else {
      echo $this->element('settings/networks');
    }
  ?>
</div>
</div>

元素代码:

<script type="text/javascript">
  $(document).ready(function(){

    var deleteNetwork = function(network, button) {
      $.ajax({
        url: '<?php echo $html->url('/fonykers/remove_network/', true); ?>' + network,
        dataType: 'json',
        type: 'POST',
        success: function(response) {
          if(response.ok) {
            button.replaceWith('<a id="'+network+'-connect" class="connect-button connect" href="'+response.url+'" class="span-3">Connect</a>');
          }
        }
      });  
    }

    if($('#twitter-connect').attr('href') == '#'){
      $('#twitter-connect').addClass('connected');
      $('#twitter-connect').html('Connected');
    } else {
      $('#twitter-connect').addClass('connect');
      $('#twitter-connect').html('Connect'); 
    }

    if($('#facebook-connect').attr('href') == '#'){
      $('#facebook-connect').addClass('connected');
      $('#facebook-connect').html('Connected');
    } else {
      $('#facebook-connect').addClass('connect');
      $('#facebook-connect').html('Connect'); 
    }

    $('.connected').hover(
      function() { 
        $(this).removeClass('connected');
        $(this).addClass('disconnect');
        $(this).html('Disconnect')
      },
      function() {
        $(this).removeClass('disconnect');
        $(this).addClass('connected');
        $(this).html('Connected')
      }
    );

    $('#twitter-connect').click(function(event) {
      if($(this).attr('href') == '#') {
        event.preventDefault();
        deleteNetwork('twitter', $(this));
      }
    });

    $('#facebook-connect').click(function(event) {
      if($(this).attr('href') == '#') {
        event.preventDefault();
        deleteNetwork('facebook', $(this));
      }
    });

  });
</script>
<div class="span-4 prepend-top">
<div class="span-4">
  <div class="span-1">
    <?php echo $html->image('twitter-connect.png', array('alt' => 'Twitter', 'class' => 'span-1',  'style' => 'height:40px;width:40px')); ?>
  </div>
  <div class="span-3 last">
    <a id="twitter-connect" class="connect-button" href="<?php echo $twitterUrl; ?>" class="span-3"></a>
  </div>
</div>
<div class="span-4 prepend-top">
  <div class="span-1">
  <?php echo $html->image('facebook-connect.png', array('alt' => 'Twitter', 'class' => 'span-1', 'style' => 'height:40px;width:40px')); ?>
  </div>
  <div class="span-3 last">
    <a id="facebook-connect" class="connect-button" href="<?php echo $facebookUrl; ?>"></a>
  </div>
</div>
</div>

很抱歉这篇文章比较长。

2个回答

4
在您的retrieve_network操作中,我假设您在用户重新连接到特定服务时调用该操作,如果您发现已连接到1个特定服务,则会覆盖NetworkData会话变量。
if(isset($_GET['oauth_token'])) {...} 

或者

if(isset($_GET['code'])) {...}

您将$networkData设置为返回的服务对象,然后通过以下方式覆盖整个会话:
$this->Session->write('NetworkData', $networkData);

根据您的代码,我会始终检查是否存在正在进行的服务,如果是,则不覆盖整个会话,只需将特定数据添加到现有的NetworkData会话数组中:

if($this->Session->read('NetworkData.TwitterData')){
    $facebookData = array(
                'username' => $userinfo['username'],
                'name' => $userinfo['name'],
                'email' => $userinfo['email'],
                'token' => $token,
                'link' => $userinfo['link'],
    );
    $this->Session->write('NetworkData.FacebookData', $facebookData);
}

注意:这只是一个示例,展示了如何实现此操作。对于这种特定情况,我将重新设计该方法以获得更好的逻辑,可能将TwitterData和FacebookData存储在它们自己单独的数组中,而不是一个更大更复杂的NetworkData数组中。此外,您可以通过$this->params['url']['paramname']访问$_GET参数,以保持cakePHP约定。

1
这是问题的一部分,如果您检查我的设置方法,在用户从我的检索网络重定向后,它会检查添加了哪个网络,删除NetworkData并添加必要的网络,TwitterData或FacebookData,因此无论NetworkData是否被覆盖都没有关系,因为它一开始就不存在,当提取必要信息后就会被删除。现在,编写任何会话变量都会覆盖整个会话吗?因为我的其他会话变量保持不变。 - 8vius
在进入settings()方法之前,retrieve_network()方法中当前存在的NetworkData会被覆盖。您的retrieve_network操作只考虑Twitter或Facebook中的一个,而不是在当前会话期间同时考虑两者,因此如果在NetworkData会话中设置了TwitterData,然后Facebook尝试连接或重新连接,则整个NetworkData会话将被仅包含Facebook数据的内容覆盖。当您通过$this->Session->write('name', $var)设置会话时,这与执行$_SESSION['name'] = $var相同。使用write()不会附加到现有会话。 - Anthony
这就是应该发生的事情,安东尼。在我点击“连接到Twitter或Facebook”按钮之后,我的回调URL指向retrieve_network()函数,然后在那里提取NetworkData并重定向到setting。现在,我该如何使用Cake来追加会话?奇怪的是,当我写入其他会话变量时,并不会删除它们。而且当用户登录时,我会分别提取他的FB和Twitter数据并将它们单独写入,当我输出会话时,它们会并排显示。 - 8vius

0

我认为问题在于您正在替换网络数据,而不是合并它。

这意味着当您使用FB登录时,您会用FB替换任何Twitter数据,而不是保留它们两者。

我希望也许可以改为

$this->Session->write('NetworkData', $networkData);

那个

$this->Session->write('NetworkData', array_merge($networkData, $this->Session->read('NetworkData'));

可能会起作用。

否则,对我来说,会话删除代码不应该相互干扰。虽然在浏览时可能会错过一些内容。我建议使用echo()或调试工具来跟踪代码执行路径。


再次强调,这不是问题。如果您检查我的设置方法,您会发现在设置TwitterData或FacebookData之后,NetworkData被删除了。 - 8vius
1
@8vius,你一直坚称你的代码没有问题,但实际上存在问题。你能否展示相关的视图代码呢?试试我的解决方案,看看有什么不同吗? - Ivo
我并不是在坚称我的代码没有问题@Ivo,我只是想说人们在发布之前似乎没有仔细阅读代码,因为我相信很清楚我的NetworkData会话变量在完成其功能后从会话中删除,我将更新我的问题与我的视图代码。 - 8vius

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接