Ajout d'une extension

This commit is contained in:
Gauvain Boiché
2020-04-04 18:27:27 +02:00
parent c3ed8cc1c1
commit 3a964fe237
387 changed files with 58921 additions and 0 deletions

View File

@@ -0,0 +1,262 @@
<?php
/**
*
* phpBB Studio - Advanced Shop System. An extension for the phpBB Forum Software package.
*
* @copyright (c) 2019, phpBB Studio, https://www.phpbbstudio.com
* @license GNU General Public License, version 2 (GPL-2.0)
*
*/
namespace phpbbstudio\ass\operator;
/**
* phpBB Studio - Advanced Shop System: Blocks operator
*/
class blocks
{
/** @var \phpbbstudio\aps\core\functions */
protected $aps_functions;
/** @var \phpbb\auth\auth */
protected $auth;
/** @var \phpbb\config\config */
protected $config;
/** @var \phpbb\db\driver\driver_interface */
protected $db;
/** @var \phpbb\group\helper */
protected $group_helper;
/** @var \phpbbstudio\ass\operator\item */
protected $operator_item;
/** @var \phpbb\template\template */
protected $template;
/** @var \phpbb\user_loader */
protected $user_loader;
/** @var string ASS Categories table */
protected $categories_table;
/** @var string ASS Items table */
protected $items_table;
/** @var string ASS Logs table */
protected $logs_table;
/**
* Constructor.
*
* @param \phpbbstudio\aps\core\functions $aps_functions APS Functions object
* @param \phpbb\auth\auth $auth Auth object
* @param \phpbb\config\config $config Config object
* @param \phpbb\db\driver\driver_interface $db Database object
* @param \phpbb\group\helper $group_helper Group helper object
* @param \phpbbstudio\ass\operator\item $operator_item Item operator object
* @param \phpbb\template\template $template Template object
* @param \phpbb\user_loader $user_loader User loader object
* @param string $categories_table ASS Categories table
* @param string $items_table ASS Items table
* @param string $logs_table ASS Logs table
*/
public function __construct(
\phpbbstudio\aps\core\functions $aps_functions,
\phpbb\auth\auth $auth,
\phpbb\config\config $config,
\phpbb\db\driver\driver_interface $db,
\phpbb\group\helper $group_helper,
item $operator_item,
\phpbb\template\template $template,
\phpbb\user_loader $user_loader,
$categories_table,
$items_table,
$logs_table
)
{
$this->aps_functions = $aps_functions;
$this->auth = $auth;
$this->config = $config;
$this->db = $db;
$this->group_helper = $group_helper;
$this->operator_item = $operator_item;
$this->template = $template;
$this->user_loader = $user_loader;
$this->categories_table = $categories_table;
$this->items_table = $items_table;
$this->logs_table = $logs_table;
}
/**
* Get the Shop display blocks.
*
* @return array The shop display blocks
*/
public function get_blocks()
{
return [
'charts' => [
'purchases_category' => 'ASS_DISPLAY_PURCHASES_CATEGORY',
'purchases_group' => 'ASS_DISPLAY_PURCHASES_GROUP',
],
'items' => [
'sale' => 'ASS_SALE_ITEMS',
'featured' => 'ASS_FEATURED_ITEMS',
'recent' => 'ASS_ITEMS_RECENT',
'purchases' => 'ASS_DISPLAY_PURCHASES_RECENT',
'available' => 'ASS_DISPLAY_LIMITED_AVAILABLE',
'limited' => 'ASS_DISPLAY_LIMITED_STOCK',
],
'users' => [
'buyers' => 'ASS_DISPLAY_BIGGEST_BUYERS',
'gifters' => 'ASS_DISPLAY_BIGGEST_GIFTERS',
'spenders' => 'ASS_DISPLAY_BIGGEST_SPENDERS',
],
];
}
/**
* Display the "charts" blocks.
*
* @param string $block The block name
* @return void
*/
protected function charts($block)
{
$s_group = $block === 'purchases_group';
if ($s_group)
{
$sql = 'SELECT g.group_name, COUNT(l.log_id) as purchases
FROM ' . $this->logs_table . ' l,
' . $this->aps_functions->table('users') . ' u,
' . $this->aps_functions->table('groups') . ' g
WHERE l.item_purchase = 1
AND l.user_id = u.user_id
AND u.group_id = g.group_id
AND g.group_type <> ' . GROUP_HIDDEN . '
GROUP BY g.group_name
ORDER BY purchases DESC';
}
else
{
$sql = 'SELECT c.category_title, SUM(i.item_purchases) as purchases
FROM ' . $this->items_table . ' i,
' . $this->categories_table . ' c
WHERE i.category_id = c.category_id' .
(!$this->auth->acl_get('u_ass_can_view_inactive_items') ? ' AND c.category_active = 1' : '') . '
GROUP BY i.category_id
ORDER BY c.category_order';
}
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
{
$name = $s_group ? $this->group_helper->get_name($row['group_name']) : $row['category_title'];
$this->template->assign_block_vars($block, [
'NAME' => (string) $name,
'PURCHASES' => (int) $row['purchases'],
]);
}
$this->db->sql_freeresult($result);
}
/**
* Display the "items" blocks.
*
* @param string $block The block name
* @return void
*/
protected function items($block)
{
$items = $this->operator_item->assign_specific_items($block, 3, 0, false);
foreach ($items as $item)
{
$this->template->assign_block_vars($block, $this->operator_item->get_variables($item));
}
}
/**
* Display the "users" blocks.
*
* @param string $block The block name
* @return void
*/
protected function users($block)
{
switch ($block)
{
case 'buyers':
$select = 'COUNT(log_id)';
$where = ' WHERE item_purchase = 1 AND recipient_id = 0';
break;
case 'gifters':
$select = 'COUNT(log_id)';
$where = ' WHERE item_purchase = 1 AND recipient_id <> 0';
break;
case 'spenders':
default:
$select = 'SUM(points_sum)';
$where = '';
break;
}
$sql = 'SELECT ' . $select . ' as count, user_id
FROM ' . $this->logs_table . $where . '
GROUP BY user_id
ORDER BY count DESC';
$result = $this->db->sql_query_limit($sql, 3);
$rowset = $this->db->sql_fetchrowset($result);
$this->db->sql_freeresult($result);
$users = array_column($rowset, 'count', 'user_id');
$this->user_loader->load_users(array_map('intval', array_keys($users)));
foreach ($users as $user_id => $count)
{
$avatar = $this->user_loader->get_avatar($user_id);
$avatar = $avatar ? $avatar : $this->aps_functions->get_no_avatar();
$this->template->assign_block_vars($block, [
'NAME' => $this->user_loader->get_username($user_id, 'full'),
'AVATAR' => $avatar,
'COUNT' => $count,
]);
}
$this->template->assign_var('USER_BLOCK', $block);
}
/**
* Magic method to call a function within this object.
*
* Needed as APS only calls each function ones,
* and ASS groups all blocks to certain categories.
* So, the block listener calls the block name in this object,
* which by this method is routed to the category's function.
*
* @see \phpbbstudio\ass\event\blocks_listener
*
* @param $method
* @param $arguments
* @return void
*/
public function __call($method, $arguments)
{
foreach ($this->get_blocks() as $type => $blocks)
{
if (in_array($method, array_keys($blocks)))
{
call_user_func_array([$this, $type], $arguments);
}
}
}
}

