Arguments for Laravel command - how to define correctly? - php

In Laravel I have programmed a console command to do a database operation. The command should take two parameters: <single> and <plural>. The console command should look like: $ php artisan entities:make pagespeed_sample pagespeed_samples. This short program resides in a vendor package, installed by composer: https://packagist.org/packages/phitech/entities. When I tested it while it was still in the /routes/console.php of my laravel application, it worked correctly. But now after installing it as a package, it doesn't work. I do not know by the way whether I have perhaps changed anything inbetween to break it.
The program returns an error: "No arguments expected for "entities:make" command, got "pagespeed_sample".".
Why does it say it is not expecting any arguments? Also, when I try it without arguments, it returns the error: "Unable to resolve dependency [Parameter #0 [ $single ]] in class Illuminate\Foundation\Console\ClosureCommand".
Is there a way to explicitly define expected arguments for my command, besides having the arguments required in the callback?
The full code of this console command is found below. I am using Laravel Framework 9.35.1.
Artisan::command('entities:make', function ($single, $plural) {
$entity_definition = json_encode([
"entity_name" => $single,
"main_db_table" => $plural,
"meta_db_table" => $plural . "_meta",
"meta_instance_id" => $single . "_id",
"main_required_columns" => [$single . "_id"],
]);
DB::table('entities')->insert([
'name' => $single,
'definition' => $entity_definition
]);
})->purpose('Register a new entity definition.');

Closure command parameters need to be part of the command definition e.g.
Artisan::command('entities:make {single} {plural}', function ($single, $plural) {
$entity_definition = json_encode([
"entity_name" => $single,
"main_db_table" => $plural,
"meta_db_table" => $plural . "_meta",
"meta_instance_id" => $single . "_id",
"main_required_columns" => [$single . "_id"],
]);
DB::table('entities')->insert([
'name' => $single,
'definition' => $entity_definition
]);
})->purpose('Register a new entity definition.');

Related

Unable to locate factory with name on production?

