Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create product bundles that can contain both physical and digital products #14

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions _build/build.schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,6 @@ class [+class+]_[+platform+] extends [+class+]

$generator->parseSchema($sources['schema'] . 'commerce_digitalproduct.mysql.schema.xml', $sources['model']);

$manager->createObjectContainer('Digitalproduct');
$manager->createObjectContainer('DigitalproductFile');

$mtime= microtime();
$mtime= explode(" ", $mtime);
$mtime= $mtime[1] + $mtime[0];
Expand Down
10 changes: 10 additions & 0 deletions core/components/commerce_digitalproduct/lexicon/en/default.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
$_lang['commerce.DigitalproductProduct'] = 'Digital Product';
$_lang['commerce.add_DigitalproductProduct'] = 'Add Digital Product';

// Bundle
$_lang['commerce.DigitalProductBundle'] = 'Digital Product Bundle';
$_lang['commerce.add_DigitalProductBundle'] = 'Add Digital Product Bundle';

// Tabs
$_lang['commerce_digitalproduct.product_tab'] = 'Digital';

Expand All @@ -34,6 +38,12 @@
$_lang['commerce_digitalproduct.resource_display_name'] = 'Display Name (shows to customer)';
$_lang['commerce_digitalproduct.url'] = 'URL to File';

$_lang['commerce_digitalproduct.primary_delivery_type'] = 'Primary Delivery Type';
$_lang['commerce_digitalproduct.secondary_delivery_type'] = 'Secondary Delivery Type (Optional)';
$_lang['commerce_digitalproduct.primary_delivery_type.field_desc'] = '<b>Required:</b> If there are both physical and digital products in the bundle, set the physical delivery type here. If not, set the digital delivery type.';
$_lang['commerce_digitalproduct.secondary_delivery_type.field_desc'] = '<b>Optional:</b> If the primary delivery type is physical, set the digital delivery type here.';
$_lang['commerce_digitalproduct.no_secondary_delivery_type'] = 'No secondary delivery type';

// Frontend
$_lang['commerce_digitalproduct.pages'] = 'Pages';
$_lang['commerce_digitalproduct.files'] = 'Files';
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

use modmore\Commerce\Admin\Widgets\Form\DeliveryTypeField;
use modmore\Commerce_DigitalProduct\Admin\Widgets\Form\SecondaryDeliveryTypeField;