View File

@@ -0,0 +1,236 @@
<?php
/**
*
* phpBB Studio - Advanced Shop System. An extension for the phpBB Forum Software package.
*
* @copyright (c) 2019, phpBB Studio, https://www.phpbbstudio.com
* @license GNU General Public License, version 2 (GPL-2.0)
*
*/
namespace phpbbstudio\ass\operator;
use phpbb\exception\runtime_exception;
use phpbbstudio\ass\entity\category as entity;
use phpbbstudio\ass\exceptions\shop_exception;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* phpBB Studio - Advanced Shop System: Category operator
*/
class category
{
/** @var \phpbb\auth\auth */
protected $auth;
/** @var ContainerInterface */
protected $container;
/** @var \phpbb\db\driver\driver_interface */
protected $db;
/** @var \phpbbstudio\ass\helper\router */
protected $router;
/** @var string Categories table */
protected $categories_table;
/**
* Constructor.
*
* @param \phpbb\auth\auth $auth Auth object
* @param ContainerInterface $container Service container object
* @param \phpbb\db\driver\driver_interface $db Database object
* @param \phpbbstudio\ass\helper\router $router Router helper object
* @param string $categories_table Categories table
* @return void
* @access public
*/
public function __construct(
\phpbb\auth\auth $auth,
ContainerInterface $container,
\phpbb\db\driver\driver_interface $db,
\phpbbstudio\ass\helper\router $router,
$categories_table
)
{
$this->auth = $auth;
$this->container = $container;
$this->db = $db;
$this->router = $router;
$this->categories_table = $categories_table;
}
/**
* Get a category entity.
*
* @return entity|object The category entity
* @access public
*/
public function get_entity()
{
return $this->container->get('phpbbstudio.ass.entity.category');
}
/**
* Get loaded category entities for a rowset.
*
* @param array $rowset The rowset retrieved from the categories table
* @return array Category entities
* @access public
*/
public function get_entities(array $rowset)
{
$categories = [];
foreach ($rowset as $row)
{
$categories[(int) $row['category_id']] = $this->get_entity()->import($row);
}
return (array) $categories;
}
/**
* Load a category entity from a slug.
*
* @param string $category_slug The category slug
* @return entity The category entity
* @throws shop_exception
* @access public
*/
public function load_entity($category_slug)
{
$category = $this->get_entity();
try
{
$category->load(0, $category_slug);
}
catch (runtime_exception $e)
{
throw new shop_exception(404, 'ASS_ERROR_NOT_FOUND_CATEGORY');
}
if (!$category->get_active() && !$this->auth->acl_get('u_ass_can_view_inactive_items'))
{
throw new shop_exception(403, 'ASS_ERROR_NOT_ACTIVE_CATEGORY');
}
return $category;
}
/**
* Get all (active) category entities.
*
* @param bool $only_active Whether or not to only load active categories
* @return array Category entities
* @access public
*/
public function get_categories($only_active = false)
{
$sql = 'SELECT *
FROM ' . $this->categories_table . '
' . ($only_active && !$this->auth->acl_get('u_ass_can_view_inactive_items') ? 'WHERE category_active = 1' : '') . '
ORDER BY category_order ASC';
$result = $this->db->sql_query($sql);
$rowset = $this->db->sql_fetchrowset($result);
$this->db->sql_freeresult($result);
return $this->get_entities($rowset);
}
/**
* Get category entities from identifiers.
*
* @param array $ids The category identifiers
* @return array Category entities
* @access public
*/
public function get_categories_by_id(array $ids)
{
$sql = 'SELECT *
FROM ' . $this->categories_table . '
WHERE ' . $this->db->sql_in_set('category_id', array_unique($ids), false, true) .
(!$this->auth->acl_get('u_ass_can_view_inactive_items') ? ' AND category_active = 1' : '') . '
ORDER BY category_order ASC';
$result = $this->db->sql_query($sql);
$rowset = $this->db->sql_fetchrowset($result);
$this->db->sql_freeresult($result);
return $this->get_entities($rowset);
}
/**
* Delete a category.
*
* @param int $category_id The category identifier
* @return bool Whether or not the category was deleted
* @access public
*/
public function delete_category($category_id)
{
$sql = 'DELETE FROM ' . $this->categories_table . '
WHERE category_id = ' . (int) $category_id;
$this->db->sql_query($sql);
return (bool) $this->db->sql_affectedrows();
}
/**
* Move a category.
*
* @param int $category_id The category identifier
* @param int $order The new category order
* @return bool Whether or not the category was moved
* @access public
*/
public function move($category_id, $order)
{
$category_id = (int) $category_id;
$order = (int) $order;
$entity = $this->get_entity()->load($category_id);
$lower = $entity->get_order() > $order;
$min = $lower ? $order - 1 : $entity->get_order();
$max = $lower ? $entity->get_order() : $order + 1;
$sql = 'UPDATE ' . $this->categories_table . '
SET category_order = ' . $this->db->sql_case('category_id = ' . $entity->get_id(), $order, ($lower ? 'category_order + 1' : ' category_order - 1')) . '
WHERE category_id = ' . $entity->get_id() . '
OR category_order BETWEEN ' . $min . ' AND ' . $max;
$this->db->sql_query($sql);
return (bool) $this->db->sql_affectedrows();
}
/**
* Get category template variables.
*
* @param entity $category The category entity
* @param string $prefix The variables prefix
* @param bool $prepend Whether or not "statuses" and "URLs" should be prepended
* @return array The template variables
* @access public
*/
public function get_variables(entity $category, $prefix = '', $prepend = true)
{
$bool = $prepend ? 'S_' : '';
$link = $prepend ? 'U_' : '';
return [
"{$prefix}TITLE" => $category->get_title(),
"{$prefix}SLUG" => $category->get_slug(),
"{$prefix}DESC" => $category->get_desc(),
"{$prefix}DESC_HTML" => $category->get_desc_for_display(),
"{$prefix}ICON" => $category->get_icon(),
"{$prefix}CONFLICTS" => $category->get_conflicts(),
"{$bool}{$prefix}ACTIVE" => $category->get_active(),
"{$link}{$prefix}VIEW" => $category->get_id() ? $this->router->category($category->get_slug()) : '',
];
}
}