I create a factory of a model inside an artisan command:
public function handle()
{
if (!$this->isDevelopment()) {
$this->errorMessageSwitchEnvToDev();
return;
}
$userId = $this->ask('Please specifiy user_id you want to add the payouts to.',2148);
$numberOfPayouts = $this->ask('How many payouts you want to generate?', 10);
factory(\App\Payout::class, $numberOfPayouts)->create([
'user_id' => $userId,
]);
}
The artisan works on my local desktop, but it does not work after deployment on my test server.
I get the following error message:
InvalidArgumentException : Unable to locate factory with name [100] [App\Payout].
at /www/htdocs/w0146a6f/dev/dev4.partner.healyworld.net/releases/20201014150056/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php:269
265| */
266| protected function getRawAttributes(array $attributes = [])
267| {
268| if (! isset($this->definitions[$this->class][$this->name])) {
> 269| throw new InvalidArgumentException("Unable to locate factory with name [{$this->name}] [{$this->class}].");
270| }
271|
272| $definition = call_user_func(
273| $this->definitions[$this->class][$this->name],
Exception trace:
1 Illuminate\Database\Eloquent\FactoryBuilder::getRawAttributes([])
/www/htdocs/w0146a6f/dev/dev4.partner.healyworld.net/releases/20201014150056/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php:292
2 Illuminate\Database\Eloquent\FactoryBuilder::Illuminate\Database\Eloquent\{closure}()
/www/htdocs/w0146a6f/dev/dev4.partner.healyworld.net/releases/20201014150056/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/GuardsAttributes.php:122
I do the deployment with envoyer.
My factory is defined in database/factories/PayoutFactory.php
<?php
$factory->define(\App\Payout::class, function (Faker\Generator $faker) {
return [
'user_id' => function () {
return factory(App\User::class)->create()->id;
},
'amount' => $faker->randomFloat(2),
'req_amount' => 0,
'tax_amount' => 0,
'withheld' => 0,
'vat_rate' => $faker->randomNumber(2),
'released_amount' => $faker->randomFloat(2),
'released_amount_local_currency' => $faker->randomFloat(2),
'status' => 'released',
'flag' => 0,
'created_at' => $faker->dateTimeBetween('-6 months', 'now'),
];
});
However, it won't work on production. I already cleared the cache, the routes and called composer dump-autoload, but it still failes with the same issue.
Any suggestions?
I also read all answers of Laravel 5.2: Unable to locate factory with name [default] but none of them worked.
Notice this:
Unable to locate factory with name [100]
It looks like factory() is willing to use states instead of quantity. In this case it's looking for a factory state called (string) "100" instead of (int) 100
Cast your amount variable to be an integer
$numberOfPayouts = (int) $this->ask('How many payouts you want to generate?', 10);
Alternatively, try using ->times($amount) method to be more explicit.

ZF2 Zend Logger - Filters by priority

I'm using the Zend Logger with following configuration in the module_config.php:
'log' => [
\Base\Log\ConsoleLoggerAwareInterface::class => [
'writers' => [
'standard-output' => [
'name' => 'stream',
'options' => [
'stream' => 'php://output',
],
],
],
],
]
But as it is I can't influence the log to filter or suppress messages.
The goal is to improve the logging to be smarter.
I think I need to add a filter to the writer but I can't find an example how to do that in the module_config.php.
Is there also a way to call a script (e.g. from within a cron) by using a verbosity level?
I hope you know what I'm trying to achive.
Edit:
I have this example in my code:
$this->consoleLogger->emerg('EMERG');
$this->consoleLogger->alert('ALERT');
$this->consoleLogger->crit('CRIT');
$this->consoleLogger->err('ERR');
$this->consoleLogger->warn('WARN');
$this->consoleLogger->notice('NOTICE');
$this->consoleLogger->info('INFO');
$this->consoleLogger->debug('DEBUG');
Should it then not output the filtered ones?
Q: How to filter a Log Writer to a specific error level?
Add a filters key to the particular writer's configuration. Here's direct instantiation to remove any configuration peculiarities: this outputs only "WARN" and "EMERG" messages:
$config = [
'writers' => [
'standard-output' => [
'name' => 'stream',
'options' => [
'stream' => 'php://output',
'filters' => \Zend\Log\Logger::WARN,
],
],
],
];
$logger = new \Zend\Log\Logger($config);
$logger->emerg('EMERG');
$logger->warn('WARN');
$logger->debug('DEBUG');
Adding the filters configuration to your modules_config.php should have a similar effect. If not, check your zend-log version (with eg composer show) and advise.
Q: How to change error level filter with the -v command line parameter?
AFAIK, there is no automatic way to bind the standard verbose flag (-v) with a particular logging level. So you'll have to write your own filter. One thing that's neat to know is that the filters key can take:
an int (as done above, which translates to the built-in log level);
a string (corresponding to a class name implementing \Zend\Log\Filter\FilterInterface);
an object (instance of \Zend\Log\Filter\FilterInterface);
or an array of these.
You can use this flexibility to solve your need of binding a command line parameter to a log value. Here is a custom class that shows emergency events by default, but for every v on the command line increases the shown priority:
class CliLoggingFilter implements \Zend\Log\Filter\FilterInterface
{
public function __construct()
{
$this->level = \Zend\Log\Logger::EMERG;
if (array_key_exists('v', $args = getopt('v'))) {
$this->level += count($args['v']);
}
}
public function filter(array $event)
{
return ($event['priority'] <= $this->level);
}
}
You'd then have a configuration like: 'filters' => CliLoggingFilter::class.
$ php public/index.php
2016-07-25T10:57:28-04:00 EMERG (0): EMERG
$ php public/index.php -vvvv
2016-07-25T10:57:32-04:00 EMERG (0): EMERG
2016-07-25T10:57:32-04:00 WARN (4): WARN
$ php public/index.php -vvvvvvv
2016-07-25T10:57:34-04:00 EMERG (0): EMERG
2016-07-25T10:57:34-04:00 WARN (4): WARN
2016-07-25T10:57:34-04:00 DEBUG (7): DEBUG
Q: How to change all routes to use -v?
AFAIK, there is no way to specify a global command line parameter. You need to either (a) update all your console routes to accept the argument or (b) pass the log level a different way.
Updating all your routes isn't terribly hard. You can define a variable that holds the value and then include that in the configuration, like so:
$globalConsoleRouteParams = '[--verbose|-v]';
return [ 'console' => 'router' => 'routes' => [
'foo' => [ 'options' => [ 'route' => "foo $globalConsoleRouteParams ..." ] ],
'bar' => [ 'options' => [ 'route' => "bar $globalConsoleRouteParams ..." ] ],
// ...
]];
Alternatively, you could use say environment variables to pass your desired log level, plus perhaps any additional configuration you might desire. Modifying our earlier example:
class CliLoggingFilter implements \Zend\Log\Filter\FilterInterface
{
public function __construct()
{
$this->level = \Zend\Log\Logger::EMERG;
if (false !== ($level = getenv('LOG_LEVEL'))) {
$this->level = $level;
}
}
// ...
}
Then it may be invoked like
$ LOG_LEVEL=7 php index.php foo

How to use namespace in php?

I'm developing a solution that i need use Amazon WebServices library. Their library use namespace in all the project and how i am a beginner in PHP development i need your help to understand better how it works.
Here is my class:
<?php
// include('AmazonSNS\vendor\aws\aws-sdk-php\src\Sdk.php');
// include('AmazonSNS\model\CustomCredentials.php');
use Aws\Sdk;
class AwsSns {
public $sns;
public $platformApplicationArn;
public function __construct(){
$sdk = new Sdk([
'version' => 'latest',
'debug' => false,
'retries' => 3,
'credentials' => [
'key' => CustomCredentials::SNS_KEY,
'secret' => CustomCredentials::SNS_SECRET
],
'Sns' => [
'region' => 'sa-east-1'
]
]);
$this->sns = $sdk->createSns();
$this->generatePlatformApplicationArn();
}
private function generatePlatformApplicationArn( ){
$result = $this->sns->createPlatformApplication( array(
// Name is required
'Name' => 'GCMPedro',
// Platform is required
'Platform' => 'GCM',
// Attributes is required
'Attributes' => array(
// Associative array of custom 'String' key names
'PlatformCredential' => "AIzaSyBYjNaE7ShuLc2y4mf53bVwszDt8XA-YTI" //__API_KEY__
),
));
$this->platformApplicationArn = $result->get('PlatformApplicationArn');
Util::generateFile('PlataformApplicationArn: '.$this->platformApplicationArn, 'a');
}
public function getEndpointArn( $token ){
$result = $this->sns->createPlatformEndpoint(array(
// PlatformApplicationArn is required
'PlatformApplicationArn' => $this->platformApplicationArn,
// Token is required
'Token' => $token,
//'CustomUserData' => 'string',
'Attributes' => array(
// Associative array of custom 'String' key names
'Enabled' => 'true'
),
));
Util::generateFile('EndpointArn: '.$result->get('EndpointArn'), 'a');
return( $result->get('EndpointArn') );
}
}
?>
1) About name space, to use it, Do have I include or not include the .php file?
Observation:
When i don't use the include, the php returns the following error message:
Fatal error: Class 'Aws\Sdk' not found in C:\Program Files
(x86)\VertrigoServ\www\AmazonSNS\extra\AwsSns.php on line 14
Sure of your attention i thank you so much.
When you haven't set up an autoloading like PSR-0 or PSR-4 (like in the common PHP frameworks is used) or something else, the neccessary file is not going to be loaded/included automatically when its being called. I guess you haven't such an autoloading set up, so you can include with the include keyword.
In the official documentation of PHP you can read all about namespaces.
Citate of the manual. 2 benefits:
In the PHP world, namespaces are designed to solve two problems that authors of libraries and applications encounter when creating re-usable code elements such as classes or functions:
Name collisions between code you create, and internal PHP classes/functions/constants or third-party classes/functions/constants.
Ability to alias (or shorten) Extra_Long_Names designed to alleviate the first problem, improving readability of source code.

twice() method doesn't work in Mockery PHP

I am new to PHP Mockery Framework. I have a mock function executePrepared($arg1, $arg2, arg3) which I am calling it twice but seems to be not working and gives below error in PHPUnit command line:
Configuration read from C:\xampp\htdocs\DatabaseTesting\phpunit.xml
..←[31;1mE←[0m
Time: 47 ms, Memory: 3.25Mb
There was 1 error:
1) Test\Database\Table\TableTest::testinsertMany
Mockery\Exception\NoMatchingExpectationException: No matching handler found for
Mockery_0_Database_PGC::executePrepared(array(0=>'ClayPipe',1=>2000,2=>2100,3=>1
,4=>'2000-01-01',5=>'{"1":"1","2":6,"3":8,"4":10}',), "insert_assets", "\Databas
e\Model\Asset"). Either the method was unexpected or its arguments matched no ex
pected argument list for this method
my test function is as below:
public function testinsertMany() {
$this->PGCMock->shouldReceive('executePrepared')->twice()->withArgs(array(
[array('Clay Pipe',2000,2100,1,'2000-01-01','{"1":"1","2":6,"3":8,"4":10}'), 'insert_assets', '\Database\Model\Asset'],
[array('Main Street',1000,1100,0,'2000-02-01','{"1":"1","2":6,"3":8,"4":10}'), 'insert_assets', '\Database\Model\Asset']))
->andReturn($expectedResult1);
$data1 = array('name'=>'Clay Pipe',
'hist_cost' => 2000,
'val_cost' => 2100,
'val_method' => 1,
'service_date' => '2000-01-01',
'tags' => '{"1":"1","2":6,"3":8,"4":10}'
);
$data2 = array('name'=>'Main Street',
'hist_cost' => 1000,
'val_cost' => 1100,
'val_method' => 0,
'service_date' => '2000-02-01',
'tags' => '{"1":"1","2":6,"3":8,"4":10}'
);
$actualResult = $this->tableMock->insertMany(array($data1,$data2));
}
I don't understand what's wrong here. Is my Syntax for calling mock function twice() with passed argument wrong? Could any body please guide me here?
twice() should be used when the same call (including arguments) is expected to be executed 2 times. Looks like you want to check 2 consecutive calls, each with distinct argument.
If that is the case, this would work:
$this->PGCMock
->shouldReceive('executePrepared')
->once()
->ordered()
->withArgs([
array('Clay Pipe',2000,2100,1,'2000-01-01','{"1":"1","2":6,"3":8,"4":10}'),
'insert_assets', '\Database\Model\Asset'
])
->andReturn($result1);
$this->PGCMock
->shouldReceive('executePrepared')
->once()
->ordered()
->withArgs([
array('Main Street',1000,1100,0,'2000-02-01','{"1":"1","2":6,"3":8,"4":10}'),
'insert_assets', '\Database\Model\Asset'
])
->andReturn($result2);

How can I make sure DynamoDB putItem was successful

I'm using amazon sdk v2 and using aws factory for dynamoDB and I have a simple putItem operation but I have no idea how I can make sure putItem was successful or not because putItem returns a Model which doesnt contain any information about status of operation. Any idea?
Here is my code
class DynamoLogger{
protected $client;
protected $tableName;
public function __construct(ServiceBuilder $builder, $tableName)
{
$this->client = $builder->get('dynamodb');
$this->tableName = $tableName;
}
public function log(Request $request)
{
$model = $this->client->putItem(array(
'TableName' => $this->tableName,
'Item' => array(
'cc_id' => array(
'S' => $request->get('cc_id')
),
'date' => array(
'S' => date('Y-m-d H:i:s') . substr((string)microtime(), 1, 8)
),
'tt_id' => array(
'N' => $request->get('tt_id')
),
'action_name' => array(
'S' => $request->get('name')
),
'action_value' => array(
'S' => $request->get('value')
),
'gg_nn' => array(
'S' => $request->get('gg_nn')
),
'ffr_id' => array(
'N' => $request->get('ffr_id')
)
),
'ReturnValues' => 'ALL_OLD'
));
return $model;
}
}
With the AWS SDK for PHP 2.x, you should assume that any operation that returns without throwing an exception was successful. In the case of DynamoDB, an Aws\DynamoDb\Exception\DynamoDbException (or subclass) will be thrown if there was an error. Also, in the case of DynamoDB, the service will not respond until your item has been written to at least 2 locations, ensuring the integrity of your data.
Additionally, with the AWS SDK for PHP 2.x, you can use the long-form command syntax in order to have access to the Guzzle Request and Response objects, if you are interested in introspecting them. Here is an example:
$command = $client->getCommand('PutItem', array(/*...params...*/));
$model = $command->getResult(); // Actually executes the request
$request = $command->getRequest();
$response = $command->getResponse();
var_dump($response->isSuccessful());
Please also see the Commands and Response Models sections of the AWS SDK for PHP User Guide.

Categories