I get the impression the codeception documentation is outdated.
I have Cept files working with a usersteps definition file that I use for things like login calls.
Due to complexity, I'd love to use Cest classes instead, but I can't get them to recognize my Usersteps. Here's an example:
<?php
/*
* #guy TestGuy\UserSteps
*/
class ViewPagesCest {
public function testViewCharacter(TestGuy $I) {
$I->loginToCharacter('admin', 'admin', 'Alice Kepler');
$target = $I->grabFromRepository('BM2SiteBundle:Character', 'id', array('name' => 'Carol Stanis'));
$I->amOnPage('/en/character/view/'.$target->getId());
$I->see($target->getName());
}
}
I get, of course:
[RuntimeException] Call to undefined method
TestGuy::loginToCharacter
because loginToCharacter is defined in a usersteps file. The same stuff as a Cept file works just fine. What am I missing?
You should use docblock (T_DOC_BLOCK) to place #guy annotation, but you use comment (T_COMMENT).
Just add second star at beginning of your comment:
/**
* #guy TestGuy\UserSteps
*/
class ViewPagesCest {
Related
I'm using Lumen default Tests only added this line to the test :
$users = \App\Models\User::factory()->count(5)->create();
But i get this error when running the test :
InvalidArgumentException: Unknown format "name"
I did't touch the UserFactory Class i include it below , whats wrong with my code?
public function definition()
{
return [
'name' => $this->faker->name,
'email' => $this->faker->unique()->safeEmail,
];
}
Should anybody else end up here looking for a similar issue in Laravel, make sure you include
parent::setUp();
in your setup method (if you have one). For example,
class ManageDocumentTest extends TestCase
{
public $user;
public function setUp():void
{
parent::setUp();
$this->user = User::factory()->create();
...
Uncommented these lines in app.php and its working now :
$app->withFacades();
$app->withEloquent();
You have to extend use Tests\TestCase instead of PHPUnit\Framework\TestCase.
At least, it helped me.
If you are using Tests\TestCase, calling parent::setUp(); and it still doesn't work, make sure not to call $faker before the actual test - ie. in a #dataProvider it won't work
I retrieve dates from a database and have the option to pre-process them (via the Laravel framework (v5.2)). The dates or times can come in any particular format but for this example let's say Y-m-d.
I want to be able to access the date as a Carbon instance in the view — this would give me the flexibility to format the date however I please or do nothing with it and print as-is (with the default toString being the same as its original string format).
The issue is maintaining the default expected toString format at the top-level Carbon toString format.
According to the docs, you can use the ::setToStringFormat() method to change the default format of toString. It is possible to set it with the static method Carbon::setToStringFormat() but it also works as an instance method e.g. ($date = Carbon::now())->setToStringFormat('Y-m-d') - albeit this seems to behave identically to the static method.
So, is it possible to set the individual __toString() format for a date instance?
It would allow me to do the following:
public function getDateAttribute($value)
{
$date = Carbon::createFromFormat('Y-m-d', $value);
// $date->setToStringFormat('Y-m-d');
return $date; // prints in 'Y-m-d' format
}
In a view, I would then chain methods on the date, or print it as-is.
I had the same sort of issue and worked my way around it
First create a global serialization method for carbon dates (e.g. in the boot of the Laravel AppServiceProvider)
<?php
namespace App\Providers;
use Illuminate\Support\Carbon;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider {
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot() {
// ...
Carbon::serializeUsing(function (Carbon $carbon):string {
$format = $carbon->getSettings()['toStringFormat'] ?? 'Y-m-d\TH:i:s';
return $carbon->format($format);
});
// ...
}
// ...
}
Then set the 'toStringFormat' setting to the format you need
$someCarbonDate->settings([ 'toStringFormat' => 'Y-m-d' ]);
Carbon::serializeUsing will now check if the carbon being serialized has a toStringFormat and use that or it will fall back to some other format you define.
You could probably also create your own Carbon class and extend Carbon\Carbon or Illuminate\Support\Carbon (used by Laravel) and override the __toString method, but that creates some new challenges when used in combination with the casting Laravel does internally.
If you just want to set the default format for when rendering Blade templates you can use the Blade::stringable method.
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
// ...
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot() {
// ...
Blade::stringable(function(\Illuminate\Support\Carbon $dateTime) {
return $dateTime->format('d/m/Y H:i:s');
});
// ...
}
// ...
}
Any Illuminate\Support\Carbon instances should automatically be rendered with this format unless you choose otherwise.
For example...
{{ $user->created_at }} would now render as 23/07/2021 10:16:24 by default
{{ $user->created_at->toDateString() }} still works and would render as 23/07/2021
NOTE: You might need to run php artisan view:clear to clear any compiled views before this takes effect 🙂
I read a lot of things of things in the cookbook or on stackoverflow but I can't find something adapted and clearly explained about how to solve my problem.
I have an SQL request that allows me to find schools that teaches a specific subject. I need to set this SQL request so that when I load the page containing my form, the request is done and I see the result (a list of school) in a multi select form. My best guess is that I need to set it inside my controller, but then again, I'm not even sure of that since it's the first time that I need to do that
I don't know if I should show you any code, so ask if you need to see something!
Thank you in advance
edit Here is my formType
<?php
namespace MissionBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use SocieteBundle\Entity\Societe;
class PublicType extends AbstractType{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('public')
->add('ecolesDispo')
// My goal is to replace 'ecolesDispo' (that is currently a one-to-many)
// by my SQL request.
;
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'MissionBundle\Entity\Mission'
));
}
}
Surely not in the controller. You need to use the "query_builder" attribute when you add the field to the form. Take a look at this example, from the Symfony cookbook : http://symfony.com/doc/current/reference/forms/types/entity.html#using-a-custom-query-for-the-entities
And you should translate your raw SQL query into DQL, so it's database-agnostic.
UPDATE about using a query builder with native SQL : http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/native-sql.html#the-nativequery-class
So something like this following piece of code should work (you'll have to edit some property names and fill the query though)
$builder->add('ecolesDispo', EntityType::class, array(
'class' => 'AppBundle:Ecole',
'query_builder' => function (EntityRepository $er) {
return $er->createNativeQuery('SELECT * FROM ecoles WHERE [...]');
},
'choice_label' => 'title',
));
in the Docs
http://symfony.com/doc/master/cookbook/profiler/storage.html
you still can find Information about Profiler Storage.
I just checked the code and could not find any clues how to set a custom storage.
I also find no Documentation stating this except some #legacy notes in the Original Source at 2.8.
Is there a Reason why this was removed?
I was using redis to store this data with a lifetime of eta 1hour.
Now I need to run a manual cleanup to whipe all files in that directory.
If anybody has some clues or hints on helping me with this issue are appreceated ^^
Chris
Thanks to the Tip of Matteo I was able to solve this quite flexible.
The Team of Symfony removed this, because it was hard coded into the Profiler Subsystem.
Instead of fixing this by adding a class parameter I had to solve it. :)
Ok, here is the code, If somebody needs this to.
First of all we need the Original Classes from Symfony 2.7 (at least I reused them as I only need the Redis Option ( I use it, because I can Compress the data using igbinary)
Next you need to implement a Compiler Pass.
namespace AcmeBunlde\DependencyInjection\CompilerPass;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class ProfilerCompilerPass implements CompilerPassInterface
{
/**
* You can modify the container here before it is dumped to PHP code.
*
* #param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
$definition = $container->getDefinition('profiler');
$definition->addArgument('%acmebundle.profiler.defaultEnabled%');
$definition->addArgument('%acmebundle.profiler.class%');
$definition->addArgument('%acmebundle.profiler.dsn%');
$definition->addArgument('%acmebundle.profiler.username%');
$definition->addArgument('%acmebundle.profiler.password%');
$definition->addArgument('%acmebundle.profiler.ttl%');
$definition->setClass('acmebundle\Profiler\Profiler');
}
}
This needs to be loaded inside the Bundle Loader:
public function build(ContainerBuilder $container)
{
...
$container->addCompilerPass(new ProfilerCompilerPass());
}
After this we need to add the Configuration for the New Profiler Storage in the DependencyInjection Folder.
namespace AcmeBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
/**
* This is the class that validates and merges configuration from your app/config files
*
* To learn more see {#link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class}
* #author Chris
*/
class Configuration implements ConfigurationInterface
/**
* {#inheritdoc}
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('library');
$rootNode
->children()
->arrayNode('profiler')
->addDefaultsIfNotSet()
->children()
->booleanNode('defaultStorage')
->defaultTrue()
->end()
->scalarNode('class')
->defaultValue('')
->end()
->scalarNode('dsn')
->defaultValue('')
->end()
->scalarNode('username')
->defaultValue('')
->end()
->scalarNode('password')
->defaultValue('')
->end()
->scalarNode('ttl')
->defaultValue('3600')
->end()
->end()
->end();
return $treeBuilder();
}
}
Now set the Default Values in The Dependency Injection Bundle Loader
<?php
namespace AcmeBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
/**
* This is the class that loads and manages your bundle configuration
*
* To learn more see {#link http://symfony.com/doc/current/cookbook/bundles/extension.html}
* #author Chris
*/
class AcmeExtension extends Extension
{
/**
* {#inheritdoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
...
$container->setParameter('acmebundle.profiler.defaultEnabled',$config['profiler']['defaultStorage']);
$container->setParameter('acmebundle.profiler.class',$config['profiler']['class']);
$container->setParameter('acmebundle.profiler.dsn',$config['profiler']['dsn']);
$container->setParameter('acmebundle.profiler.username',$config['profiler']['username']);
$container->setParameter('acmebundle.profiler.password',$config['profiler']['password']);
$container->setParameter('acmebundle.profiler.ttl',$config['profiler']['ttl']);
...
}
...
}
As Last Step you need to build a basic container for adding the new Profiler Handler.
I have choosen to implement it not to complex:
<?php
namespace AcmeBundle\Profiler;
use Psr\Log\LoggerInterface;
use \Symfony\Component\HttpKernel\Profiler\Profiler as ProfilerSrc;
use Symfony\Component\HttpKernel\Profiler\ProfilerStorageInterface;
/**
* Profiler.
*/
class Profiler extends ProfilerSrc
{
public function __construct(ProfilerStorageInterface $storage, LoggerInterface $logger, $defaultEnabled=true,$class=null,$dsn=null,$username=null,$password=null,$ttl=3600)
{
if($defaultEnabled!==true)
{
$storage = new $class($dsn,$username,$password,$ttl);
}
parent::__construct($storage , $logger);
}
}
I have also added a Library to define the Constructor of the Storage Interface.
<?php
namespace AcmeBundle\Profiler;
use Symfony\Component\HttpKernel\Profiler\ProfilerStorageInterface as ProfilerStorageSource;
interface ProfilerStorageInterface extends ProfilerStorageSource
{
/**
* ProfilerStorageInterface constructor.
*
* #param $dsn
* #param $username
* #param $password
* #param $ttl
*/
public function __construct($dsn,$username,$password,$ttl);
}
All you need to do now is to define some Options in your config_dev.yml file.
acmebundle:
profiler:
defaultEnabled: false
class:CLASSNAME INCLUDING NAMESPACE
dsn: redis://localhost/1
username:
password
ttl: 3600
with defaultEnabled = true you can reenable to Original Handler.
the rest is, I believe self explaining.
username + password is from the original feature set.
(ttl == lifetime)
I hope this helps somebody else as well :)
Is marked as deprecated since 2.8 with the suppression in the 3.0. I can't find any motivation about in the PR. The doc is not yet updated as you mention.
The only suggestion is about a comment in this issue:
If you want to use your own implementation of a profiler storage,
then just override the profile.storage service.
Hope this help
Has anyone tried or found an example of a class derived from CModel that replicates CActiveRecord functionality with WebServices instead of database connection???
If done with RESTFULL WebServices it would be great. If data is transmitted JSON encoded, wonderful!!...
I'd appretiate your help. Thanks.
I spend a lot of time looking for that as well, I came across this Yii extension on Github:
https://github.com/Haensel/ActiveResource
It allows you to have exactly what you are looking for, the readme isn't updated with the changes reflected in changes.md, so I recommend you read through this document as well.
EActiveResource for Yii
...is an extension for the Yii PHP framework allowing the user to create models that use RESTful services as persistent storage.
The implementation is inspired by Yii's CActiveRecord class and the Ruby on Rails implementation of ActiveResource (http://api.rubyonrails.org/classes/ActiveResource/Base.html).
HINT:
CAUTION: THIS IS STILL AN ALPHA RELEASE!
This project started as a draft and is still under development, so as long is there is no 1.0 release you may experience changes that could break your code. Look at the CHANGES.md file for further information
As there are thousands of different REST services out there that use a thousand different approaches it can be tricky to debug errors. Because of that I added extensive
tracing to all major functions, so you should always be able to see every request, which method it used and how the service responded. Just enable the tracing functionality of Yii
and look for the category "ext.EActiveResource"
INSTALL:
Add the extension to Yii by placing it in your application's extension folder (for example '/protected/extensions')
Edit your applications main.php config file and add 'application.extensions.EActiveResource.*' to your import definitions
Add the configuration for your resources to the main config
'activeresource'=>array(
'class'=>'EActiveResourceConnection',
'site'=>'http://api.aRESTservice.com',
'contentType'=>'application/json',
'acceptType'=>'application/json',
)),
'queryCacheId'=>'SomeCacheComponent')
4.) Now create a class extending EActiveResource like this (don't forget the model() function!):
QUICK OVERVIEW:
class Person extends EActiveResource
{
/* The id that uniquely identifies a person. This attribute is not defined as a property
* because we don't want to send it back to the service like a name, surname or gender etc.
*/
public $id;
public static function model($className=__CLASS__)
{
return parent::model($className);
}
public function rest()
{
return CMap::mergeArray(
parent::rest(),
array(
'resource'=>'people',
)
);
}
/* Let's define some properties and their datatypes
public function properties()
{
return array(
'name'=>array('type'=>'string'),
'surname'=>array('type'=>'string'),
'gender'=>array('type'=>'string'),
'age'=>array('type'=>'integer'),
'married'=>array('type'=>'boolean'),
'salary'=>array('type'=>'double'),
);
}
/* Define rules as usual */
public function rules()
{
return array(
array('name,surname,gender,age,married,salary','safe'),
array('age','numerical','integerOnly'=>true),
array('married','boolean'),
array('salary','numerical')
);
}
/* Add some custom labels for forms etc. */
public function attributeLabels()
{
return array(
'name'=>'First name',
'surname'=>'Last name',
'salary'=>'Your monthly salary',
);
}
}
Usage:
/* sends GET to http://api.example.com/person/1 and populates a single Person model*/
$person=Person::model()->findById(1);
/* sends GET to http://api.example.com/person and populates Person models with the response */
$persons=Person::model()->findAll();
/* create a resource
$person=new Person;
$person->name='A name';
$person->age=21;
$person->save(); //New resource, send POST request. Returns false if the model doesn't validate
/* Updating a resource (sending a PUT request)
$person=Person::model()->findById(1);
$person->name='Another name';
$person->save(); //Not at new resource, update it. Returns false if the model doesn't validate
//or short version
Person::model()->updateById(1,array('name'=>'Another name'));
/* DELETE a resource
$person=Person::model()->findById(1);
$person->destroy(); //DELETE to http://api.example.com/person/1
//or short version
Person::model()->deleteById(1);
Hope this helps you