/**
* Digitalproduct for Commerce.
*
* Copyright 2019 by Tony Klapatch <[email protected]>
*
* This file is meant to be used with Commerce by modmore. A valid Commerce license is required.
*
* @package commerce_digitalproduct
* @license See core/components/commerce_digitalproduct/docs/license.txt
*/
class DigitalProductBundle extends comProductBundle
{
public function getModelFields()
{
$fields = parent::getModelFields();

foreach ($fields as $k => $field) {
if ($field instanceof DeliveryTypeField && $field->getName() === 'delivery_type') {
// Alter delivery type label and description
$field->setLabel($this->adapter->lexicon('commerce_digitalproduct.primary_delivery_type'));
$field->setDescription($this->adapter->lexicon('commerce_digitalproduct.primary_delivery_type.field_desc'));

// Add secondary delivery type (digital only)
array_splice( $fields, $k + 1, 0, [
new SecondaryDeliveryTypeField($this->commerce, [
'name' => 'properties[digital_bundle_delivery_type]',
'label' => $this->adapter->lexicon('commerce_digitalproduct.secondary_delivery_type'),
'description' => $this->adapter->lexicon('commerce_digitalproduct.secondary_delivery_type.field_desc'),
'value' => $this->getProperty('digital_bundle_delivery_type'),
])
]);
}
}

return $fields;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?php

use modmore\Commerce\Adapter\AdapterInterface;
use modmore\Commerce\Admin\Widgets\Form\NumberField;
use modmore\Commerce\Admin\Widgets\Form\SelectField;
use modmore\Commerce_DigitalProduct\Admin\Widgets\Form\ResourceField;
Expand All @@ -21,6 +22,11 @@ public static function getFieldsForProduct(Commerce $commerce, comProduct $produ
{
$fields = [];

// Don't show digital product fields on the bundle object itself
if ($product instanceof comProductBundle) {
return [];
}

$fields[] = new SelectField($commerce, [
'label' => $commerce->adapter->lexicon('commerce_digitalproduct.user_group'),
'name' => 'properties[usergroup]',
Expand Down Expand Up @@ -136,13 +142,13 @@ private function filterDigitalProducts(comOrder $order): array
$bundleProducts = $product->getProducts();
// Treat each product that's part of the bundle as a separate digital product
foreach ($bundleProducts as $bundleProduct) {
$output[] = $this->processDigitalProduct($bundleProduct, $order, $user);
$output[] = $this->processDigitalProduct($this->adapter, $bundleProduct, $order, $user);
}
continue;
}

// Process non-bundle products
$output[] = $this->processDigitalProduct($product, $order, $user);
$output[] = $this->processDigitalProduct($this->adapter, $product, $order, $user);
}

return $output;
Expand All @@ -155,7 +161,7 @@ private function filterDigitalProducts(comOrder $order): array
* @param modUser|null $user
* @return array
*/
private function processDigitalProduct($product, comOrder $order, modUser $user = null): array
public static function processDigitalProduct(AdapterInterface $adapter, $product, comOrder $order, modUser $user = null): array
{
// Joins the user to the product's usergroup if they are logged in
if ($user && $product->getProperty('usergroup')) {
Expand All @@ -176,12 +182,12 @@ private function processDigitalProduct($product, comOrder $order, modUser $user

// Add the product to the digitalproduct table for tracking
/** @var Digitalproduct $digitalProduct */
$digitalProduct = $this->adapter->newObject('Digitalproduct', $values);
$digitalProduct = $adapter->newObject('Digitalproduct', $values);
$digitalProduct->save();

// Get the digital items
$resources = $this->getDigitalProductResources($product, $digitalProduct);
$files = $this->getDigitalProductFiles($product, $digitalProduct);
$resources = self::getDigitalProductResources($adapter, $product, $digitalProduct);
$files = self::getDigitalProductFiles($adapter, $product, $digitalProduct);
$all = array_merge($resources, $files);

// In twig, you can see which by checking for an empty array.
Expand All @@ -200,28 +206,28 @@ private function processDigitalProduct($product, comOrder $order, modUser $user
* @param Digitalproduct $digitalProduct
* @return array
*/
private function getDigitalProductResources($product, $digitalProduct)
private static function getDigitalProductResources(AdapterInterface $adapter, $product, $digitalProduct)
{
$output = [];
$resources = $product->getProperty('resources');

foreach ((array)$resources as $resource) {
if ($resource) {
$page = $this->adapter->getObject('modResource', (int)$resource);
$page = $adapter->getObject('modResource', (int)$resource);

if (!$page) {
$this->adapter->log(1, '[Digitalproduct] Could not find resource with ID of ' . $resource);
$adapter->log(1, '[Digitalproduct] Could not find resource with ID of ' . $resource);
continue;
}

$digitalProductFile = $this->adapter->newObject('DigitalproductFile', [
$digitalProductFile = $adapter->newObject('DigitalproductFile', [
'digitalproduct_id' => $digitalProduct->get('id'),
'name' => $page->get('pagetitle'), //@todo, make custom setting. Maybe let it be set by TV?
'file' => $page->get('id'),
'download_method' => $product->getProperty('download_method'),
'download_expiry' => $this->getDownloadExpiry($product),
'download_limit' => $this->getDownloadLimit($product),
'secret' => $this->generateSecret()
'download_expiry' => self::getDownloadExpiry($adapter, $product),
'download_limit' => self::getDownloadLimit($adapter, $product),
'secret' => self::generateSecret($adapter)
]);
$digitalProductFile->save();

Expand All @@ -239,7 +245,7 @@ private function getDigitalProductResources($product, $digitalProduct)
* @param Digitalproduct $digitalProduct
* @return array
*/
private function getDigitalProductFiles($product, $digitalProduct)
private static function getDigitalProductFiles(AdapterInterface $adapter, $product, $digitalProduct)
{
$output = [];
$files = $product->getProperty('files');
Expand All @@ -251,14 +257,14 @@ private function getDigitalProductFiles($product, $digitalProduct)
'url' => $file['url']
];

$digitalProductFile = $this->adapter->newObject('DigitalproductFile', [
$digitalProductFile = $adapter->newObject('DigitalproductFile', [
'digitalproduct_id' => $digitalProduct->get('id'),
'name' => $file['display_name'],
'file' => $file['url'],
'download_method' => $product->getProperty('download_method'),
'download_expiry' => $this->getDownloadExpiry($product),
'download_limit' => $this->getDownloadLimit($product),
'secret' => $this->generateSecret()
'download_expiry' => self::getDownloadExpiry($adapter, $product),
'download_limit' => self::getDownloadLimit($adapter, $product),
'secret' => self::generateSecret($adapter)
]);
$digitalProductFile->save();

Expand All @@ -275,7 +281,7 @@ private function getDigitalProductFiles($product, $digitalProduct)
* @param comProduct $product
* @return int
*/
public function getDownloadExpiry($product)
public static function getDownloadExpiry(AdapterInterface $adapter, $product)
{
$expiration = $product->getProperty('download_expiry');
return $expiration ? strtotime($expiration) : 0;
Expand All @@ -287,7 +293,7 @@ public function getDownloadExpiry($product)
* @param comProduct $product
* @return int
*/
public function getDownloadLimit($product)
public static function getDownloadLimit(AdapterInterface $adapter, $product)
{
$limit = $product->getProperty('download_limit');
return $limit ? : 0;
Expand All @@ -298,19 +304,19 @@ public function getDownloadLimit($product)
*
* @return string
*/
public function generateSecret($secret = null, $bytes = 40, $check = true)
public static function generateSecret(AdapterInterface $adapter, $secret = null, $bytes = 40, $check = true)
{
// Allow future customization of secret for custom downloads.
if (!$secret) {
$secret = bin2hex(random_bytes($bytes));
}
// Check to ensure random generated string has not been used before
if ($check) {
$query = $this->adapter->getObject('DigitalproductFile', ['secret' => $secret]);
$query = $adapter->getObject('DigitalproductFile', ['secret' => $secret]);

if ($query) {
// Generate a new one if it is being used.
$secret = $this->generateSecret($bytes, $check);
$secret = self::generateSecret($bytes, $check);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
<?php

use modmore\Commerce\Admin\Widgets\Form\TextField;
use modmore\Commerce\Admin\Widgets\Form\Tab;

/**
* Digitalproduct for Commerce.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
<?php

$xpdo_meta_map = array (
'comProductBundle' =>
array (
0 => 'DigitalProductBundle',
),
'comProduct' =>
array (
0 => 'DigitalproductProduct',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
'null' => false,
'default' => 0,
),
'bundle' =>
'bundle' =>
array (
'dbtype' => 'int',
'attributes' => 'unsigned',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php
require_once strtr(realpath(dirname(dirname(__FILE__))), '\\', '/') . '/digitalproductbundle.class.php';
/**
* Digitalproduct for Commerce.
*
* Copyright 2019 by Tony Klapatch <[email protected]>
*
* This file is meant to be used with Commerce by modmore. A valid Commerce license is required.
*
* @package commerce_digitalproduct
* @license See core/components/commerce_digitalproduct/docs/license.txt
*/
class DigitalProductBundle_mysql extends DigitalProductBundle
{

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php
/**
* Digitalproduct for Commerce.
*
* Copyright 2019 by Tony Klapatch <[email protected]>
*
* This file is meant to be used with Commerce by modmore. A valid Commerce license is required.
*
* @package commerce_digitalproduct
* @license See core/components/commerce_digitalproduct/docs/license.txt
*/

$xpdo_meta_map['DigitalProductBundle']= array (
'package' => 'commerce_digitalproduct',
'version' => '1.1',
'extends' => 'comProductBundle',
'tableMeta' =>
array (
'engine' => 'InnoDB',
),
'fields' =>
array (
),
'fieldMeta' =>
array (
),
);
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<model package="commerce_digitalproduct" baseClass="comSimpleObject" platform="mysql" defaultEngine="InnoDB" version="1.1">
<object class="DigitalProductBundle" extends="comProductBundle" />
<object class="DigitalproductProduct" extends="comProduct" />
<object class="DigitalproductOrderShipment" extends="comOrderShipment" />

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace modmore\Commerce_DigitalProduct\Admin\Widgets\Form;

use modmore\Commerce\Admin\Widgets\Form\DeliveryTypeField;

class SecondaryDeliveryTypeField extends DeliveryTypeField
{
public function getDeliveryTypes()
{
$c = $this->adapter->newQuery('comDeliveryType');
$c->where([
'removed' => false,
'shipment_type' => 'DigitalproductOrderShipment',
]);
$c->sortby('name');

$this->options[] = [
'value' => 0,
'label' => $this->adapter->lexicon('commerce_digitalproduct.no_secondary_delivery_type')
];

foreach ($this->adapter->getIterator('comDeliveryType', $c) as $delType) {
$this->options[] = [
'value' => $delType->get('id'),
'label' => $delType->get('name')
];
}
}
}
Loading