In use Gas ORM for CodeIgniter.
Like what said in : http://gasorm-doc.taufanaditya.com/configuration.html
Gas ORM support auto-creation of tables. This mean you can convert your existing Gas models into a database. For security reasons, this option is disabled by default. To enable :
$config['auto_create_tables'] = TRUE;
And then i enable migration in migration.php and then create 2 class in models folder called user.php and blog.php. The code look like :
User class :
<?php
namespace Model;
use \Gas\Core;
use \Gas\ORM;
class User extends ORM {
public $primary_key = 'id';
function _init()
{
self::$relationships = array (
'blog' => ORM::has_many('\\Model\\Blog');
);
self::$fields = array(
'id' => ORM::field('auto[10]'),
'username' => ORM::field('char[64]'),
'password' => ORM::field('char[255]'),
'email' => ORM::field('char[255]'),
);
}
}
Blogclass:
<?php namespace Model;
use \Gas\Core;
use \Gas\ORM;
class Blog extends ORM {
public $primary_key = 'id';
function _init()
{
self::$relationships = array (
'user' => ORM::belongs_to('\\Model\\User')
);
self::$fields = array(
'id' => ORM::field('auto[10]'),
'title' => ORM::field('char[255]', array('required','max_length[255]')),
'body' => ORM::field('string'),
'modified_at' => ORM::field('datetime'),
'created_at' => ORM::field('datetime'),
);
$this->ts_fields = array('modified_at','[created_at]');
}
}
When i refresh the pages, the page showing error:
A PHP Error was encountered
Severity: Runtime Notice
Message: Only variables should be passed by reference
Filename: classes/core.php
Line Number: 2460
Backtrace:
File: /application/third_party/gas/classes/core.php
Line: 2460
Function: _error_handler
File: /application/third_party/gas/classes/core.php
Line: 320
Function: _generate_tables
File: /application/third_party/gas/classes/core.php
Line: 360
Function: __construct
File: /application/third_party/gas/bootstrap.php
Line: 229
Function: make
File: /application/libraries/Gas.php
Line: 111
Function: include_once
File: /application/controllers/Home_Controller.php
Line: 7
Function: __construct
File: /index.php
Line: 315
Function: require_once
I really stuck with this error. Can anyone help me to solve my problem?
I already trace my code, and the problem similar like this reference : Only variables should be passed by reference
The fact of this problem is maybe the code show error when running but actually the code completely its function. So i decide to turn the $config['auto_create_tables'] = TRUE; to $config['auto_create_tables'] = FALSE; after using this feature.
Related
In my CakePHP 4.0 project, and I'm trying to achieve what I think is a fairly trivial goal: I would like to have to have a "base" console command, with some basic setup, and other classes that extend it.
Specifically, I would like to define a [ConsoleOptionParser][1] in my base class, because all other Command classes should have access to the same options:
<?php
namespace Import\Shell;
use Cake\Command\Command;
use Cake\Console\ConsoleOptionParser;
class BaseImportCommand extends Command
{
public function __construct()
{
parent::__construct();
// setup some stuff related to my project here
}
protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser
{
// Get an empty parser from the framework.
$parser = parent::getOptionParser();
// Define your options and arguments.
$parser->addOptions(
[
'country' => [
'short' => 'c',
'help' => 'The country for which to execute the operation.',
'required' => false,
],
'author' => [
'short' => 'a',
'help' => 'The ID of the author for which to execute the operation.',
'required' => false,
],
'product' => [
'short' => 'p',
'help' => 'The ID of the product for which to execute the operation.',
'required' => false,
],
]
);
// Return the completed parser
return $parser;
}
}
<?php
namespace Import\Shell;
use Cake\Console\Arguments;
use Cake\Console\ConsoleIo;
class ProcessProductImagesCommand extends BaseImportCommand
{
public function __construct()
{
parent::__construct();
// setup some more stuff here
}
/**
* execute() method.
*
* #return bool|int|null Success or error code.
*/
public function execute(Arguments $args, ConsoleIo $io)
{
$country = $args->getOption('country');
$productId = $args->getOption('product');
// do my logic here
}
}
The problem is that when I run
bin/cake processProductImages -c CH
in the shell I get this error:
Error: Unknown short option `c`.
Why is that? I am not redefining the buildOptionParser method inside the ProcessProductImagesCommand class, so I would assume that the ConsoleOptionParser configuration is inherited from the BaseCommand class.
To fix the problem, I have tried adding this method to the ProcessProductImagesCommand class:
protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser
{
return parent::buildOptionParser($parser);
}
but what happens in this case when I run
bin/cake processProductImages -c CH
in the shell I then get this error:
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 4096 bytes) in /var/www/repo/public/vendor/cakephp/cakephp/src/Console/ConsoleOptionParser.php on line 430
I have found out the the only actual way to have the options that I need, in the classes that I need them, is to completely repeat the initialisation of the ConsoleOptionParser in the child class by copying the whole buildOptionParser method from the BaseImportCommand class, but obviously I don't like this solution as it leads to useless code repetition.
[1]: https://book.cakephp.org/4/en/console-commands/option-parsers.html
By convention commands are supposed to live in the Command namespace, not the Shell namespace.
You cannot call parent::buildOptionParser() without any arguments.
The first argument of addArgument() is meant to be a string, or an instance of \Cake\Console\ConsoleInputArgument, not an array. Multiple arguments can be added at once using the addArguments() method (note the trailing s).
Arguments (positional values) and options are two different things, -c is an option that needs to be configured using addOption().
If you're exhausting 130+ MB of memory in the options parsing stage, then you possibly created an infinite loop.
I have this file
namespace Drupal\api\ConfigArrays {
const jsonApiUris = array(
'insert_publication' => array(
'method' => 'POST',
'uri' => 'node/publication'
)
);
}
But when i try to import in some class:
use const Drupal\api\ConfigArrays\jsonApiUris;
class HttpHelper
{
static public function sendToJsonAPI($content, $endpoint, $token)
{
var_dump(jsonApiUris);
die;
}
}
my IDE (PhpStorm) recognizes the variable and the autocomplete, but when I execute it, I get this error
Error: Undefined constant 'Drupal\api\ConfigArrays\jsonApiUris' in
Drupal\api\Helpers\HttpHelper::sendToJsonAPI() (line 21 of
modules/custom/api/src/Helpers/HttpHelper.php).
Your syntax is fine for PHP5.6+ but if you are running a prior version you'll need to use Drupal\api\ConfigArrays then access it via ConfigArrays\jsonApiUris
Are you sure the code in the first snippet has been included/defined by the time it reaches the second snippet?
I created new resources with this code:
class WebserviceRequest extends WebserviceRequestCore {
public static function getResources(){
$resources = parent::getResources();
// if you do not have class for your table
$resources['test'] = array('description' => 'Manage My API', 'specific_management' => true);
$resources['categoryecommerce'] = array('description' => 'o jacie marcin', 'class' => 'CategoryEcommerce');
$mp_resource = Hook::exec('addMobikulResources', array('resources' => $resources), null, true, false);
if (is_array($mp_resource) && count($mp_resource)) {
foreach ($mp_resource as $new_resources) {
if (is_array($new_resources) && count($new_resources)) {
$resources = array_merge($resources, $new_resources);
}
}
}
ksort($resources);
return $resources;
}
}
And new class:
class CategoryEcommerceCore extends ObjectModelCore {
public $category_id;
public $category_core_id;
public static $definition = array(
'table' => "category_ecommerce",
'primary' => 'category_id',
'fields' => array(
'category_core_id' => array('type' => self::TYPE_INT),
)
);
protected $webserviceParameters = array();
}
Webservice is override properly. My class WebserviceRequest is copying to
/override/classes/webservice/WebserviceRequest
but class isn't copying to /override/classes/ when i installing my module.
How to add new resourcess with own logic ? I want to add categories within relation to my table.
Regards
Martin
As soon as there is literally nothing regarding the API except Webkul tutorial... I tried to implement the "Webkul's" tutorial, but also failed. However seems that it's better to use hooks instead of overrides. I used my "reverse engineering skills" to determine the way to create that API, so-o-o-o, BEHOLD! :D
Let's assume you have a custom PrestaShop 1.7 module. Your file is mymodule.php and here are several steps.
This is an install method wich allows you to register the hook within database (you can uninstall and reinstall the module for this method to be executed):
public function install() {
parent::install();
$this->registerHook('addWebserviceResources');
return true;
}
Add the hook listener:
public function hookAddWebserviceResources($resources) {
$added_resources['test'] = [
'description' => 'Test',
'specific_management' => true,
];
return $added_resources;
}
That specific_management option shows you are going to use WebsiteSpecificManagement file instead of database model file.
Create WebsiteSpecificManagement file, called WebsiteSpecificManagementTest (Test - is CamelCased name of your endpoint). You can take the skeleton for this file from /classes/webservice/WebserviceSpecificManagementSearch.php. Remove everything except:
setObjectOutput
setWsObject
getWsObject
getObjectOutput
setUrlSegment
getUrlSegment
getContent (should return $this->output; and nothing more)
manage - you should rewrite it to return/process the data you want.
Add
include_once(_PS_MODULE_DIR_.'YOURMODULENAME/classes/WebserviceSpecificManagementTest.php');
to your module file (haven't figured out how to include automatically).
Go to /Backoffice/index.php?controller=AdminWebservice and setup the new "Auth" key for your application, selecting the test endpoint from the permissions list. Remember the key.
Visit /api/test?ws_key=YOUR_KEY_GENERATED_ON_STEP_4 and see the XML response.
Add &output_format=JSON to your URL to see the response in JSON.
You have to use something like $this->output = json_encode(['blah' => 'world']) within manage method at WebsiteSpecificManagementTest.
I'm using Codeigniter 3 and Doctrine 2, which is loaded by a library class.
Doctrine itself is loaded via composer autoload.
On localhost (windows with php 5.6.0) I'm using the php built in server and everything is working.
When I'm uploading the project to my webserver (Plesk with nginx and proxied apache, php 5.6.15), i get the following error:
An uncaught Exception was encountered
Type: Doctrine\Common\Persistence\Mapping\MappingException
Message: Class 'Entity\User' does not exist
Filename: /var/www/vhosts/example.org/project.example.org/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/MappingException.php
Line Number: 96
Backtrace:
File: /var/www/vhosts/example.org/project.example.org/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/RuntimeReflectionService.php
Line: 41
Function: nonExistingClass
File: /var/www/vhosts/example.org/project.example.org/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php
Line: 282
Function: getParentClasses
File: /var/www/vhosts/example.org/project.example.org/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php
Line: 313
Function: getParentClasses
File: /var/www/vhosts/example.org/project.example.org/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
Line: 78
Function: loadMetadata
File: /var/www/vhosts/example.org/project.example.org/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php
Line: 216
Function: loadMetadata
File: /var/www/vhosts/example.org/project.example.org/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php
Line: 281
Function: getMetadataFor
File: /var/www/vhosts/example.org/project.example.org/vendor/doctrine/orm/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php
Line: 44
Function: getClassMetadata
File: /var/www/vhosts/example.org/project.example.org/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php
Line: 698
Function: getRepository
File: /var/www/vhosts/example.org/project.example.org/application/controllers/User.php
Line: 18
Function: getRepository
File: /var/www/vhosts/example.org/project.example.org/index.php
Line: 301
Function: require_once
The controller is as follows:
....
public function show($id)
{
$user = $this->doctrine->em->getRepository('Entity\User')->findOneBy(array('id' => $id));
}
....
and the doctrine library:
use Doctrine\Common\ClassLoader,
Doctrine\ORM\Tools\Setup,
Doctrine\ORM\EntityManager;
class Doctrine {
public $em;
public function __construct()
{
// Load the database configuration from CodeIgniter
require APPPATH . 'config/database.php';
$connection_options = array(
'driver' => 'pdo_mysql',
'user' => $db['default']['username'],
'password' => $db['default']['password'],
'host' => $db['default']['hostname'],
'dbname' => $db['default']['database'],
'charset' => $db['default']['char_set'],
'driverOptions' => array(
'charset' => $db['default']['char_set'],
),
);
// With this configuration, your model files need to be in application/models/Entity
// e.g. Creating a new Entity\User loads the class from application/models/Entity/User.php
$models_namespace = 'Entity';
$models_path = APPPATH . 'models';
$proxies_dir = APPPATH . 'models/proxies';
$metadata_paths = array(APPPATH . 'models/entity');
// Set $dev_mode to TRUE to disable caching while you develop
$dev_mode = true;
// If you want to use a different metadata driver, change createAnnotationMetadataConfiguration
// to createXMLMetadataConfiguration or createYAMLMetadataConfiguration.
$config = Setup::createAnnotationMetadataConfiguration($metadata_paths, $dev_mode, $proxies_dir);
$this->em = EntityManager::create($connection_options, $config);
$loader = new ClassLoader($models_namespace, $models_path);
$loader->register();
}
}
The library is loaded via the autoload.php:
$autoload['libraries'] = array('OAuth2', 'session', 'doctrine');
the entity is located in models\Entity\
<?php
namespace Entity;
use Doctrine\ORM\Mapping\Entity;
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* User Model
*
* #Entity
* #Table(name="user")
*/
class User {
/**
* #Id
* #Column(type="integer", nullable=false)
* #GeneratedValue(strategy="AUTO")
*/
protected $id;
....
The strange thing is that it works locally.
Any ideas?
Found the problem: Case-sensitivity of linux:
The folder of the entities should be capitalized according to the namespace. Since the directory was models\entity\ and Windows' file system is case-insensitiv, it worked on locally. But linux is case-sensitiv and expects models\Entity.
Renamed the folder to models\Entity and it's working.
(using Zend Framework 2.2.4)
My validator factory, doesn't seem to "exist" at validation time. If I attempt to instantiate the validator from the controller in which the form is housed, it conversely works fine:
This works...
$mycustomvalidator = $this->getServiceLocator()
->get('ValidatorManager')
->get('LDP_PinAvailable');
Here's how things are set up otherwise in the code, I can't seem to find the problem, and was hopeful to avoid opening up ZF2 source to understand. By way of documentation, it seems right.
Module Config
public function getValidatorConfig()
{
return array(
'abstract_factories' => array(
'\LDP\Form\Validator\ValidatorAbstractFactory',
),
);
}
Factory Class
namespace LDP\Form\Validator;
use Zend\ServiceManager\AbstractFactoryInterface,
Zend\ServiceManager\ServiceLocatorInterface;
class ValidatorAbstractFactory implements AbstractFactoryInterface
{
public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)
{
return stristr($requestedName, 'LDP_PinAvailable') !== false;
}
public function createServiceWithName(ServiceLocatorInterface $locator, $name, $requestedName)
{
// baked in for sake of conversation
$validator = new \LDP\Form\Validator\PinAvailable();
if( $validator instanceof DatabaseFormValidatorInterface )
$validator->setDatabase( $locator->get('mysql_slave') );
return $validator;
}
}
Custom Validator
namespace LDP\Form\Validator;
class PinAvailable extends \Zend\Validator\AbstractValidator implements DatabaseFormValidatorInterface
{
/**
* #var \Zend\Db\Sql\Sql
*/
private $database;
public function setDatabase( \Zend\Db\Sql\Sql $db )
{
$this->database = $db;
}
public function isValid( $value )
{
$DBA = $this->database->getAdapter();
// do the mixed database stuff here
return true;
}
}
Lastly, the form field validator config part of the array:
'pin' => array(
'required' => true,
'filters' => array(
array('name' => 'alnum'),
array('name' => 'stringtrim'),
),
'validators' => array(
array( 'name' => 'LDP_PinAvailable' )
),
),
),
Piecing it all together, the form loads, and when submitted, it does with the stack trace below:
2013-10-28T17:09:35-04:00 ERR (3): Exception:
1: Zend\Validator\ValidatorPluginManager::get was unable to fetch or create an instance for LDP_PinAvailable
Trace:
#0 /Users/Saeven/Documents/workspace/Application/vendor/zendframework/zendframework/library/Zend/ServiceManager/AbstractPluginManager.php(103): Zend\ServiceManager\ServiceManager->get('LDP_PinAvailabl...', true)
#1 /Users/Saeven/Documents/workspace/Application/vendor/zendframework/zendframework/library/Zend/Validator/ValidatorChain.php(82): Zend\ServiceManager\AbstractPluginManager->get('LDP_PinAvailabl...', Array)
The ValidatorPluginManager extends the Zend\ServiceManager\AbstractPluginManager. The AbstractPluginManager has a feature called "autoAddInvokableClass", which is enabled by default.
Basically, what this means, is that if the service name requested can't be resolved by the ValidatorPluginManager, it will then check if the name is a valid class name. If so, it will simply add it as an invokable class right there, on-demand, which of course means that it will never fall back to your abstract factory.
To circumvent this behavior, the easiest method is to simply make your abstract factory respond to service names that do not actually resolve to the actual class names.
See: AbstractPluginManager.php#L98-L100
Digging some more, I've found the problem. It distilled to these lines in Zend\Validator\ValidatorChain circa line 80:
public function plugin($name, array $options = null)
{
$plugins = $this->getPluginManager();
return $plugins->get($name, $options);
}
There was no plugin manager available in context.
It took about three seconds of Googling to find that I had to do this when I prepared the form in the controller:
$validators = $this->getServiceLocator()->get('ValidatorManager');
$chain = new ValidatorChain();
$chain->setPluginManager( $validators );
$form->getFormFactory()->getInputFilterFactory()->setDefaultValidatorChain( $chain );
Hopefully this helps someone else. You are able to use regular old classnames when setting it up this way, no need to warp the classnames.
In ZF3/Laminas, if a validator is registered as an invokable, you can call the validator in the getInputFilterSpecification() of your form, and no problem. If a validator is instantiated using a factory, you get into trouble. If I understand correctly, even if your form is registered like this
'form_elements' => [
'factories' => [
SomeForm::class => SomeFormFactory::class,
]
]
and your validator:
'validators' => [
'factories' => [
SomeValidator::class => SomeValidatorFactory::class,
]
]
you won't be instantiating the validator via factory. The reason is that the form factory (the one you get like $form->getFormFactory()) has an input filter factory and in there sits default validator chain. And this validator chain has no ValidatorManager attached. And without the ValidatorManager, the default chain cannot map the validator name to the validator factory.
To solve all this headache, in your controller factory do this:
$form->('FormElementManager')->get(SomeForm::class);
$form->getFormFactory()->getInputFilterFactory()
->getDefaultValidatorChain()->setPluginManager($container->get('ValidatorManager'));
and your troubles are over.