View File

@@ -0,0 +1,334 @@
<?php
/**
*
* phpBB Studio - Advanced Shop System. An extension for the phpBB Forum Software package.
*
* @copyright (c) 2019, phpBB Studio, https://www.phpbbstudio.com
* @license GNU General Public License, version 2 (GPL-2.0)
*
*/
namespace phpbbstudio\ass\operator;
use phpbbstudio\ass\entity\category as category_entity;
use phpbbstudio\ass\entity\item as item_entity;
/**
* phpBB Studio - Advanced Shop System: Inventory operator
*/
class inventory
{
/** @var \phpbbstudio\aps\points\distributor */
protected $aps_distributor;
/** @var \phpbbstudio\aps\core\functions */
protected $aps_functions;
/** @var \phpbb\config\config */
protected $config;
/** @var \phpbb\db\driver\driver_interface */
protected $db;
/** @var \phpbbstudio\ass\operator\item */
protected $operator_item;
/** @var \phpbb\user */
protected $user;
/** @var string Inventory table */
protected $inventory_table;
/** @var string Items table */
protected $items_table;
/** @var string Users table */
protected $users_table;
/**
* Constructor.
*
* @param \phpbbstudio\aps\points\distributor $aps_distributor APS Distributor oject
* @param \phpbbstudio\aps\core\functions $aps_functions APS Functions object
* @param \phpbb\config\config $config Config object
* @param \phpbb\db\driver\driver_interface $db Database object
* @param \phpbbstudio\ass\operator\item $operator_item Item operator object
* @param \phpbb\user $user User object
* @param string $inventory_table Inventory table
* @param string $items_table Items table
* @param string $users_table Users table
* @return void
* @access public
*/
public function __construct(
\phpbbstudio\aps\points\distributor $aps_distributor,
\phpbbstudio\aps\core\functions $aps_functions,
\phpbb\config\config $config,
\phpbb\db\driver\driver_interface $db,
item $operator_item,
\phpbb\user $user,
$inventory_table,
$items_table,
$users_table
)
{
$this->aps_distributor = $aps_distributor;
$this->aps_functions = $aps_functions;
$this->config = $config;
$this->db = $db;
$this->operator_item = $operator_item;
$this->user = $user;
$this->inventory_table = $inventory_table;
$this->items_table = $items_table;
$this->users_table = $users_table;
}
/**
* Clean up the inventories.
*
* @return bool Whether or not inventory rows were removed
* @access public
*/
public function clean_inventory()
{
$sql = 'DELETE inv
FROM ' . $this->inventory_table . ' inv
JOIN ' . $this->items_table . ' i
ON i.item_id = inv.item_id
WHERE (i.item_count <> 0
AND i.item_count <= inv.use_count
AND (i.item_delete_seconds = 0
OR i.item_delete_seconds + inv.use_time <= ' . time() . '))
OR (i.item_expire_seconds <> 0
AND i.item_expire_seconds + i.item_delete_seconds + inv.purchase_time <= ' . time() . ')';
$this->db->sql_query($sql);
return (bool) $this->db->sql_affectedrows();
}
/**
* Get a user's inventory.
*
* @param category_entity|null $category The category entity
* @return array The user's inventory
* @access public
*/
public function get_inventory(category_entity $category = null)
{
$rowset = [];
$sql_where = $category !== null ? ' AND i.category_id = ' . $category->get_id() : '';
$sql = 'SELECT i.*, u.username as gifter_name, u.user_colour as gifter_colour
FROM ' . $this->inventory_table . ' i
LEFT JOIN ' . $this->users_table . ' u
ON i.gifter_id = u.user_id
WHERE i.user_id = ' . (int) $this->user->data['user_id'] .
$sql_where;
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
{
$rowset[(int) $row['inventory_id']] = $row;
}
$this->db->sql_freeresult($result);
return (array) $rowset;
}
/**
* Get an inventory item.
*
* @param item_entity $item The item entity
* @param int $index The item index
* @return array
* @access public
*/
public function get_inventory_item(item_entity $item, $index)
{
$sql = 'SELECT *
FROM ' . $this->inventory_table . '
WHERE user_id = ' . (int) $this->user->data['user_id'] . '
AND item_id = ' . $item->get_id() . '
AND category_id = ' . $item->get_category();
$result = $this->db->sql_query_limit($sql, 1, $index);
$row = $this->db->sql_fetchrow($result);
$this->db->sql_freeresult($result);
return (array) $row;
}
/**
* Get the item stack count in a user's inventory.
*
* @param item_entity $item The item entity
* @param int $user_id The user identifier
* @return int The item stack count
* @access public
*/
public function get_inventory_stack(item_entity $item, $user_id = 0)
{
$user_id = $user_id ? $user_id : $this->user->data['user_id'];
$sql = 'SELECT COUNT(inventory_id) as stack
FROM ' . $this->inventory_table . '
WHERE user_id = ' . (int) $user_id . '
AND item_id = ' . $item->get_id() . '
AND category_id = ' . $item->get_category();
$result = $this->db->sql_query($sql);
$stack = $this->db->sql_fetchfield('stack');
$this->db->sql_freeresult($result);
return (int) $stack;
}
/**
* Add a purchase (or gift).
*
* @param item_entity $item The item entity
* @param int $user_id The user identifier
* @param bool $purchase Whether it's a purchase or a gift
* @return double
* @access public
*/
public function add_purchase(item_entity $item, $user_id = 0, $purchase = true)
{
$price = $this->get_price($item, $purchase);
$points = $this->aps_functions->equate_points($this->user->data['user_points'], $price, '-');
$points = $this->aps_functions->format_points($points);
$this->db->sql_transaction('begin');
$this->aps_distributor->update_points($points);
$sql = 'INSERT INTO ' . $this->inventory_table . ' ' . $this->db->sql_build_array('INSERT', [
'category_id' => $item->get_category(),
'item_id' => $item->get_id(),
'user_id' => $user_id ? $user_id : (int) $this->user->data['user_id'],
'gifter_id' => $user_id ? (int) $this->user->data['user_id'] : $user_id,
'purchase_time' => time(),
'purchase_price' => $price,
]);
$this->db->sql_query($sql);
$this->db->sql_transaction('commit');
return (double) $points;
}
/**
* Get the purchase (inventory row) identifier.
*
* @return int The purchase identifier
* @access public
*/
public function get_purchase_id()
{
return (int) $this->db->sql_nextid();
}
/**
* Delete an inventory item.
*
* @param int $inventory_id The inventory identifier
* @return bool Whether or not the item was deleted
* @access public
*/
public function delete($inventory_id)
{
$sql = 'DELETE FROM ' . $this->inventory_table . '
WHERE inventory_id = ' . (int) $inventory_id;
$this->db->sql_query($sql);
return (bool) $this->db->sql_affectedrows();
}
/**
* Delete inventory item(s).
*
* @param int $category_id The category identifier
* @param int $item_id The item identifier
* @return int
* @access public
*/
public function delete_items($category_id, $item_id)
{
$sql = 'DELETE FROM ' . $this->inventory_table . '
WHERE ' . ($category_id ? 'category_id = ' . (int) $category_id : 'item_id = ' . (int) $item_id);
$this->db->sql_query($sql);
return (int) $this->db->sql_affectedrows();
}
/**
* Update the activated count for an inventory item.
*
* @param int $inventory_id The inventory identifier
* @param array $data The inventory item data
* @return bool Whether or not the inventory item was updated
* @access public
*/
public function activated($inventory_id, $data)
{
$sql = 'UPDATE ' . $this->inventory_table . '
SET ' . $this->db->sql_build_array('UPDATE', $data) . '
WHERE inventory_id = ' . (int) $inventory_id;
$this->db->sql_query($sql);
return (bool) $this->db->sql_affectedrows();
}
/**
* Check if the current user can afford this item.
*
* @param item_entity $item The item entity
* @param bool $purchase Whether it's a purchase or a gift
* @return bool Whether or not the user can afford this item
* @access public
*/
public function check_price(item_entity $item, $purchase = true)
{
if ($this->config['aps_points_min'] !== '')
{
$item_points = $this->get_price($item, $purchase);
$user_points = $this->user->data['user_points'];
$points = $user_points - $item_points;
if ($points < $this->config['aps_points_min'])
{
return false;
}
}
return true;
}
/**
* Get the price for an item, taking into account sale and gift.
*
* @param item_entity $item The item entity
* @param bool $purchase Whether it's a purchase or a gift
* @return double The item price
* @access public
*/
public function get_price(item_entity $item, $purchase = true)
{
if ($purchase)
{
return $this->operator_item->on_sale($item) ? $item->get_sale_price() : $item->get_price();
}
if (!$item->get_gift_type())
{
return $item->get_gift_price();
}
$pct = $item->get_gift_percentage() / 100;
$pct = $pct + 1;
$price = $this->get_price($item) * $pct;
return $this->aps_functions->format_points($price);
}
}

