first blood

This commit is contained in:
Gilles Crettenand
2015-05-07 10:07:22 +02:00
commit a9190fe282
11 changed files with 1896 additions and 0 deletions

574
lib/AudioBook.php Normal file
View File

@@ -0,0 +1,574 @@
<?php
require_once('DbMapping.php');
function convertMSChar($src)
{
$text = preg_replace('/([\xc0-\xdf].)/se', "'&#' . ((ord(substr('$1', 0, 1)) - 192) * 64 + (ord(substr('$1', 1, 1)) - 128)) . ';'", $src);
$text = preg_replace('/([\xe0-\xef]..)/se', "'&#' . ((ord(substr('$1', 0, 1)) - 224) * 4096 + (ord(substr('$1', 1, 1)) - 128) * 64 + (ord(substr('$1', 2, 1)) - 128)) . ';'", $text);
return $text;
}
/**
* AudioBook is mapped on a Notice from NetBiblio
*
* @property string summary
* @property string sql_summary
* @property string editor
* @property string sql_editor
* @property string media
* @property string sql_media
* @property string collection
* @property string sql_collection
* @property string isbn
* @property string sql_isbn
* @property string readBy
* @property string sql_readBy
* @property string cover
* @property string sql_cover
* @property string typeMedia1
* @property string sql_typeMedia1
*
* @property string id
* @property string sql_id
* @property string title
* @property string sql_title
* @property string author
* @property string sql_author
* @property string code
* @property string sql_code
* @property string score
* @property string sql_score
* @property string type
* @property string sql_type
* @property string category
* @property string sql_category
* @property string date
* @property string sql_date
* @property string code3
* @property string sql_code3
* @property string code3Long
* @property string sql_code3Long
* @property string genre
* @property string sql_genre
* @property string genreCode
* @property string sql_genreCode
* @property string coverdisplay
* @property string sql_coverdisplay
* @property string link
* @property string sql_link
* @property string linkTitle
* @property string sql_linkTitle
* @property string itemNr
* @property string sql_itemNr
*/
class AudioBook extends DbMapping
{
public static $tableName = 'Notices';
public static $idColumn = 'NoticeID';
protected $extendedAttributeNames = 'summary editor media collection isbn readBy cover typeMedia1';
protected $attributeNames = 'id title author code score summary editor media collection isbn readBy cover type category date code3 code3Long genre genreCode coverdisplay link linkTitle itemNr typeMedia1';
private $loaded = false;
/**
* Build an AudioBook
* @param array $attributes
* @param bool $doLoadDetails
*/
public function __construct($attributes, $doLoadDetails = FALSE)
{
parent::__construct($attributes);
if ($doLoadDetails) {
$this->loadDetails();
}
}
public function loadDetails()
{
if ($this->loaded) {
return;
}
$this->editor = '';
$this->summary = '';
$this->media = '';
$this->isbn = '';
$this->collection = '';
$this->category = '';
$this->cover = '';
$sql_string = '';
// Introducing the cast as varchar(8000) to avoid the unixODBC LongText bug..
$sql_string .= "SELECT Tag, SubfieldCode, ContentShortPart, cast(ContentLongPart as varchar(3000)) as ContentLongPart, DisplayText ";
$sql_string .= "FROM NoticeFields ";
$sql_string .= "LEFT JOIN Authorities ON Authorities.AuthorityID = NoticeFields.AuthorityID ";
$sql_string .= "WHERE NoticeID = " . $this->id . " ";
$sql_string .= "ORDER BY Tag ASC, TagRepetition ASC, SubfieldCodeNr ASC;";
//print $sql_string;
// ajout de l'url de l'image amazon
$result = Connection::execute($sql_string, true);
while ($row = $result->next()) {
switch ($row['Tag']) {
case '520':
$this->summary = $this->addDetailToField(convertMSChar($this->summary), $row);
break;
case '260':
$this->editor = $this->addDetailToField($this->editor, $row);
break;
case '300':
$this->media = $this->addDetailToField($this->media, $row);
break;
case '020':
$this->isbn = $this->addDetailToField($this->isbn, $row);
break;
case '490':
$this->collection = $this->addDetailToField($this->collection, $row);
break;
case '600':
case '610':
case '650':
case '651':
case '655':
case '690':
case '691':
case '695':
case '696':
$this->category = $this->addDetailToField($this->category, $row);
break;
case '901':
$this->readBy = $this->addDetailToField($this->readBy, $row);
break;
case '856':
if ($row['SubfieldCode'] == 'u') {
$this->link = $this->addDetailToField($this->link, $row);
} else if ($row['SubfieldCode'] == 'z') {
$this->linkTitle = $this->addDetailToField($this->linkTitle, $row);
}
break;
case '899':
if ($row['SubfieldCode'] == 'a') {
$this->cover = "http://ecx.images-amazon.com/images/I/" . $row['ContentShortPart'] . "._SL320_.jpg";
}
}
if ($this->coverdisplay == 2) {
$this->cover = "http://fichiers.bsr-lausanne.ch:8089/Netbiblio3/images/covers/" . "Cover" . $this->id . "_Original.jpg";
}
}
$this->loaded = true;
}
private function addDetailToField($actualValue, $row)
{
$actualValue = ($actualValue ? $actualValue . ' ' : '');
$actualValue .= $row['ContentShortPart'] . $row['ContentLongPart'] . $row['DisplayText'];
return $actualValue;
}
/**
* If $id is an array, return an array of book, if it is only one id, return one book
* Load books details only if not an array.
*
* Beware that this search use the NoticeID, not the NoticeNr, if you need the last one
* use findByCode method instead;
* @param int|array $id
* @return AudioBook|AudioBook[]
*/
public static function find($id)
{
$id = str_replace("'", "''", $id);
$fullIdColumn = 'ab.'.AudioBook::$idColumn;
if (is_array($id)) {
if (count($id) > 0) {
$condition = $fullIdColumn . ' IN (' . implode(', ', $id) . ')';
} else {
$condition = "$fullIdColumn IS NULL"; // bad way of returning an empty ResultSet
}
$top = 'DISTINCT ';
} else {
$condition = "$fullIdColumn = $id";
$top = 'TOP 1';
}
$sql = sprintf("SELECT %s
ab.[%s] AS id,
[Title] AS title,
[Author] AS author,
LTRIM(RTRIM(NoticeNr)) AS code,
RTRIM(userdefined3code) AS code3,
[code3Code].TextFre AS code3Long,
[genreCode].TextFre AS genre,
[genreCode].Code AS genreCode,
[coverdisplay],
[MediaType1Code] AS typeMedia1,
12 AS score,
CONVERT(varchar, CreationDate, 102) AS date
FROM [%s] AS ab
INNER JOIN Codes code3Code ON ab.userdefined3code = code3Code.Code AND code3Code.Type=6
INNER JOIN Codes genreCode ON MediaType2Code = genreCode.Code AND genreCode.Type = 2
WHERE %s AND LTRIM(RTRIM(noticenr)) NOT LIKE '%%~%%' ORDER BY Author, Title
;", $top, self::$idColumn, self::$tableName, $condition);
$result_set = Connection::execute($sql, true);
if (is_array($id)) {
$result = array();
foreach ($id as $book_id) {
while ($row = $result_set->next()) {
if ($row['id'] == $book_id) {
$result[] = new AudioBook($row, TRUE);
break;
}
}
$result_set->rewind();
}
} else {
$row = $result_set->next();
if (!$row) {
return null;
// throw new Exception("NotFoundException");
}
$result = new AudioBook($row, TRUE);
}
return $result;
}
/**
* Return a book or an array of book given their notice number without any letter.
*
* if $code is an array, return an array of book. If not, return the first match.
*
* Due to the fact that notice number is incosistent in the Notices table,
* we use the si_sentences view instead.
*
* @param string $code
* @return AudioBook
* @throws Exception
* @throws SqlException
*/
public static function findByCode3($code)
{
$fullIdColumn = AudioBook::$tableName . '.' . AudioBook::$idColumn;
if (is_array($code)) {
$value = str_replace("'", "''", implode(" ", $code));
$value = str_replace(' ', "', '", $value);
$top = '';
$condition = "si_sentences.[Key] IN ('" . $value . "')";
} else {
$value = str_replace("'", "''", $code);
$top = 'top 1';
$condition = "si_sentences.[Key] = '$value'";
}
$sql_string = '';
$sql_string .= "SELECT $top $fullIdColumn as id, ";
$sql_string .= "Title as title, Author as author, si_sentences.[Key] as code, ";
$sql_string .= "Codes.TextFre As type, ";
$sql_string .= "0 AS score ";
$sql_string .= "FROM " . AudioBook::$tableName;
$sql_string .= " INNER JOIN Codes ON " . AudioBook::$tableName . ".MediaType2Code = Codes.Code AND Codes.Type = 2 ";
$sql_string .= " INNER JOIN si_sentences ON si_sentences.NoticeID = Notices.NoticeID";
$sql_string .= " AND si_sentences.Category = 'Code'";
$sql_string .= " WHERE ($condition) ORDER BY author, title;";
$result_set = Connection::execute($sql_string, false);
if (is_array($code)) {
$result = array();
foreach ($code as $book_code) {
while ($row = $result_set->next()) {
if ($row['code'] == $book_code) {
$result[] = new AudioBook($row, FALSE);
break;
}
}
$result_set->rewind();
}
} else {
$row = $result_set->next();
if (!$row) {
throw new Exception("NotFoundException");
}
$result = new AudioBook($row, TRUE);
}
return $result;
}
public static function findByCode($code)
{
$fullIdColumn = AudioBook::$tableName . '.' . AudioBook::$idColumn;
if (is_array($code)) {
$value = str_replace("'", "''", implode(" ", $code));
$value = str_replace(' ', "', '", $value);
$top = '';
$condition = "LTRIM(RTRIM(NoticeNr)) in ('" . $value . "')";
} else {
$value = str_replace("'", "''", $code);
$top = 'top 1';
$condition = "LTRIM(RTRIM(NoticeNr)) = '$value'";
}
$sql_string = '';
$sql_string .= "SELECT $top $fullIdColumn as id, ";
$sql_string .= "Notices.Title as title, Notices.Author as author, LTRIM(RTRIM(NoticeNr)) as code, ";
$sql_string .= "Codes.TextFre As type, ";
$sql_string .= "0 AS score ";
$sql_string .= "FROM " . AudioBook::$tableName;
$sql_string .= " INNER JOIN Codes ON " . AudioBook::$tableName . ".MediaType2Code = Codes.Code AND Codes.Type = 2 ";
$sql_string .= " WHERE ($condition) ORDER BY author, title ;";
$result_set = Connection::execute($sql_string, false);
if (is_array($code)) {
$result = array();
while ($row = $result_set->next()) {
$result[] = new AudioBook($row, true);
}
return $result;
} else {
$row = $result_set->next();
if (!$row) {
throw new Exception("NotFoundException");
}
$result[] = new AudioBook($row, true);
}
return $result;
}
/**
* @param $code
* @return int
* @throws Exception
* @throws SqlException
*/
public static function findIdByCode($code)
{
$sql = "SELECT NoticeId FROM Notices WHERE LTRIM(RTRIM(NoticeNr)) = '$code';";
$result = Connection::execute($sql, false);
if ($result === false || $result->length == 0) {
throw new Exception("NotFoundException");
}
$row = $result->current();
return $row['NoticeId'];
}
/**
* Retrieve the last books for each type. If 'type' is an empty string, then
* it returns all types.
*/
public static function lastBooksByType($type, $itemsByGroup = 10)
{
$type_before_escape = $type;
$type = Connection::escape(utf8_decode($type));
if ($type_before_escape == "Jeunesse") {
if ($itemsByGroup < 20)
$itemsByGroup = 20;
$sqlQuery = " SELECT top " . $itemsByGroup . " Notices.NoticeId AS id, ";
$sqlQuery .= " Notices.title AS title, ";
$sqlQuery .= " Notices.author AS author, ";
$sqlQuery .= " LTRIM(RTRIM(Notices.NoticeNr)) AS code, ";
$sqlQuery .= " 'Jeunesse' AS type, 0 as score, ";
$sqlQuery .= " convert(varchar, CreationDate, 102) as date ";
$sqlQuery .= " FROM Notices ";
$sqlQuery .= " WHERE Notices.NoticeNr NOT LIKE '%~%' ";
$sqlQuery .= " AND Notices.NoticeNr NOT LIKE '%V%' ";
$sqlQuery .= " AND Notices.NoticeNr NOT LIKE '%T%' ";
$sqlQuery .= " AND Notices.MediaType1Code = 'CDD' ";
$sqlQuery .= " AND Notices.Visible = 1 ";
$sqlQuery .= " AND Notices.AgeCode in ('E', 'J') ";
$sqlQuery .= " ORDER BY date DESC;";
} else {
$sqlQuery = "WITH cte AS ( ";
$sqlQuery .= " SELECT Notices.NoticeId AS id, ";
$sqlQuery .= " Notices.title AS title, ";
$sqlQuery .= " Notices.author AS author, ";
$sqlQuery .= " LTRIM(RTRIM(Notices.NoticeNr)) AS code, ";
$sqlQuery .= " Codes.TextFre AS type, ";
$sqlQuery .= " convert(varchar, CreationDate, 102) as date, ";
$sqlQuery .= " rank() OVER ( ";
$sqlQuery .= " PARTITION BY Codes.TextFre ";
$sqlQuery .= " ORDER BY cast(LTRIM(RTRIM(Notices.NoticeNr)) as int) DESC ";
$sqlQuery .= " ) AS num ";
$sqlQuery .= " FROM Notices ";
$sqlQuery .= " INNER JOIN Codes ";
$sqlQuery .= " ON Notices.MediaType2Code = Codes.Code ";
$sqlQuery .= " WHERE Codes.Type = 2 ";
if (strlen($type))
$sqlQuery .= " AND Codes.TextFre = " . $type . " ";
$sqlQuery .= " AND Notices.NoticeNr NOT LIKE '%~%' ";
$sqlQuery .= " AND Notices.NoticeNr NOT LIKE '%V%' ";
$sqlQuery .= " AND Notices.NoticeNr NOT LIKE '%T%' ";
$sqlQuery .= " AND Notices.MediaType1Code = 'CDD' ";
$sqlQuery .= " AND Notices.Visible = 1 ";
$sqlQuery .= " GROUP BY Codes.TextFre, ";
$sqlQuery .= " Notices.NoticeNr, ";
$sqlQuery .= " Notices.NoticeId, ";
$sqlQuery .= " Notices.title, ";
$sqlQuery .= " Notices.author, ";
$sqlQuery .= " Notices.CreationDate ";
$sqlQuery .= ") ";
$sqlQuery .= "SELECT id, title, author, code, type, 0 as score, date ";
$sqlQuery .= "FROM cte ";
$sqlQuery .= "WHERE num <= " . intval($itemsByGroup) . " ";
$sqlQuery .= "ORDER BY date DESC;";
}
$resultSet = Connection::execute($sqlQuery);
$result = array();
while (($row = $resultSet->next()))
$result[] = new AudioBook($row, TRUE);
return $result;
}
/**
* Retrieve the list of all readers (volunteers) having read at least 4 books (2 notices per book).
* Returns an associative array containing $lastname and $firstname
*/
public static function listOfReaders()
{
$sql = "SELECT
count(*),
ContentShortPart AS name
FROM noticefields
WHERE Tag=901
GROUP BY ContentShortPart
HAVING count(*) > 6
ORDER BY SUBSTRING(ContentShortPart, CHARINDEX(' ', ContentShortPart)+1, 15);";
$results = Connection::execute($sql);
return array_map(function($row) {
$fullname = str_replace("*", "", $row['name']);
$parts = explode(" ", $fullname);
$firstname = array_shift($parts);
$lastname = implode(" ", $parts);
return array(
'lastname' => $lastname,
'firstname' => $firstname);
}, $results->to_array());
}
/**
* Retrieve the list of all categories
*/
public static function listOfCategories()
{
$sql = "SELECT
LTRIM(RTRIM(Code)) as code,
TextFre AS text
FROM Codes
WHERE
type=2
AND Code!='-'
ORDER BY TextFre;";
$results = Connection::execute($sql);
return array_map(function($row) {
return array(
'code' => $row['code'],
'text' => $row['text'],
);
}, $results->to_array());
}
/**
* Retrieve the list of all type available in the database.
*/
public static function listOfTypes()
{
$sql = "SELECT DISTINCT
Codes.TextFre AS type
FROM Codes
INNER JOIN Notices ON Codes.Code = Notices.MediaType2Code
WHERE
Codes.Type = 2
AND Notices.NoticeNr NOT LIKE '%~%'
AND Notices.NoticeNr NOT LIKE '%V%'
AND Notices.NoticeNr NOT LIKE '%T%'
AND Notices.MediaType1Code = 'CDD';";
$results = Connection::execute($sql);
$results = array_map(function($r) {
return $r['type'];
}, $results->to_array());
array_unshift($results, "Jeunesse");
return $results;
}
/**
* Retrieve the list of all books currently lended to readers.
*/
public static function inReading()
{
$sql = "SELECT
noticenr, title, author, displayName
FROM notices, items, circulations, useraccounts
WHERE
mediatype1code='N' and NoticeNr not like '%~%'
AND items.noticeid = notices.noticeid
AND items.ItemID=circulations.ItemID
AND useraccounts.useraccountid=circulations.useraccountid
ORDER BY author, title;";
$results = Connection::execute($sql);
return array_map(function($row) {
return array(
"noticenr" => $row['noticenr'],
"auteur" => $row['author'],
"titre" => $row['title'],
"lecteur" => $row['displayName']
);
}, $results->to_array());
}
public function to_array()
{
if (!$this->loaded) {
$this->loadDetails();
}
return parent::to_array();
}
public function __set($name, $value)
{
if ($name == 'code' && is_string($value)) {
$value = preg_replace('/[~a-zA-Z]/', '', $value);
}
parent::__set($name, $value);
}
}

78
lib/BookSearch.php Normal file
View File

@@ -0,0 +1,78 @@
<?php
mb_http_output('UTF-8');
class BookSearch
{
/** @var SolrClient */
private $client;
/** @var SolrQuery */
private $query;
private $queryParts = array();
public function __construct()
{
$options = array
(
'hostname' => Configuration::get('solr.server'),
'port' => Configuration::get('solr.port'),
'login' => Configuration::get('solr.username'),
'password' => Configuration::get('solr.password'),
);
$this->client = new SolrClient($options);
$this->query = new SolrQuery();
$this->query->setQuery('*:*');
$this->query->addField('id');
$this->query->addField('code');
$this->query->addParam('q.op', 'AND');
}
public function addQuery($queryText, $queryField = '')
{
if ($queryField != '')
$queryText = "$queryField:($queryText)";
$this->queryParts[] = $queryText;
}
public function addResultField($field)
{
$this->query->addField($field);
}
public function addSortField($field, $order = SolrQuery::ORDER_DESC)
{
$this->query->addSortField($field, $order);
}
public function addFacet($field, $minCount = 2)
{
$this->query->setFacet(true);
$this->query->addFacetField($field);
$this->query->setFacetMinCount($minCount, $field);
}
public function setYearInterval($beginning = 0, $end = 2500)
{
}
/**
* @param int $start
* @param int $count
* @return SolrObject
*/
public function getResults($start = 0, $count = 15)
{
if (count($this->queryParts) == 0)
$query = '*:*';
else {
$query = implode(' AND ', $this->queryParts);
}
$this->query->setQuery($query);
$this->query->setStart($start);
$this->query->setRows($count);
return $this->client->query($this->query)->getResponse();
}
}

205
lib/Connection.php Normal file
View File

@@ -0,0 +1,205 @@
<?php
class Connection
{
// Internal variable to hold the connection
private static $db;
final private function __construct() {}
/**
* @param $query
* @param bool $throw_error
* @return OdbcResultSet|resource|string
* @throws SqlException
*/
public static function execute($query, $throw_error = false)
{
$result = odbc_exec(self::get(), utf8_decode($query));
$result = new OdbcResultSet($result);
if ($result->is_error()) {
if($throw_error) {
throw new SqlException($result->get_error(), $query);
}
return $result->get_error();
}
return $result;
}
public static function get()
{
if (is_null(self::$db)) {
$dsn = sprintf(
"Driver={%s};Server=%s;Database=%s;",
Configuration::get('db.driver'),
Configuration::get('db.server'),
Configuration::get('db.name')
);
self::$db = odbc_pconnect($dsn, Configuration::get('db.username'), Configuration::get('db.password'));
if (self::$db === false) {
throw new SqlException("Unable to connect to the server.");
}
}
// Return the connection
return self::$db;
}
public static function escape($data)
{
if (is_numeric($data))
return $data;
$unpacked = unpack('H*hex', $data);
return '0x' . $unpacked['hex'];
}
final private function __clone() {}
}
class SqlException extends Exception
{
private $query;
public function __construct($message = "Sql Error", $query = "")
{
$this->query = $query;
parent::__construct($message, 0);
}
public function getSqlError()
{
return $this->getMessage().' while executing: '.$this->query;
}
}
class OdbcResultSet implements Iterator, ArrayAccess
{
public $length;
private $results;
private $error;
private $num_fields;
private $cursor_index;
public function __construct($odbc_result)
{
if ($odbc_result === false) {
$this->error = odbc_errormsg(Connection::get());
} else {
try {
$this->results = array();
$this->num_fields = odbc_num_fields($odbc_result);
if ($this->num_fields > 0) {
while ($row = odbc_fetch_row($odbc_result)) {
$data = array();
for ($i = 1; $i <= $this->num_fields; ++$i) {
$data[odbc_field_name($odbc_result, $i)] = utf8_encode(odbc_result($odbc_result, $i));
}
$this->results[] = $data;
}
};
} catch (Exception $e) {
print($e->getMessage());
}
$this->cursor_index = 0;
$this->length = count($this->results);
odbc_free_result($odbc_result);
}
}
public function is_error()
{
return ($this->error ? true : false);
}
public function get_error()
{
return $this->error;
}
public function get_row()
{
return $this->current();
}
public function to_array()
{
return $this->results;
}
// ArrayAccess
/**
* @param int $offset
* @return bool
*/
public function offsetExists($offset)
{
return !$this->error && $this->cursor_index < $this->length && $this->cursor_index >= 0;
}
/**
* @param int $offset
* @return bool|array
*/
public function offsetGet($offset)
{
return $this->offsetExists($offset) ? $this->results[$offset] : false;
}
public function offsetSet($offset, $value)
{
if($this->offsetExists($offset)) {
$this->results[$offset] = $value;
}
}
public function offsetUnset($offset)
{
throw new RuntimeException("This makes no sense at all.");
}
// Iterator
/**
* @return bool|array
*/
public function current()
{
return $this->offsetGet($this->cursor_index);
}
/**
* @return int
*/
public function key()
{
return $this->cursor_index;
}
/**
* @return array|bool
*/
public function next()
{
$current = $this->current();
++$this->cursor_index;
return $current;
}
public function rewind()
{
$this->cursor_index = 0;
}
/**
* @return bool
*/
public function valid()
{
return $this->offsetExists($this->cursor_index);
}
}

136
lib/DbMapping.php Normal file
View File

@@ -0,0 +1,136 @@
<?php
/**
* Base class for mapping objects. inherit you database filled objects from here.
*
* @property int $id
*/
abstract class DbMapping
{
protected $attributes;
protected $attributeNames = '';
protected $privateAttributeNames = '';
/**
* @param array $attributes
*/
public function __construct(array $attributes)
{
$this->setAttributes($attributes);
}
/**
* Define a bunch of attribute given by an associative array
* @param array $attributes
*/
public function setAttributes(array $attributes)
{
$this->assertAttributes($attributes);
foreach ($attributes as $key => $value) {
$this->__set($key, $value);
}
}
/**
* Ensure that all keys from attributes are authorized
* @param array $attributes
*/
private function assertAttributes(array $attributes)
{
foreach ($attributes as $key => $value) {
$this->assertAttribute($key);
}
}
/**
* Ensure that name attribute is authorized
* If public_only is false, check agains PRIVATE_ATTRIBUTES_NAME too.
* Those one cannot be accessed via setAttributes and other batch methods.
* @param string $name
* @param bool $public_only
* @throws InvalidAttributeException if the attribute is not a valid one
*/
private function assertAttribute($name, $public_only = TRUE)
{
if (strpos($this->attributeNames, $name) === false && ($public_only || strpos($this->privateAttributeNames, $name) === false)) {
throw(new InvalidAttributeException("The attribute $name is invalid"));
}
}
/**
* Get a user attribute or the linked whishes
*
* If the name start with sql_, escape the string before to return it to avoid SQL injection.
* @param string $name
* @return mixed
*/
public function __get($name)
{
$sql_safe = FALSE;
if (strpos($name, 'sql_') === 0) {
$name = substr($name, 4);
$sql_safe = TRUE;
}
$this->assertAttribute($name, false);
if (isset($this->attributes[$name])) {
$value = $this->attributes[$name];
if ($sql_safe) {
$value = str_replace("'", "''", $value);
}
return $value;
} else {
return NULL;
}
}
public function to_array() {
return $this->attributes;
}
/**
* Set a user attribute
* @param string $name
* @param mixed $value
*/
public function __set($name, $value)
{
$this->assertAttribute($name, false);
$this->attributes[$name] = $value;
}
public function reload()
{
$this->setAttributes(DbMapping::find($this->id)->toArray());
}
/**
* Function to retrieve data from an id.
* @param int $id
* @return DbMapping
*/
abstract public static function find($id);
/**
* Return all the public attributes in an array;
*/
public function toArray()
{
$result = array();
foreach ($this->attributes as $name => $value) {
if (strpos($this->attributeNames, $name) !== false) {
$result[$name] = $value;
}
}
return $result;
}
}
/**
* Exception raised when an invalid attribute name is accessed
*/
class InvalidAttributeException extends Exception
{
}

282
lib/User.php Normal file
View File

@@ -0,0 +1,282 @@
<?php
require_once('DbMapping.php');
require_once('AudioBook.php');
/**
* User is mapped on the Useraccounts table. Contains user information : id, login, firstName, lastName, displayName.
*
* @property int id
* @property string $login
* @property string $sql_login
* @property string $password
* @property string $sql_password
* @property string $privatePhone
* @property string $sql_privatePhone
* @property string $officePhone
* @property string $sql_officePhone
* @property string $mobilePhone
* @property string $sql_mobilePhone
* @property string $addressId
* @property string $sql_addressId
* @property string $displayName
* @property string $sql_displayName
* @property string $firstName
* @property string $sql_firstName
* @property string $lastName
* @property string $sql_lastName
* @property string $mail
* @property string $sql_mail
*/
class User extends DbMapping
{
public static $tableName = 'Useraccounts';
public static $idColumn = 'UseraccountID';
protected static $addressTableName = 'Addresses';
protected static $addressIdColumn = 'AddressID';
protected static $wishTableName = 'Wishes';
protected static $circulationTableName = 'Circulations';
protected static $itemTableName = 'Items';
protected $wishes;
protected $circulations;
protected $oldCirculations;
protected $attributeNames = 'id login firstName lastName displayName freeOne mail addressId mobilePhone officePhone privatePhone';
protected $privateAttributeNames = 'password';
/**
* @param string $login Login for the user
* @param string $password Password for the user
* @return User|null User object if we were able to authenticate
*/
public static function authenticate($login, $password)
{
$password = str_replace("'", "''", $password);
return User::find($login, " UPPER(password) = UPPER('$password') ", false);
}
/**
* Retrieve a user by its login. Do not represent a valid authentication.
*
* Cond has to be safe because no check are made inside.
*
* @param string $login login the login name
* @param string $cond a condition to restrict the choice, optional
* @param bool $raiseError
* @return User the User object or NULL if no user found.
*/
public static function find($login, $cond = '', $raiseError = true)
{
$login = str_replace("'", "''", $login);
if(strlen($cond) > 0) {
$cond = " AND $cond";
}
$sql = sprintf("SELECT TOP 1
[FirstName] AS firstName,
[LastName] AS lastName,
[DisplayName] AS displayName,
[UserDefined1] AS freeOne,
[ActualAddressID] AS addressId,
[Email] AS mail,
[TelephoneMobile] AS mobilePhone,
[TelephonePrivate] AS privatePhone,
[Telephone] AS officePhone,
[%s] AS id,
REPLACE(UseraccountNr, ' ', '') AS login
FROM [%s] AS u
LEFT JOIN [%s] AS a ON a.[%s] = u.[ActualAddressID]
WHERE REPLACE(UseraccountNr, ' ', '') = '%s' AND disabled = 1 %s;",
self::$idColumn, self::$tableName, self::$addressTableName, self::$addressIdColumn, $login, $cond);
$results = Connection::execute($sql, $raiseError);
return $results->current() !== false ? new User($results->current()) : null;
}
public function __toString()
{
return $this->displayName;
}
/**
* Update the database. Note that new user insertion don't work in this implementation.
*/
public function save()
{
$strSQL = "UPDATE " . User::$tableName . " SET FirstName = '$this->sql_firstName', LastName = '$this->sql_lastName', ";
$strSQL .= "DisplayName = '$this->sql_displayName'";
$strSQL .= "WHERE Replace(UseraccountNr, ' ', '') = '$this->sql_login'";
Connection::execute($strSQL, true);
$strSQL = "UPDATE " . User::$addressTableName . " SET Email = '$this->sql_mail', TelephoneMobile = '$this->sql_mobilePhone', ";
$strSQL .= "Telephone = '$this->sql_officePhone', TelephonePrivate = '$this->sql_privatePhone' ";
$strSQL .= "WHERE " . User::$addressTableName . "." . User::$addressIdColumn . " = $this->sql_addressId";
Connection::execute($strSQL, true);
if ($this->password) {
$strSQL = "UPDATE " . User::$tableName . " SET Password = UPPER('$this->sql_password') ";
$strSQL .= "WHERE Replace(UseraccountNr, ' ', '') = '$this->sql_login'";
Connection::execute($strSQL, true);
}
}
public function reload()
{
$this->setAttributes(User::find($this->login)->toArray());
}
public function getCirculations()
{
if (!$this->circulations) {
$strSQL = "SELECT NoticeId, CheckOutDate, ItemNr FROM Circulations, Items " .
"WHERE Circulations.UseraccountId = $this->id and Items.ItemId=Circulations.ItemId " .
"ORDER BY ItemNr asc";
$result = Connection::execute($strSQL);
$ids = array();
$checkOutDates = array();
$itemNrs = array();
while ($row = $result->next()) {
$ids[] = $row['NoticeId'];
$checkOutDates[] = $row['CheckOutDate'];
$itemNrs[] = $row['ItemNr'];
}
$this->circulations = AudioBook::find($ids);
// ici je remplace le champs date du livre par la date du prêt
$counter = 0;
foreach ($this->circulations as &$circulation) {
$circulation->date = substr($checkOutDates[$counter], 0, 10);
$circulation->itemNr = $itemNrs[$counter];
$counter++;
}
}
return $this->circulations;
}
public function getOldCirculations()
{
//if(!$this->oldCirculations){
$strSQL = "SELECT NoticeId, CheckOutDate FROM OldCirculations, Items " .
"WHERE OldCirculations.UseraccountId = $this->id and Items.ItemId=OldCirculations.ItemId " .
"ORDER BY CheckOutDate desc";
$result = Connection::execute($strSQL);
$ids = array();
$checkOutDates = array();
while ($row = $result->next()) {
$ids[] = $row['NoticeId'];
$checkOutDates[] = $row['CheckOutDate'];
}
$this->oldCirculations = AudioBook::find($ids);
// ici je remplace le champs date du livre par la date du prêt
$counter = 0;
foreach ($this->oldCirculations as &$circulation) {
$circulation->date = substr($checkOutDates[$counter], 0, 10);
$counter++;
}
//}
return $this->oldCirculations;
}
/**
* Add a book to the wish list if it is not already inside.
*
* delete the wishes cache for it to be reloaded the next time getWishes will be called.
* @param int $noticeId
* @return bool
*/
public function addWish($noticeId)
{
$noticeId = str_replace("'", "''", $noticeId);
if (!$this->hasWish($noticeId)) {
// recover last id
$idSQL = "SELECT WishID from Counters";
$idResult = Connection::execute($idSQL, true);
// return print_r($idResult, 1);
if ($row = $idResult->next()) {
// get new value
$newWishID = $row['WishID'] + 1;
// update counter
$idSQL = "UPDATE Counters SET WishID=" . $newWishID;
Connection::execute($idSQL, true);
$table = User::$wishTableName;
$employee_id = Configuration::get('www_employee_id');
$library_id = Configuration::get('www_library_id');
$strSQL = "INSERT INTO $table (WishID, " . AudioBook::$idColumn . ", " . User::$idColumn . ", CreationDate, EmployeeID, BranchOfficeID, Remark, ModificationDate)";
$strSQL .= " VALUES($newWishID, $noticeId, $this->id, GETDATE(), $employee_id, $library_id, '', GETDATE())";
// return $strSQL;
Connection::execute($strSQL);
// $this->wishes = NULL;
return true;
} else {
return false;
}
}
return false;
}
/**
* Return true if the book is in the wish list
* @param int $noticeId
* @return bool
*/
public function hasWish($noticeId)
{
foreach ($this->getWishes() as $book) {
if ($book->id == $noticeId) {
return true;
}
}
return false;
}
/**
* Wishes are all the books that this user want to read.
* @param int $limit
* @return AudioBook[]
*/
public function getWishes($limit = 50)
{
if (!$this->wishes) {
$strSQL = "SELECT TOP " . $limit . AudioBook::$idColumn . " FROM " . User::$wishTableName . " WHERE " . User::$idColumn . " = $this->id ORDER BY CreationDate desc";
$result = Connection::execute($strSQL);
$ids = array();
while ($row = $result->next()) {
$ids[] = $row['NoticeID'];
}
$this->wishes = AudioBook::find($ids);
}
return $this->wishes;
}
/**
* Remove a book from the wish list
* @param int $noticeId
*/
public function deleteWish($noticeId)
{
$noticeId = str_replace("'", "''", $noticeId);
$table = User::$wishTableName;
$strSQL = "DELETE FROM $table";
$strSQL .= " WHERE " . AudioBook::$idColumn . " = $noticeId AND " . User::$idColumn . " = $this->id;";
Connection::execute($strSQL, true);
}
}