public function testMalXml()
 {
     $anime = new Anime();
     $items = array();
     $output = "<?xml version=\"1.0\"?>\n<entry><episode>7</episode><status>1</status><score>9</score><downloaded_episodes>8</downloaded_episodes><storage_type>2</storage_type><storage_value>3.7</storage_value><times_rewatched>1</times_rewatched><rewatch_value>4</rewatch_value><date_start>01012015</date_start><date_finish>01022015</date_finish><priority>0</priority><comments>This is a comment.</comments><fansub_group>GG</fansub_group><tags>one,two,three</tags></entry>\n";
     $anime->setId(1);
     $anime->setWatchedEpisodes(7);
     $items[] = 'episodes';
     $anime->setWatchedStatus(1);
     $items[] = 'status';
     $anime->setScore(9);
     $items[] = 'score';
     $anime->setEpsDownloaded(8);
     $items[] = 'downloaded';
     $anime->setStorage(2);
     $items[] = 'storage';
     $anime->setStorageValue(3.7);
     $items[] = 'storageAmt';
     $anime->setRewatchCount(1);
     $items[] = 'rewatchCount';
     $anime->setRewatchValue(4);
     $items[] = 'rewatchValue';
     $anime->setWatchingStart(new \DateTime('20150101'));
     $items[] = 'start';
     $anime->setWatchingEnd(new \DateTime('20150102'));
     $items[] = 'end';
     $anime->setPriority(6);
     $items[] = 'priority';
     $anime->setPersonalComments('This is a comment.');
     $items[] = 'comments';
     $anime->setFansubGroup('GG');
     $items[] = 'fansubber';
     $anime->setPersonalTags('one,two,three');
     $items[] = 'tags';
     $this->assertEquals($output, $anime->MALApiXml($items));
 }
 public static function parseExtendedPersonal($contents, Anime $anime)
 {
     $crawler = new Crawler();
     $crawler->addHTMLContent($contents, 'UTF-8');
     #Personal tags
     #<td class="borderClass"><textarea name="tags" rows="2" id="tagtext" cols="45" class="textarea">action, sci-fi</textarea></td>
     $personalTags = $crawler->filter('textarea[id="add_anime_tags"]')->text();
     if (strlen($personalTags) > 0) {
         $personalTags = explode(',', $personalTags);
         foreach ($personalTags as $tag) {
             $tagArray[] = trim($tag);
         }
         $anime->setPersonalTags($tagArray);
     }
     #Start and Finish Dates
     #<tr>
     #   <td class="borderClass">Start Date</td>
     #               <td class="borderClass">
     #   Month:
     #   <select name="startMonth"  class="inputtext">
     #       <option value="00">
     #       <option value="1" >Jan<option value="2" selected>Feb<option value="3" >Mar<option value="4" >Apr<option value="5" >May<option value="6" >Jun<option value="7" >Jul<option value="8" >Aug<option value="9" >Sep<option value="10" >Oct<option value="11" >Nov<option value="12" >Dec         </select>
     #   Day:
     #   <select name="startDay"  class="inputtext">
     #       <option value="00">
     #       <option value="1" >1<option value="2" selected>2<option value="3" >3<option value="4" >4<option value="5" >5<option value="6" >6<option value="7" >7<option value="8" >8<option value="9" >9<option value="10" >10<option value="11" >11<option value="12" >12<option value="13" >13<option value="14" >14<option value="15" >15<option value="16" >16<option value="17" >17<option value="18" >18<option value="19" >19<option value="20" >20<option value="21" >21<option value="22" >22<option value="23" >23<option value="24" >24<option value="25" >25<option value="26" >26<option value="27" >27<option value="28" >28<option value="29" >29<option value="30" >30<option value="31" >31            </select>
     #   Year:
     #   <select name="startYear"  class="inputtext">
     #       <option value="0000">
     #       <option value="2014" selected>2014<option value="2013" >2013<option value="2012" >2012<option value="2011" >2011<option value="2010" >2010<option value="2009" >2009<option value="2008" >2008<option value="2007" >2007<option value="2006" >2006<option value="2005" >2005<option value="2004" >2004<option value="2003" >2003<option value="2002" >2002<option value="2001" >2001<option value="2000" >2000<option value="1999" >1999<option value="1998" >1998<option value="1997" >1997<option value="1996" >1996<option value="1995" >1995<option value="1994" >1994<option value="1993" >1993<option value="1992" >1992<option value="1991" >1991<option value="1990" >1990<option value="1989" >1989<option value="1988" >1988<option value="1987" >1987<option value="1986" >1986<option value="1985" >1985<option value="1984" >1984          </select>
     #   &nbsp;
     #   <label><input type="checkbox"  onchange="ChangeStartDate();"  name="unknownStart" value="1"> <small>Unknown Date</label><br>Start Date represents the date you started watching the Anime <a href="javascript:setToday(1);">Insert Today</a></small>
     #   </td>
     #</tr>
     #<tr>
     #   <td class="borderClass">Finish Date</td>
     #               <td class="borderClass">
     #   Month:
     #   <select name="endMonth" class="inputtext" disabled>
     #       <option value="00">
     #       <option value="1" >Jan<option value="2" >Feb<option value="3" >Mar<option value="4" >Apr<option value="5" >May<option value="6" >Jun<option value="7" >Jul<option value="8" >Aug<option value="9" >Sep<option value="10" >Oct<option value="11" >Nov<option value="12" >Dec         </select>
     #   Day:
     #   <select name="endDay" class="inputtext" disabled>
     #       <option value="00">
     #       <option value="1" >1<option value="2" >2<option value="3" >3<option value="4" >4<option value="5" >5<option value="6" >6<option value="7" >7<option value="8" >8<option value="9" >9<option value="10" >10<option value="11" >11<option value="12" >12<option value="13" >13<option value="14" >14<option value="15" >15<option value="16" >16<option value="17" >17<option value="18" >18<option value="19" >19<option value="20" >20<option value="21" >21<option value="22" >22<option value="23" >23<option value="24" >24<option value="25" >25<option value="26" >26<option value="27" >27<option value="28" >28<option value="29" >29<option value="30" >30<option value="31" >31            </select>
     #   Year:
     #   <select name="endYear" class="inputtext" disabled>
     #       <option value="0000">
     #       <option value="2014" >2014<option value="2013" >2013<option value="2012" >2012<option value="2011" >2011<option value="2010" >2010<option value="2009" >2009<option value="2008" >2008<option value="2007" >2007<option value="2006" >2006<option value="2005" >2005<option value="2004" >2004<option value="2003" >2003<option value="2002" >2002<option value="2001" >2001<option value="2000" >2000<option value="1999" >1999<option value="1998" >1998<option value="1997" >1997<option value="1996" >1996<option value="1995" >1995<option value="1994" >1994<option value="1993" >1993<option value="1992" >1992<option value="1991" >1991<option value="1990" >1990<option value="1989" >1989<option value="1988" >1988<option value="1987" >1987<option value="1986" >1986<option value="1985" >1985<option value="1984" >1984          </select>
     #   &nbsp;
     #   <small><label><input type="checkbox" onchange="ChangeEndDate();" checked name="unknownEnd" value="1"> Unknown Date</label><br>Do <u>not</u> fill out the Finish Date unless status is <em>Completed</em> <a href="javascript:setToday(2);">Insert Today</a></small>
     #   </td>
     #</tr>
     $isStarted = $crawler->filter('input[id="unknown_start"]')->attr('checked');
     $isEnded = $crawler->filter('input[id="unknown_end"]')->attr('checked');
     if ($isStarted != 'checked') {
         //So, MAL allows users to put in just years, just years and months, or all three values.
         //This mess here is to try and avoid things breaking.
         if ($crawler->filter('select[id="add_anime_start_date_year"] option:selected')->count() > 0) {
             $startYear = $crawler->filter('select[id="add_anime_start_date_year"] option:selected')->attr('value');
             $startMonth = 6;
             $startDay = 15;
             if ($startYear !== '') {
                 if ($crawler->filter('select[id="add_anime_start_date_month"] option:selected')->count() > 0) {
                     $startMonth = $crawler->filter('select[id="add_anime_start_date_month"] option:selected')->attr('value');
                     if ($startMonth === '') {
                         $startMonth = 6;
                     }
                     if ($crawler->filter('select[id="add_anime_start_date_day"] option:selected')->count() > 0) {
                         $startDay = $crawler->filter('select[id="add_anime_start_date_day"] option:selected')->attr('value');
                         if ($startDay === '') {
                             $startDay = 15;
                         }
                     }
                 }
                 $anime->setWatchingStart(DateTime::createFromFormat('Y-n-j', "{$startYear}-{$startMonth}-{$startDay}"));
             }
         }
     }
     if ($isEnded != 'checked') {
         //Same here, avoid breaking MAL's allowing of partial dates.
         if ($crawler->filter('select[id="add_anime_finish_date_year"] option:selected')->count() > 0) {
             $endYear = $crawler->filter('select[id="add_anime_finish_date_year"] option:selected')->attr('value');
             $endMonth = 6;
             $endDay = 15;
             if ($endYear !== '') {
                 if ($crawler->filter('select[id="add_anime_finish_date_month"] option:selected')->count() > 0) {
                     $endMonth = $crawler->filter('select[id="add_anime_finish_date_month"] option:selected')->attr('value');
                     if ($endMonth === '') {
                         $endMonth = 6;
                     }
                     if ($crawler->filter('select[id="add_anime_finish_date_day"] option:selected')->count() > 0) {
                         $endDay = $crawler->filter('select[id="add_anime_finish_date_day"] option:selected')->attr('value');
                         if ($endDay === '') {
                             $endDay = 15;
                         }
                     }
                 }
                 $anime->setWatchingEnd(DateTime::createFromFormat('Y-n-j', "{$endYear}-{$endMonth}-{$endDay}"));
             }
         }
     }
     #Priority
     #<td class="borderClass"><select name="priority" class="inputtext">
     #<option value="0" selected>Low<option value="1" >Medium<option value="2" >High         </select>
     $priority = $crawler->filter('select[id="add_anime_priority"] option:selected')->attr('value');
     $anime->setPriority($priority);
     #Storage
     #
     #<td class="borderClass" align="left"><select name="storage" id="storage" onchange="StorageBooleanCheck(2);" class="inputtext">
     #   <option value="0">Select storage type
     #   <option value="1" >Hard Drive<option value="6" >External HD<option value="7" >NAS<option value="2" >DVD / CD<option value="4" >Retail DVD<option value="5" >VHS<option value="3" >None          </select>
     #<div style="margin: 3px 0px; display: none;" id="StorageDiv">Total <span id="storageDescription">DvD's</span> <input type="text" name="storageVal" id="storageValue" value="0.00" size="4" class="inputtext"></div>
     #</td>
     //Note that if storage isn't defined, nothing will be marked as selected. We thus have to get the value in two stages to avoid raising an exception.
     $storage = $crawler->filter('select[id="add_anime_storage_type"] option:selected');
     if (count($storage)) {
         $anime->setStorage($storage->attr('value'));
     }
     #Storage Value - Either number of discs or size in GB
     #<div style="margin: 3px 0px; display: none;" id="StorageDiv">Total <span id="storageDescription">DvD's</span> <input type="text" name="storageVal" id="storageValue" value="1.00" size="4" class="inputtext"></div>
     $storageval = (double) $crawler->filter('input[id="add_anime_storage_value"]')->attr('value');
     if ($storageval > 0) {
         $anime->setStorageValue($storageval);
     }
     #Rewatched
     #<label><input type="checkbox" id="add_anime_is_rewatching" name="add_anime[is_rewatching]" value="1" checked="checked">
     $rewatch = $crawler->filter('input[id="add_anime_is_rewatching"]')->attr('checked');
     if ($rewatch == null) {
         $anime->setRewatching(false);
     } else {
         $anime->setRewatching(true);
     }
     #Times Rewatched
     #<td class="borderClass"><input type="text" name="list_times_watched" value="0" size="4" class="inputtext">
     $rewatchCount = $crawler->filter('input[id="add_anime_num_watched_times"]')->attr('value');
     if ($rewatchCount > 0) {
         $anime->setRewatchCount($rewatchCount);
     }
     #Rewatch Value
     #<td class="borderClass"><select name="list_rewatch_value" class="inputtext">
     #    <option value="0">Select rewatch value<option  value="1">Very Low<option  value="2">Low<option  value="3">Medium<option  value="4">High<option selected value="5">Very High            </select>
     $rewatchValue = $crawler->filter('select[id="add_anime_rewatch_value"] option:selected');
     if (count($rewatchValue)) {
         $anime->setRewatchValue($rewatchValue->attr('value'));
     }
     #Comments
     #<td class="borderClass"><textarea name="list_comments" rows="5" cols="45" class="textarea"></textarea></td>
     $comments = trim($crawler->filter('textarea[id="add_anime_comments"]')->text());
     if (strlen($comments)) {
         $anime->setPersonalComments($comments);
     }
     return $anime;
 }
 /**
  * Update an anime on a user's list.
  *
  * Uses the contents of the HTTP Request to get the needed data for updating the
  * requested title. The user must have passed the basic authentication needs and the
  * PHP_AUTH_USER and PHP_AUTH_PW variables must be set. If so, the get variables of
  * "status", "episodes", and "score" are checked and used in the creation of an Anime
  * object. The object is used to make an XML document that is then posted to MyAnimeList.
  *
  * @param Request $request    Contains all the needed information to update the title.
  * @param int     $id         ID of the anime.
  * @param float   $apiVersion The API version for the request
  *
  * @return View
  */
 public function updateAction(Request $request, $id, $apiVersion)
 {
     // http://myanimelist.net/api/animelist/update/#{id}.xml
     //get the credentials we received
     $username = $this->getRequest()->server->get('PHP_AUTH_USER');
     $password = $this->getRequest()->server->get('PHP_AUTH_PW');
     //Don't bother making a request if the user didn't send any authentication
     if ($username === null) {
         $view = $this->view(array('error' => 'unauthorized'), 401);
         $view->setHeader('WWW-Authenticate', 'Basic realm="myanimelist.net"');
         return $view;
     }
     $anime = new Anime();
     $anime->setId($id);
     //Only use values we were sent for the Update XML
     $update_items = array();
     try {
         if ($request->request->get('status') !== null) {
             $anime->setWatchedStatus($request->request->get('status'));
             $update_items[] = 'status';
         }
         if ($request->request->get('episodes') !== null) {
             $anime->setWatchedEpisodes($request->request->get('episodes'));
             $update_items[] = 'episodes';
         }
         if ($request->request->get('score') !== null) {
             $anime->setScore($request->request->get('score'));
             $update_items[] = 'score';
         }
         //API 2 Items
         if ($apiVersion >= 2.0) {
             if ($request->request->get('start') !== null) {
                 $anime->setWatchingStart(DateTime::createFromFormat('Y-m-d', $request->request->get('start')));
                 //Needs to be DT!
                 $update_items[] = 'start';
             }
             if ($request->request->get('end') !== null) {
                 $anime->setWatchingEnd(DateTime::createFromFormat('Y-m-d', $request->request->get('end')));
                 //Needs to be DT!
                 $update_items[] = 'end';
             }
             if ($request->request->get('downloaded_eps') !== null) {
                 $anime->setEpsDownloaded($request->request->get('downloaded_eps'));
                 //Int
                 $update_items[] = 'downloaded';
             }
             if ($request->request->get('storage_type') !== null) {
                 $anime->setStorage($request->request->get('storage_type'));
                 //Int (see getStorage mappings)
                 $update_items[] = 'storage';
             }
             if ($request->request->get('storage_amt') !== null) {
                 $anime->setStorageValue($request->request->get('storage_amt'));
                 //Float, either in number of discs or in GB
                 $update_items[] = 'storageAmt';
             }
             if ($request->request->get('priority') !== null) {
                 $anime->setPriority($request->request->get('priority'));
                 $update_items[] = 'priority';
             }
             if ($request->request->get('rewatch_value') !== null) {
                 $anime->setRewatchValue($request->request->get('rewatch_value'));
                 //Int
                 $update_items[] = 'rewatchValue';
             }
             if ($request->request->get('tags') !== null) {
                 $anime->setPersonalTags($request->request->get('tags'));
                 //Comma-separated string
                 $update_items[] = 'tags';
             }
             if ($request->request->get('comments') !== null) {
                 $anime->setPersonalComments($request->request->get('comments'));
                 //Plain text string. No HTML.
                 $update_items[] = 'comments';
             }
             if ($request->request->get('fansubber') !== null) {
                 $anime->setFansubGroup($request->request->get('fansubber'));
                 //Plain string
                 $update_items[] = 'fansubber';
             }
             if ($request->request->get('is_rewatching') !== null) {
                 $anime->setRewatching($request->request->get('is_rewatching'));
                 //Bool - 0 = no, 1 = yes
                 $update_items[] = 'isRewatching';
             }
             if ($request->request->get('rewatch_count') !== null) {
                 $anime->setRewatchCount($request->request->get('rewatch_count'));
                 //Int
                 $update_items[] = 'rewatchCount';
             }
         }
     } catch (\Exception $e) {
         return $this->view(array('error' => $e->getMessage()), 500);
     }
     $xmlcontent = $anime->MALApiXml($update_items);
     $connection = $this->get('atarashii_api.communicator');
     try {
         $connection->sendXML('/api/animelist/update/' . $anime->getId() . '.xml', $xmlcontent, $username, $password);
         return $this->view('ok', 200);
     } catch (Exception\ClientErrorResponseException $e) {
         $view = $this->view(array('error' => 'unauthorized'), 401);
         $view->setHeader('WWW-Authenticate', 'Basic realm="myanimelist.net"');
         return $view;
     } catch (Exception\ServerErrorResponseException $e) {
         //MAL broke API responses, so we have to check the content on the response to make sure
         //it actually was an error.
         $response = $e->getResponse()->getBody(true);
         if (stripos($response, 'Updated') === 0) {
             return $this->view('ok', 200);
         }
         return $this->view(array('error' => 'not-found'), 404);
     } catch (Exception\CurlException $e) {
         return $this->view(array('error' => 'network-error'), 500);
     }
 }