View File

@@ -0,0 +1,657 @@
<?php
/**
*
* phpBB Studio - Advanced Shop System. An extension for the phpBB Forum Software package.
*
* @copyright (c) 2019, phpBB Studio, https://www.phpbbstudio.com
* @license GNU General Public License, version 2 (GPL-2.0)
*
*/
namespace phpbbstudio\ass\operator;
use phpbb\exception\runtime_exception;
use phpbbstudio\ass\exceptions\shop_exception;
use Symfony\Component\DependencyInjection\ContainerInterface;
use phpbbstudio\ass\entity\item as entity;
/**
* phpBB Studio - Advanced Shop System: Item operator
*/
class item
{
/** @var \phpbbstudio\aps\core\dbal */
protected $aps_dbal;
/** @var \phpbb\auth\auth */
protected $auth;
/** @var ContainerInterface */
protected $container;
/** @var \phpbb\db\driver\driver_interface */
protected $db;
/** @var \phpbbstudio\ass\helper\files */
protected $files;
/** @var \phpbb\path_helper */
protected $path_helper;
/** @var \phpbbstudio\ass\helper\router */
protected $router;
/** @var \phpbb\template\template */
protected $template;
/** @var \phpbbstudio\ass\helper\time */
protected $time;
/** @var \phpbb\user */
protected $user;
/** @var string Categories table */
protected $categories_table;
/** @var string Items table */
protected $items_table;
/**
* Constructor.
*
* @param \phpbbstudio\aps\core\dbal $aps_dbal APS DBAL object
* @param \phpbb\auth\auth $auth Auth object
* @param ContainerInterface $container Service container object
* @param \phpbb\db\driver\driver_interface $db Database object
* @param \phpbbstudio\ass\helper\files $files Files helper object
* @param \phpbb\path_helper $path_helper Path helper object
* @param \phpbbstudio\ass\helper\router $router Router helper object
* @param \phpbb\template\template $template Template object
* @param \phpbbstudio\ass\helper\time $time Time helper object
* @param \phpbb\user $user User object
* @param string $categories_table Categories table
* @param string $items_table Items table
* @return void
* @access public
*/
public function __construct(
\phpbbstudio\aps\core\dbal $aps_dbal,
\phpbb\auth\auth $auth,
ContainerInterface $container,
\phpbb\db\driver\driver_interface $db,
\phpbbstudio\ass\helper\files $files,
\phpbb\path_helper $path_helper,
\phpbbstudio\ass\helper\router $router,
\phpbb\template\template $template,
\phpbbstudio\ass\helper\time $time,
\phpbb\user $user,
$categories_table,
$items_table
)
{
$this->aps_dbal = $aps_dbal;
$this->auth = $auth;
$this->container = $container;
$this->db = $db;
$this->files = $files;
$this->path_helper = $path_helper;
$this->router = $router;
$this->template = $template;
$this->time = $time;
$this->user = $user;
$this->categories_table = $categories_table;
$this->items_table = $items_table;
}
/**
* Get an item entity.
*
* @return entity|object The item entity
* @access public
*/
public function get_entity()
{
return $this->container->get('phpbbstudio.ass.entity.item');
}
/**
* Get loaded item entities for a rowset.
*
* @param array $rowset The rowset retrieved from the items table
* @return entity[] Item entities
* @access public
*/
public function get_entities(array $rowset)
{
$items = [];
foreach ($rowset as $row)
{
$items[(int) $row['item_id']] = $this->get_entity()->import($row);
}
return (array) $items;
}
/**
* Load an item entity from a slug.
*
* @param string $item_slug The item slug
* @param string $category_slug The category slug
* @param string $category_id The category identifier
* @return entity The item entity
* @throws shop_exception
* @access public
*/
public function load_entity($item_slug, $category_slug, $category_id)
{
$item = $this->get_entity();
try
{
$item->load(0, $item_slug, $category_id);
}
catch (runtime_exception $e)
{
throw new shop_exception(404, 'ASS_ERROR_NOT_FOUND_ITEM');
}
$item->set_category_slug($category_slug);
if (!$item->get_active() && !$this->auth->acl_get('u_ass_can_view_inactive_items'))
{
throw new shop_exception(403, 'ASS_ERROR_NOT_ACTIVE_ITEM');
}
return $item;
}
/**
* Get item entities.
*
* @param int $category_id The category identifier
* @param string $sql_where The SQL WHERE statement
* @param string $sql_order The SQL ORDER BY statement
* @param string $sql_dir The SQL ORDER BY direction
* @param bool $active_only Whether or not to only load active items
* @param int $limit The amount of item entities to return
* @param int $start The offset from where to return entities
* @return entity[] Item entities
* @access public
*/
public function get_items($category_id, $sql_where = '', $sql_order = 'i.item_order', $sql_dir = 'ASC', $active_only = false, $limit = 0, $start = 0)
{
$sql_active = $active_only ? $this->get_sql_where_active('i.') : '';
$sql_available = $active_only ? $this->get_sql_where_available('i.') : '';
$sql = 'SELECT i.*, c.category_slug
FROM ' . $this->items_table . ' i,
' . $this->categories_table . ' c
WHERE i.category_id = c.category_id
AND i.category_id = ' . (int) $category_id . $sql_active . $sql_available . $sql_where . "
ORDER BY {$sql_order} {$sql_dir}";
$result = $limit ? $this->db->sql_query_limit($sql, $limit, $start) : $this->db->sql_query($sql);
$rowset = (array) $this->db->sql_fetchrowset($result);
$this->db->sql_freeresult($result);
return $this->get_entities($rowset);
}
/**
* Get item entities from identifiers.
*
* @param array $ids The item identifiers
* @param bool $as_entities Whether or not to return entities
* @return entity[] Item entities
* @access public
*/
public function get_items_by_id(array $ids, $as_entities = true)
{
$sql = 'SELECT i.*, c.category_slug
FROM ' . $this->items_table . ' i,
' . $this->categories_table . ' c
WHERE i.category_id = c.category_id
AND ' . $this->db->sql_in_set('i.item_id', array_unique($ids), false, true) .
$this->get_sql_where_active('i.') . '
ORDER BY i.item_order ASC';
$result = $this->db->sql_query($sql);
$rowset = (array) $this->db->sql_fetchrowset($result);
$this->db->sql_freeresult($result);
if ($as_entities)
{
return $this->get_entities($rowset);
}
else
{
return $rowset;
}
}
/**
* Get the item count for a specific category.
*
* @param int $category_id The category identifier
* @param string $sql_where The SQL WHERE statement
* @return int The item count
* @access public
*/
public function get_item_count($category_id, $sql_where = '')
{
$sql = 'SELECT COUNT(item_id) as count
FROM ' . $this->items_table . ' i,
' . $this->categories_table . ' c
WHERE i.category_id = c.category_id
AND i.category_id = ' . (int) $category_id . $sql_where . $this->get_sql_where_active('i.');
$result = $this->db->sql_query($sql);
$count = $this->db->sql_fetchfield('count');
$this->db->sql_freeresult($result);
return (int) $count;
}
/**
* Get the item types for a specific category.
*
* @param int $category_id The category identifier
* @return array The item types
* @access public
*/
public function get_item_types($category_id)
{
$types = [];
$sql = 'SELECT item_type
FROM ' . $this->items_table . '
WHERE category_id = ' . (int) $category_id . '
' . $this->get_sql_where_active() . '
GROUP BY item_type';
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
{
$types[] = $row['item_type'];
}
$this->db->sql_freeresult($result);
return $types;
}
/**
* Delete item(s).
*
* @param int $category_id The category identifier
* @param int $item_id The item identifier
* @return int Whether or not items were deleted
* @access public
*/
public function delete_items($category_id, $item_id)
{
$sql = 'DELETE FROM ' . $this->items_table . '
WHERE ' . ($category_id ? 'category_id = ' . (int) $category_id : 'item_id = ' . (int) $item_id);
$this->db->sql_query($sql);
return (int) $this->db->sql_affectedrows();
}
/**
* Move an item.
*
* @param int $item_id The item identifier
* @param int $order The new item order
* @return bool Whether or not the item was moved
* @access public
*/
public function move($item_id, $order)
{
$item_id = (int) $item_id;
$order = (int) $order;
$entity = $this->get_entity()->load($item_id);
$lower = $entity->get_order() > $order;
$min = $lower ? $order - 1 : $entity->get_order();
$max = $lower ? $entity->get_order() : $order + 1;
$sql = 'UPDATE ' . $this->items_table . '
SET item_order = ' . $this->db->sql_case('item_id = ' . $entity->get_id(), $order, ($lower ? 'item_order + 1' : 'item_order - 1')) . '
WHERE category_id = ' . $entity->get_category() . '
AND (item_id = ' . $entity->get_id() . '
OR item_order BETWEEN ' . $min . ' AND ' . $max . ')';
$this->db->sql_query($sql);
return (bool) $this->db->sql_affectedrows();
}
/**
* Get and assign specific items to the template.
*
* @param string $mode The specific mode
* @param int $limit The amount of items to assign
* @param int $category_id The category identifier
* @param bool $assign Whether or not to assign template variables
* @return entity[]
* @access public
*/
public function assign_specific_items($mode, $limit, $category_id = 0, $assign = true)
{
$items = [];
$sql_array = [
'SELECT' => 'i.*, c.category_slug',
'FROM' => [
$this->items_table => 'i',
$this->categories_table => 'c',
],
'WHERE' => 'i.category_id = c.category_id' .
($category_id ? ' AND i.category_id = ' . (int) $category_id : '') .
$this->get_sql_where_active('i.') .
$this->get_sql_where_available('i.'),
];
switch ($mode)
{
case 'featured':
$sql_array['ORDER_BY'] = 'i.item_featured_start DESC, i.item_featured_until DESC';
$sql_array['WHERE'] .= ' AND i.item_sale_until < ' . time() . '
AND i.item_featured_start <> 0 AND i.item_featured_until <> 0
AND (' . time() . ' BETWEEN i.item_featured_start AND i.item_featured_until)';
break;
case 'sale':
$sql_array['ORDER_BY'] = 'i.item_sale_start DESC, i.item_sale_until DESC';
$sql_array['WHERE'] .= ' AND i.item_featured_until < ' . time() . '
AND i.item_sale_start <> 0 AND i.item_sale_until <> 0
AND (' . time() . ' BETWEEN i.item_sale_start AND i.item_sale_until)';
break;
case 'featured_sale':
$sql_array['ORDER_BY'] = 'i.item_sale_start DESC, i.item_featured_start DESC';
$sql_array['WHERE'] .= ' AND i.item_featured_start <> 0 AND i.item_featured_until <> 0
AND (' . time() . ' BETWEEN i.item_featured_start AND i.item_featured_until)
AND i.item_sale_start <> 0 AND i.item_sale_until <> 0
AND (' . time() . ' BETWEEN i.item_sale_start AND i.item_sale_until)';
break;
case 'recent':
$sql_array['ORDER_BY'] = 'i.item_create_time DESC';
break;
case 'limited':
$sql_array['ORDER_BY'] = 'i.item_stock ASC';
$sql_array['WHERE'] .= ' AND i.item_stock <> 0 AND i.item_stock_unlimited = 0';
break;
case 'random':
$sql_array['ORDER_BY'] = $this->aps_dbal->random();
break;
case 'purchases':
$sql_array['ORDER_BY'] = 'i.item_purchases DESC';
break;
case 'available':
$sql_array['ORDER_BY'] = 'i.item_available_start DESC, i.item_available_until DESC';
$sql_array['WHERE'] .= ' AND i.item_available_start <> 0 AND i.item_available_until <> 0
AND (' . time() . ' BETWEEN i.item_available_start AND i.item_available_until)';
break;
}
$sql_array['ORDER_BY'] = !empty($sql_array['ORDER_BY']) ? $sql_array['ORDER_BY'] : 'i.item_order ASC';
$sql = $this->db->sql_build_query('SELECT', $sql_array);
$result = $this->db->sql_query_limit($sql, (int) $limit);
while ($row = $this->db->sql_fetchrow($result))
{
$item = $this->get_entity()->import($row);
if ($assign)
{
$this->template->assign_block_vars("ass_{$mode}", $this->get_variables($item));
}
$items[$item->get_id()] = $item;
}
$this->db->sql_freeresult($result);
return $items;
}
/**
* Get and assign related items to the template
*
* @param entity $item The item entity
* @return void
* @access public
*/
public function assign_related_items(entity $item)
{
$item_ids = $item->get_related_items();
if (empty($item_ids))
{
$sql = 'SELECT i.*, c.category_slug, ABS(CAST(i.item_order as SIGNED) - ' . $item->get_order() . ') as distance
FROM ' . $this->items_table . ' i,
' . $this->categories_table . ' c
WHERE i.category_id = c.category_id
AND i.category_id = ' . $item->get_category() . '
AND i.item_id <> ' . $item->get_id() .
$this->get_sql_where_active('i.') .
$this->get_sql_where_available('i.') . '
ORDER BY distance ASC';
$result = $this->db->sql_query_limit($sql, 4);
$rowset = (array) $this->db->sql_fetchrowset($result);
$this->db->sql_freeresult($result);
usort($rowset, function($a, $b) {
return $a['item_order'] - $b['item_order'];
});
}
else
{
$rowset = $this->get_items_by_id($item_ids, false);
}
foreach ($rowset as $row)
{
$entity = $this->get_entity()->import($row);
$this->template->assign_block_vars('ass_related', $this->get_variables($entity));
}
}
/**
* Get item template variables.
*
* @param entity $item The item entity
* @param string $prefix The variables prefix
* @param bool $prepend Whether or not "statuses" should be prepended
* @param int $index The item index
* @return array The template variables
* @access public
*/
public function get_variables(entity $item, $prefix = '', $prepend = true, $index = 1)
{
$bool = $prepend ? 'S_' : '';
return [
"{$prefix}ID" => $item->get_id(),
"{$prefix}TITLE" => $item->get_title(),
"{$prefix}SLUG" => $item->get_slug(),
"{$prefix}DESC" => $item->get_desc(),
"{$prefix}DESC_HTML" => $item->get_desc_for_display(),
"{$prefix}ICON" => $item->get_icon(),
"{$prefix}PRICE" => $item->get_price(),
"{$prefix}BACKGROUND" => $item->get_background(),
"{$prefix}BACKGROUND_SRC" => $item->get_background() ? $this->get_background_path($item->get_background()) : '',
"{$prefix}IMAGES" => $item->get_images(),
"{$prefix}IMAGES_SRC" => $item->get_images() ? array_map([$this, 'get_background_path'], $item->get_images()) : [],
"{$prefix}RELATED_ITEMS" => $item->get_related_items(),
"{$prefix}COUNT" => $item->get_count(),
"{$prefix}STACK" => $item->get_stack(),
"{$prefix}STOCK" => $item->get_stock(),
"{$prefix}STOCK_INITIAL" => !$item->get_stock_unlimited() ? $item->get_stock() + $item->get_purchases() : false,
"{$prefix}STOCK_THRESHOLD" => $item->get_stock_threshold(),
"{$prefix}PURCHASES" => $item->get_purchases(),
"{$prefix}CREATE_TIME" => $item->get_create_time(),
"{$prefix}EDIT_TIME" => $item->get_edit_time(),
"{$prefix}GIFT_PRICE" => $item->get_gift_price(),
"{$prefix}GIFT_PERCENTAGE" => $item->get_gift_percentage(),
"{$prefix}GIFT_TYPE" => $item->get_gift_type(),
"{$prefix}SALE_PRICE" => $item->get_sale_price(),
"{$prefix}SALE_DIFF" => $item->get_sale_price() ? $item->get_price() - $item->get_sale_price() : 0,
"{$prefix}SALE_PCT" => $item->get_sale_price() && $item->get_price() ? round(($item->get_price() - $item->get_sale_price()) / $item->get_price() * 100) : 0,
"{$prefix}SALE_START_UNIX" => $item->get_sale_start(),
"{$prefix}SALE_UNTIL_UNIX" => $item->get_sale_until(),
"{$prefix}FEATURED_START_UNIX" => $item->get_featured_start(),
"{$prefix}FEATURED_UNTIL_UNIX" => $item->get_featured_until(),
"{$prefix}AVAILABLE_START_UNIX" => $item->get_available_start(),
"{$prefix}AVAILABLE_UNTIL_UNIX" => $item->get_available_until(),
"{$prefix}EXPIRE_STRING" => $item->get_expire_string(),
"{$prefix}EXPIRE_SECONDS" => $item->get_expire_seconds(),
"{$prefix}EXPIRE_WITHIN" => $item->get_expire_seconds() ? $this->time->seconds_to_string($item->get_expire_seconds()) : '',
"{$prefix}EXPIRE_UNIX" => $item->get_expire_seconds() ? time() + $item->get_expire_seconds() : 0,
"{$prefix}DELETE_STRING" => $item->get_delete_string(),
"{$prefix}DELETE_SECONDS" => $item->get_delete_seconds(),
"{$prefix}DELETE_WITHIN" => $item->get_delete_seconds() ? $this->time->seconds_to_string($item->get_delete_seconds()) : '',
"{$prefix}DELETE_UNIX" => $item->get_delete_seconds() ? time() + $item->get_delete_seconds() : 0,
"{$prefix}REFUND_STRING" => $item->get_refund_string(),
"{$prefix}REFUND_SECONDS" => $item->get_refund_seconds(),
"{$prefix}REFUND_WITHIN" => $item->get_refund_seconds() ? $this->time->seconds_to_string($item->get_refund_seconds()) : '',
"{$prefix}REFUND_UNIX" => $item->get_refund_seconds() ? time() + $item->get_refund_seconds() : 0,
"{$bool}{$prefix}ACTIVE" => $item->get_active(),
"{$bool}{$prefix}AVAILABLE" => $this->is_available($item),
"{$bool}{$prefix}CONFLICT" => $item->get_conflict(),
"{$bool}{$prefix}FEATURED" => $this->is_featured($item),
"{$bool}{$prefix}GIFT" => $item->get_gift(),
"{$bool}{$prefix}GIFT_ONLY" => $item->get_gift_only(),
"{$bool}{$prefix}RELATED_ENABLED" => $item->get_related_enabled(),
"{$bool}{$prefix}SALE" => $this->on_sale($item),
"{$bool}{$prefix}STOCK_UNLIMITED" => $item->get_stock_unlimited(),
"{$bool}{$prefix}OUT_OF_STOCK" => !$item->get_stock_unlimited() && !$item->get_stock(),
"U_{$prefix}ACTIVATE" => $item->get_category_slug() ? $this->router->inventory($item->get_category_slug(), $item->get_slug(), $index, 'activate') : '',
"U_{$prefix}DELETE" => $item->get_category_slug() ? $this->router->inventory($item->get_category_slug(), $item->get_slug(), $index, 'delete') : '',
"U_{$prefix}GIFT" => $item->get_category_slug() ? $this->router->gift($item->get_category_slug(), $item->get_slug()) : '',
"U_{$prefix}INVENTORY" => $item->get_category_slug() ? $this->router->inventory($item->get_category_slug(), $item->get_slug(), $index) : '',
"U_{$prefix}PURCHASE" => $item->get_category_slug() ? $this->router->purchase($item->get_category_slug(), $item->get_slug()) : '',
"U_{$prefix}REFUND" => $item->get_category_slug() ? $this->router->inventory($item->get_category_slug(), $item->get_slug(), $index, 'refund') : '',
"U_{$prefix}VIEW" => $item->get_category_slug() ? $this->router->item($item->get_category_slug(), $item->get_slug()) : '',
];
}
/**
* Check whether or not an item is available.
*
* @param entity $item The item entity
* @return bool Whether or not the item is available
* @access public
*/
public function is_available(entity $item)
{
return $item->get_available_start() ? $this->time->within($item->get_available_start(), $item->get_available_until()) : true;
}
/**
* Check whether or not an item is featured.
*
* @param entity $item The item entity
* @return bool Whether or not the item is featured
* @access public
*/
public function is_featured(entity $item)
{
return $item->get_featured_start() ? $this->time->within($item->get_featured_start(), $item->get_featured_until()) : false;
}
/**
* Check whether or not an item is on sale.
*
* @param entity $item The item entity
* @return bool Whether or not the item is on sale
* @access public
*/
public function on_sale(entity $item)
{
return $item->get_sale_start() ? $this->time->within($item->get_sale_start(),$item->get_sale_until()) : false;
}
/**
* Get an item background image path.
*
* @param string $background The item background image
* @param bool $root Whether or not to include the phpBB root path
* @return string The item background image path
* @access public
*/
public function get_background_path($background, $root = true)
{
return $this->path_helper->update_web_root_path($this->files->set_mode('images')->get_path($background, $root));
}
/**
* Get an item background image absolute path.
*
* @param string $background The item background image
* @return string The item background image absolute path
* @access public
*/
public function get_absolute_background_path($background)
{
$background = $this->path_helper->remove_web_root_path($background);
if (strpos($background, '.') === 0)
{
$background = substr($background, 1);
}
return generate_board_url() . $background;
}
/**
* Get the item active SQL WHERE statement
*
* @param string $alias The table alias
* @return string The SQL WHERE statement
* @access protected
*/
protected function get_sql_where_active($alias = '')
{
$sql_where = '';
if (!$this->auth->acl_get('u_ass_can_view_inactive_items'))
{
$sql_where .= " AND {$alias}item_active = 1";
if ($alias)
{
$sql_where .= ' AND c.category_active = 1';
}
}
return $sql_where;
}
/**
* Get the item availability SQL WHERE statement
*
* @param string $alias The table alias
* @return string The SQL WHERE statement
* @access protected
*/
protected function get_sql_where_available($alias = '')
{
$time = time();
return " AND (({$alias}item_available_start = 0 AND {$alias}item_available_until = 0)
OR ({$time} BETWEEN {$alias}item_available_start AND {$alias}item_available_until))";
}
}